My application uses a large number of MapView screens and I'm trying to figure out how to manage the API key between the debug environment and production. Apparently, there is no way to change the debug application key in Eclipse so I must use a debug map API key in that environment. Conversely, there is no way to export a package for beta testing without a production application key so I must change the map API key in every view in order to create a working package.
My first idea was to do this:
All MapView.xml files have this:
android:apiKey="#string/googleMapsAPIKey"
And then in strings.xml I put this:
<string name="googleMapsPIKey">#string/debugGoogleMapsAPIKey</string>
<string name="debugGoogleMapsAPIKey">TheMagicKeyString</string>
If this worked, it would allow me to change a single line in strings.xml and all the MapViews would get updated in the rebuild. But it didn't work. I guess strings.xml can't make references into itself. Any other ideas?
Thanks
I recommend a simpler approach that involves taking advantage of an unlikely, but more specific asset folder to house your debug key. To set this up, create a file res/values/maps-apikey.xml with the following contents:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="maps_apikey">[productionApiKey]</string>
</resources>
Then each developer locally will add a file derived from this one in res/values-v1/maps-apikey.xml where their debug API key is provided. At runtime, the Android system will favor the more specific version res/values-v1/maps-apikey.xml for all versions of Android (since all are at least on API level 1 or higher).
Source control systems like git and svn allow you to add an "ignore" file which directs the tools to ignore this res/values-v1/maps-apikey.xml file so that each developer does not accidentally commit it to the repository. To do this for git, simply add a file res/.gitignore which contains only the line values-v1 then commit this file.
To release your software, simply delete the res/values-v1/maps-apikey.xml file before exporting a release. The resulting APK will then reference the version in res/values/maps-apikey.xml which is your correct production key.
you are doing the right thing but not the right way I think. Declare your string in strings.xml like this :
<string name="googleMapsAPIKey">TheMagicKeyString</string>
<!-- You can add this at the end as comment to keep a copy of another key for instance, to exchange it between debug and production-->
Note that you didn't give the same name at your 2 strings... One is called debug and not the other.
I'm using maven and the maven-android-plugin, with a res-overlay directory that is only used in the release configuration.
Consequently, I have a res/values/google_api_key.xml file containing the debug key and a res-overlay-production/values/google_api_key.xml file containing the production key, and the latter overrides the former in the production release.
I'm also using Eclipse ADT, but this doesn't know about the release configuration, so it's happy to see the debug key and I can use the Android XML editors to set up my map views.
I'm using maven-android-plugin and I'm using a sneaky token replacement mechanism to do this.
I'm using the "morseflash" sample, and added this to the maven-resources plugin configuration:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
<configuration>
<delimiters>
<delimiter>${*}</delimiter>
<delimiter>>08*<</delimiter>
</delimiters>
</configuration>
</plugin>
The resources plugin allows you to define weird delimiters for search/replace. The default delimiter is ${*}, but I added >*< so it would match XML element content. (Actually I used >08*<; I'll explain why in a moment.)
Then, in my strings.xml, I wrote this:
<string name="googleMapsAPIKey">08DEBUGKEYABCDEFBLAHBLAHBLAH</string>
And defined a Maven property in the release profile, like this:
<profile>
<id>release</id>
<!-- via this activation the profile is automatically used when the release is done with the maven release
plugin -->
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<properties>
<DEBUGKEYABCDEFBLAHBLAHBLAH>>08RELEASEKEYABCDEFBLAHBLAHBLAH<</DEBUGKEYABCDEFBLAHBLAHBLAH>
</properties>
<-- ... -->
</profile>
That creates a Maven property named after the debug Maps key, whose value is the release debug key.
Unfortunately, Maven properties are not allowed to start with numbers. My debug key and my release key both started with 08Wfj... So I used the delimiter >08*< and made sure to include >08 in my replacement string.
I think this is a good way to do it! With Sephy's correction it should work perfectly.
On top of that, if you want to switch keys automatically between the debug & release builds, you can have a look at this post I just wrote: http://blog.cuttleworks.com/2011/02/android-dev-prod-builds/. It helped me stop worrying about configuration when building for different environments.
Try something like this:
String debugMapKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
String releaseMapKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
String mapKey = BuildConfig.DEBUG ? debugMapKey : releaseMapKey;
MapView mv = new MapView(this, mapKey);
You can set custom debug keystore in Prefs window -> Android->Build.
In the google developer console you can create one key for multiple sha1 codes
https://stackoverflow.com/a/13881624/1433372
Related
If I don't create a src/android/AndroidManifest.xml file in my Gluon project, then the mvn gluonfx:package command creates one for me with some relatively sensible defaults. However, I need to make some changes to the generated AndroidManifest.xml for my app (such as indicating support for multiple screen resolutions, and I need to add the BILLING permission).
If I copy the generated AndroidManifest.xml to src/android/AndroidManifest.xml as suggested during gluonfx:package, then Gluon no longer updates the version code and version name fields for me. I'm also not sure if there any any other side-effects to manually editing the AndroidManifest.xml file.
So my questions are:
What's the best practice when it comes to managing AndroidManifest.xml for a Gluon project?
How do folks deal with updating the version code and version name in a manually edited file as part of a CI/CD pipeline, where I don't want to have to manually edit AndroidManifest.xml for each build?
Are there any pitfalls to managing the AndroidManifest.xml outside the gluonfx:package command?
As documented here, you should use <releaseConfiguration/> to define the values that are required or need to be updated for each new release.
For Android, besides the keystore signing properties, you can also define:
version code
version name
app label
like:
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>${gluonfx.maven.plugin.version}</version>
<configuration>
<target>${gluonfx.target}</target>
<releaseConfiguration>
<versionCode>2</versionCode>
<versionName>3.0</versionName>
<appLabel>MyHelloFX</appLabel>
</releaseConfiguration>
...
So in case you need to add the AndroidManifest to src/Android (the one that was generated in target/gluonfx/aarch64-android/gensrc/android/AndroidManifest.xml), in order to add/modify part of it, it will be always updated for those three values, whenever you change them in the pom.
About CI/CD, have a look at the HelloGluon CI sample.
It doesn't have a custom manifest, but it shows how to deal with ReleaseConfiguration and updating release values in a CI environment.
The pom defines some properties that are used by the releaseConfiguration block:
<properties>
...
<main.class>com.gluonhq.hello.HelloGluonApp</main.class>
<app.identifier>${main.class}</app.identifier>
<app.description>The HelloGluon app</app.description>
<version.code/>
<provided.keystore.path/>
</properties>
...
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>${gluonfx.maven.plugin.version}</version>
<configuration>
...
<releaseConfiguration>
<vendor>Gluon</vendor>
<description>${app.description}</description>
<packageType>${package.type}</packageType>
<!-- for macOS/iOS -->
<macAppStore>${mac.app.store}</macAppStore>
<bundleShortVersion>${bundle.short.version}</bundleShortVersion>
<bundleVersion>${bundle.version}</bundleVersion>
<!-- for Android -->
<versionCode>${version.code}</versionCode>
<providedKeyStorePath>${provided.keystore.path}</providedKeyStorePath>
...
These properties are ultimately defined for each profile:
<profile>
<id>android</id>
<properties>
<gluonfx.target>android</gluonfx.target>
<app.identifier>com.gluonhq.samples.hellogluon</app.identifier>
<version.code>${env.GITHUB_RUN_NUMBER}</version.code>
...
When running the Android job, the required variables and secrets are used:
- name: Gluon Build
run: mvn -Pandroid gluonfx:build gluonfx:package
env:
GLUON_ANDROID_KEYSTOREPATH: ${{ steps.android_keystore_file.outputs.filePath }}
...
I use gmaps in my app and the api key from a file looks like:
<resources>
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">
<!-- DEBUG -->
<!-- AIzaSyB#####MY_DEBUG_API_KEY_HERE -->
<!-- RELEASE -->
AIzaSyBS####MY_RELEASE_KEY_HERE
</string>
I wouldn't like to change beetwen keys each time i build a release because i could easily forget about it and in that way gmaps wont work in released app.
I taught about using only one key but from almost every source i looked up it is marked as bad practice.
So is there an easy way/option maybe with build type/flavour to somehow made the build process "smart" to :
When i build in debug mode my build could use the debug api key and vica vera with the release build?
You can define resource files in build type specific folders.
For example, in /app/src/debug/res/values/strings.xml:
<string name="google_maps_key">debug_maps_key_here</string>
And in /app/src/release/res/values/strings.xml:
<string name="google_maps_key">release_maps_key_here</string>
The build system will automatically use only the resources for the build type it is currently building, thus using the correct key for each build.
I have a Parse account that I'm using to store user data for my Android application. Because I'm using source control, I don't want to leave my secret key embedded in the code. Is there a way to have a "config" file that I would keep out of source control, that can then host the key? If that's not feasible, what are the best practices of handling such a situation?
Yes, you can create a folder outside of source control, put a file called app.properties in there, put your key in that properties file and add the folder to your build path. Then use a properties loader to load it from the classpath.
If you have many developers or more than one dev machine, you can set the local properties location as a variable in your build path so that each developer can configure their own.
One option is to put the key in an environment variable and then read it during your build.
in your pom.xml declare a property (secret.key)
<properties>
<secretKey>${env.SECRET_KEY}</secretKey>
<properties>
further down enable "filtering" on your resources
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
In resources maintain a "config.properties" to read with the variable ready for substitution:
secret_key=${secretKey}
Filtering in maven will replace ${secret.key} with the value from your environment variable.
If you are using gradle for your build with Android studio see section 16.6.6.2 on filtering files.
Within build.gradle add the following
import org.apache.tools.ant.filters.FixCrLfFilter
import org.apache.tools.ant.filters.ReplaceTokens
task copyProductionConfig(type: Copy) {
from 'source'
include 'config.properties'
into 'build/targetpath/config'
expand([
secretKey: System.getenv("SECRET_KEY")
])
}
In gradle you can also request input when you run gradlew using
Console console = System.console()
def password = console.readPassword("Enter Secret Key: ")
And then apply it to the appropriate config or source files.
We have a unique situation where we are deploying a Xamarin.Android app to China to 33 app stores. Hence, our solution has 33 application projects, and we setup Jenkins (running on Windows) to package and sign all our apks (otherwise it would be crazy to make builds).
We also need to modify android:versionCode and android:versionName in the manifest file, by using the ${SVN_REVISION} value from Jenkins. Is there a way to pass these values command line to MSBuild?
Normally we would hand edit this value, but it's not possible because of so many application projects.
Our build parameters right now look like this in Jenkins:
/p:Configuration=Release;AndroidKeyStore=True;AndroidSigningKeyStore=ourkeystore.keystore;AndroidSigningStorePass=ourpassword;AndroidSigningKeyAlias=ouralias;AndroidSigningKeyPass=ourpassword /t:SignAndroidPackage
Add this to the end of your *.csproj file, before the ending </Project> tag:
<Target Name="BeforeBuild" Condition=" '$(JENKINS)' == '1' ">
<XmlPoke XmlInputPath="Properties\AndroidManifest.xml" Namespaces="<Namespace Prefix='android' Uri='http://schemas.android.com/apk/res/android' />" Query="manifest/#android:versionCode" Value="$(SVN_REVISION)" />
<XmlPoke XmlInputPath="Properties\AndroidManifest.xml" Namespaces="<Namespace Prefix='android' Uri='http://schemas.android.com/apk/res/android' />" Query="manifest/#android:versionName" Value="2.0.$(SVN_REVISION)" />
</Target>
I have Jenkins configured to pass JENKINS=1 and SVN_REVISION. When it goes to build, it modifies AndroidManifest.xml before the build.
I don't know if this will work on xbuild on a Mac or not, depends on if XmlPoke is implemented. I should do a blog post on this.
No. You'll have to manipulate the android:versionCode and android:versionName yourself. Personally, I use a rake task to handle this particular detail.
I have an XML file that contains some config data for my Android App. In it there is config info that can be used for development and production. E.g. the link to our api can be set as follows:
For production:
<api>api.example.com</api>
For development:
<api>dev.example.com</api>
I keep this config file under /assets/app-config.xml
It is quite a hassle to keep having to remember which setting I have in the XML. Is there a way to automatically configure eclipse/ android so that it uses the production for runtime (export etc.) and the development when in debug mode.
Define multiple resources and use BuildConfig.DEBUG to conditionally get a resource or another:
<string name="url_api">api.example.com</string>
<string name="url_api_dev">dev.example.com</string>
When extracting the resource:
getString(BuildConfig.DEBUG ? R.string.url_api_dev : R.string.url_api);
This constant is set to true as long as you run from Eclipse. When you select the Export Signed Application Package option, it will be set to false.
If you use this method, it is a good idea to be aware of this bug.
Customize your build using ANT
Please refer the following link for more information
http://playaprogrammer.blogspot.com/2013/01/android-build-configuration-tutorial.html
I use this to create test and production builds from single source. You can have different configurations for development, QA, Production...