Android configuration value in CI - java

I am new to android but already thinking if there is a way to include some important configurations for the app in continuous integration . We use visual studio online for build and release .
Example .
Currently we have Constants.java file which stores some imp configuration values like server URL which wil be different for each environment app is deployed on for example dev,test uat production , so currently that code needs to be manually checked before it goes in to vso for build and release . . Is it possible to somehow configure it in continuous integration of environment and pick from there so that manual check is not required ..

See this:
Look this function readApiKey() it reads the keys in from Environment or from a .properties file. Then look at this line:
buildConfigField("String", "API_PUBLIC_KEY", readApiKey(KeyType.PUBLIC_KEY)) it loads the string resource with the value.
If you have different builds with different values, that's where flavours comes in. You can read it up here.
apply plugin: 'com.android.application'
apply from: '../codequality/quality.gradle'
/*
* Read API key from CI server or from keys.properties file
*/
enum KeyType {
PUBLIC_KEY,
PRIVATE_KEY
}
def readApiKey(KeyType type) {
String apiKey = ""
if (System.getenv("CIENV")) {
if (type == KeyType.PUBLIC_KEY) {
apiKey = System.getenv("PB_KEY")
} else apiKey = System.getenv("PR_KEY")
} else {
Properties props = new Properties()
try {
props.load(new FileInputStream(new File(getRootDir().getAbsolutePath() + "/keys.properties")))
if (type == KeyType.PUBLIC_KEY) {
apiKey = props.getProperty("api_pb_key")
} else apiKey = props.getProperty("api_pr_key")
} catch (FileNotFoundException fnfe) {
println("Please create a keys.properties file in the root directory of the project")
}
}
return "\"$apiKey\"";
}
println 'PUBLIC KEY Log' + readApiKey(KeyType.PUBLIC_KEY)
println 'Private Key Log' + readApiKey(KeyType.PRIVATE_KEY)
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
dataBinding {
enabled true
}
testOptions {
unitTests.returnDefaultValues = true
}
defaultConfig {
applicationId "co.tonespy.dummarvel"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// Setting up picked up data to String resource
buildConfigField("String", "API_PUBLIC_KEY", readApiKey(KeyType.PUBLIC_KEY))
buildConfigField("String", "API_PRIVATE_KEY", readApiKey(KeyType.PRIVATE_KEY))
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
// support dependencies
....
// test dependencies
testCompile "junit:junit:$jUnitVersion"
androidTestCompile("com.android.support.test.espresso:espresso-core:$espressoCoreVersion", {
exclude group: 'com.android.support', module: 'support-annotations'
})
testCompile "org.mockito:mockito-core:$mockitoVersion"
compile "com.android.support:support-v4:$supportLibraryVersion"
}

You can just use Replace Tokens step/task to replace the value per to each environment.
Install Replace Tokens extension
Add Replace Tokens task to each environment of your release definition (Target files **\ Constants.java)
Add environment variable (e.g server, same variable name for each environment) for each environment of you release definition
Modify Constants.java file, replace necessary value to #{server}# and check in changes (The developers can modify this file with specific value and do not check in changes if they need to debug/run app in local machine)
After that the #{server}# will be replaced with the value of server environment

Related

Getting Play Framework works with Gradle and IntelliJ Idea

I'm trying to build my web application with Play Framework using Gradle as a build tool. My IDE is IntelliJ Idea.
I use Play with Java so I don't want to use SBT in my project. But it seems Play's not supported fully by IntelliJ Idea because the project structure is quite different. IntelliJ can't recognize it.
After a while googling, I found a solution, adding this script in build.gradle:
idea {
module {
sourceDirs += file("app")
testSourceDirs += file("test")
scopes.COMPILE = [plus: [configurations.play], minus: []]
scopes.RUNTIME = [plus: [configurations.playRun], minus:[configurations.play]]
scopes.TEST = [plus: [configurations.playTest], minus: [configurations.playRun]]
}
}
But there is a problem, each time I open the project, I have to re-run idea task to make IntelliJ recognize the Play's structure.
Is there any way that's better than mine?
Thank you so much!
My Github example: https://github.com/TranNgocKhoa/play-gradle-intellij-example.
My build.gradle
plugins {
id 'play'
id 'idea'
}
def playVersion = "2.6.7"
def scalaVersion = System.getProperty("scala.binary.version", /* default = */ "2.11")
model {
components {
play {
platform play: playVersion, scala: scalaVersion, java: '1.8'
injectedRoutesGenerator = true
sources {
twirlTemplates {
defaultImports = TwirlImports.JAVA
}
}
}
}
}
def dependencyFor(String lib, String scalaVersion, String version) {
return lib + "_" + scalaVersion + ":" + version
}
dependencies {
play dependencyFor("com.typesafe.play:play-guice", scalaVersion, playVersion)
play dependencyFor("com.typesafe.play:play-logback", scalaVersion, playVersion)
play dependencyFor("com.typesafe.play:filters-helpers", scalaVersion, playVersion)
play dependencyFor("com.typesafe.play:play-java-jpa", scalaVersion, playVersion)
play "org.hibernate:hibernate-core:5.4.2.Final"
play "com.h2database:h2:1.4.197"
}
repositories {
jcenter()
maven {
name "lightbend-maven-releases"
url "https://repo.lightbend.com/lightbend/maven-release"
}
ivy {
name "lightbend-ivy-release"
url "https://repo.lightbend.com/lightbend/ivy-releases"
layout "ivy"
}
}
idea {
module {
sourceDirs += file("app")
testSourceDirs += file("test")
scopes.COMPILE = [plus: [configurations.play], minus: []]
scopes.RUNTIME = [plus: [configurations.playRun], minus: [configurations.play]]
scopes.TEST = [plus: [configurations.playTest], minus: [configurations.playRun]]
}
}
I'm using Java 8, Gradle 5.4, Play 2.6.7
The below setup works now with some finessing required to get the rest of your dependencies up and running.
plugins {
id 'play'
id 'idea'
}
# replace with
plugins {
id 'idea'
id 'org.gradle.playframework' version '0.9'
}
The next step is to execute gradle idea and you should be able to just import the folder and intellij. If that is not the case go to Build tools -> Gradle and select use gradle

onDataChanged acting weird

I'm trying to use my wearOS app to extend my Paint app. I tried sending a Bitmap to the wear app everytime a new point was added, but that caused horrible lag.
I tried serializing a Path array, but then quickly noticed I could just pass the three different paint features, (start, move, end) via points and functions.
This is my onMove attempt:
public void sendPoint(Point p)
{
long[] newPoint = new long[2];
newPoint[0] = p.x;
newPoint[1] = p.y;
PutDataMapRequest dataMap = PutDataMapRequest.create("/count");
dataMap.getDataMap().putLongArray("count", newPoint);
PutDataRequest request = dataMap.asPutDataRequest();
Task<DataItem> putTask = Wearable.getDataClient(this).putDataItem(request);
}
Before I get into onStart and onEnd - I'd like to point out with this exact code:
public void sendPaint(Bitmap b)
{
Bitmap bitmap = b;
Asset asset = createAssetFromBitmap(bitmap);
PutDataMapRequest dataMap = PutDataMapRequest.create("/image");
dataMap.getDataMap().putAsset("profileImageX", asset);
PutDataRequest request = dataMap.asPutDataRequest();
Task<DataItem> putTask = Wearable.getDataClient(this).putDataItem(request);
}
I was able to send my bitmap.
The reason I say this is weird is becasue all I did was change .putAsset
dataMap.getDataMap().putAsset("profileImageX", asset);
to .putLongArray
dataMap.getDataMap().putLongArray("count", newPoint);
Any ideas as to why this isn't working? I noticed sendData only works if the data is new, perhaps this is the issue. In that case, I'd like to know how to erase the "data" send after it is received and used in the WearOS app.
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
is needed in order to work also within your gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "your.applicationid" // needs to be the same in both modules
minSdkVersion 20
targetSdkVersion 23
versionCode 1
versionName "1.0"
targetCompatibility = '1.7'
}
...
Also as you say I think you need to put something that's really new all the time like System MillTimes
dataMap.getDataMap().putLong("Time",System.currentTimeMillis())

The use Gradle properties in build.gradle

I read through this, official Gradle reference and migration guide, and I still cannot figure out why the following build script doesn't work.
apply plugin: 'java-library'
repositories {
jcenter()
}
dependencies {
testImplementation group: 'org.testng', name: 'testng', version: '6.14.3'
}
def t_threads = test_threads
test {
useTestNG() {
setParallel('methods');
setThreadCount(t_threads)
}
maxParallelForks = t_threads
}
task printProps {
println test_threads
}
My gradle.properties file:
test_threads = 1
gradle printProps fails on the line setThreadCount(t_threads) with the exception: Could not find method setThreadCount() for arguments 1 on object of type org.gradle.api.tasks.testing.testng.TestNGOptions. If I change my code to def t_threads = 1, then gradle printProps finishes without an error displaying 1.
Answer is quite simple. setThreadCount expects Integer as a parameter, but property is a String, so all I had to do is convert String to Integer using test_threads as Integer.

How to get versionCode of app outside my own?

I am attempting to add a function to that will check a json file on my server for the versionCode of an app outside of my own and if the versionCode in json on the server is greater than the one of the app outside of my own, then do an update action.
The update action works fine, however, I am experiencing issues getting the versionCode of the outside app. The versionCode always returns as 0 instead of the actual version of the outside app.
Why doesn't it return the proper version?
Here is my code for fetching the versionCode of the other app:
public static int getinstVersionCode(Context mContext) {
if (mContext != null) {
try {
return mContext.getPackageManager().getPackageInfo(Constants.PACKAGE_NAME, 0).versionCode;
} catch (PackageManager.NameNotFoundException ignored) {
}
}
return 0;
}
The PACKAGE_NAME equals the com.example.app app package name that is held in the json file on my server:
static final String APK_VERSION_CODE = "versionCode";
static final String PACKAGE_NAME = "package";
And finally, the json file itself:
"versionCode":0,
"package":"com.example.app",
Check the exception, the application which version you are trying to get must be present on the device and exactly match the package name.

init.gradle read properties from command line

In my gradle script I've been able to successfully read properties like this:
def environment = hasProperty('env') ? env : 'dev'
Using this I can execute a build script like this:
gradlew clean assemble -Penv=prod
My issue comes in when I tried moving this to an init.gradle file. The file is recognized and I'm able to use other properties that I define in the script, however I'm not able to get any from the command line. How can I do this?
My init.gradle file:
allprojects {
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
project.ext['nexusDomainName'] = 'https://example.com/nexus'
project.ext['compileSdkVersion'] = 19
project.ext['buildToolsVersion'] = "19"
project.ext['minSdkVersion'] = 8
project.ext['targetSdkVersion'] = 19
project.ext['sourceCompatibility'] = '1.7'
project.ext['targetCompatibility'] = '1.7'
//hasProperty('release') is always false
project.ext['archiveType'] = hasProperty('release') ? '' : '-SNAPSHOT'
project.ext['archiveUrl'] = hasProperty('release') ? "$nexusDomainName/content/repositories/releases/" : "$nexusDomainName/content/repositories/snapshots/"
// This buildEnv property won't read either
project.ext['buildEnv'] = hasProperty('env') ? env : 'dev'
println "prepping for $buildEnv"
project.ext['archivesBaseNameSuffix'] = (project.ext['buildEnv'] == 'stage' || project.ext['buildEnv'] == 'dev') ? '-' + project.ext['buildEnv'] : ''
repositories {
mavenLocal()
maven {
credentials {
username 'username'
password 'password'
}
url "$nexusDomainName/content/groups/public/"
}
mavenCentral()
}
}
-P sets a project property, which isn't immediately available in an init script. (You can access projects and their properties from an init script, but that access will be deferred until the projects have been created.) However, using a system property (-D) should work.

Categories

Resources