We have an Android app built with Mono for Android, and now we have desire to make a deployable test version for use in acceptance testing. It is important that the production version remains on the device and keeps working. What is the recommended way of creating a test build without causing interference like package name collisions?
This solution applies to Mono for Android and allows you to change the package name of an application based on build configuration in Visual Studio:
Create a new Build Configuration, Test, for your solution.
Define a new Conditional compilation symbol, TEST, in your project.
Rename your existing AndroidManifest.xml to AndroidManifest-Template.xml
Create two .xslt files in the Properties folder:
manifest-transform.xslt:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/manifest/#package">
<xsl:attribute name="package">
<xsl:value-of select="'<your.test.package.name.here>'" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
manifest-copy.xslt:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Add two XslTransformation tasks to the BeforeBuild target of your project file:
<Target Name="BeforeBuild">
<XslTransformation
Condition="'$(Configuration)|$(Platform)' != 'Test|AnyCPU'"
XslInputPath="Properties\manifest-copy.xslt"
XmlInputPaths="Properties\AndroidManifest-Template.xml"
OutputPaths="Properties\AndroidManifest.xml" />
<XslTransformation
Condition="'$(Configuration)|$(Platform)' == 'Test|AnyCPU'"
XslInputPath="Properties\manifest-transform.xslt"
XmlInputPaths="Properties\AndroidManifest-Template.xml"
OutputPaths="Properties\AndroidManifest.xml" />
</Target>
Use the TEST symbol for conditional code:
#if TEST
[Application(
Label = "App Test",
Theme = "#style/Theme.App.Test",
Icon = "#drawable/ic_launcher_test")]
#else
[Application(
Label = "App",
Theme = "#style/Theme.App",
Icon = "#drawable/ic_launcher")]
#endif
You can now switch between test and regular app by changing build config :)
Changing the package name should probably be enough to keep things from conflicting, unless you are writing data to a hardcoded location, which would also need to be changed.
Related
I'm running Android Espresso tests using Junit4 annotations. Once finished it generates an junit.xml output file like this:
<?xml version="1.0"?>
<testsuites tests="1" failures="0" name="UITests" time="12">
<testsuite tests="1" failures="0" name="Test" time="232.9559440612793">
<testcase classname="Test" name="test()" time="42.36027908325195">
</testcase>
</testsuite>
</testsuites>
However I want to be able to import my tests cases to our test case management tool. In order to do so I need to to add a property to my junit.xml file. So the end result should be like this:
<?xml version="1.0"?>
<testsuites tests="1" failures="0" name="UITests" time="12">
<testsuite tests="1" failures="0" name="Test" time="232.9559440612793">
<testcase classname="Test" name="test()" time="42.36027908325195">
<properties>
<!-- using a custom "test_id" property -->
<property name="test_id" value="1234567" />
</properties>
</testcase>
</testsuite>
</testsuites>
Is there an easy way of realising this, by for instance using (custom) annotations?
Similarly to to this question, after upgrading a project to Android Studio 3.5, the .idea/misc.xml file keeps flip flopping between two developers, one on mac, another on linux with the following line:
## -1,6 +1,6 ##
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
- <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
Essentially, the project-jdk-name attribute keeps switching between the values JDK or 1.8. I've looked through many configuration options but can't seem to find the place where I can set this value to avoid it changing between commits on both platforms. Or maybe there is a way to ignore this specific line change while allowing changes to the rest of the file?
I'm trying to start my Html Project but i'm facing some problems. The desktop and Android projects work well. The problem is that I have an other project I use as a library that is not being imported or something.
[ERROR] [com.mobilecostudios.walkingskeleton.GwtDefinition] - Errors in 'file:/C:/Users/chelo/Documents/mobilecostudios-libgdx/trunk/walkingskeleton/WalkingSkeleton/src/com/mobilecostudios/walkingskeleton/GameLoop.java'
[ERROR] [com.mobilecostudios.walkingskeleton.GwtDefinition] - Line 21: No source code is available for type com.mobilecostudios.gamelibrary.Domain.BaseSprite; did you forget to inherit a required module?
My Project hierarchy is:
GameDevLibrary
WalkingSkeleton
WalkingSkeleton-html
My gwt.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name='com.badlogic.gdx.backends.gdx_backends_gwt' />
<inherits name='GameLoop' />
<entry-point class='com.mobilecostudios.walkingskeleton.client.GwtLauncher' />
<set-configuration-property name="gdx.assetpath" value="../WalkingSkeleton-android/assets" />
</module>
I have added the proyect to the build path already.
What else am I missing?
Build Path
You have to make sure that you also add the project's source code to your path. Any GWT Java modules that will be used client side needs to have its source code available.
In your case,
<inherits name='GameLoop' />
Should be:
<inherits name='com.mobilecostudios.walkingskeleton.GameLoop' />
Also, where does com.mobilecostudios.gamelibrary.Domain.BaseSprite come from? If it's used client side you need to add it to the module .gwt.xml file. Should be something like:
<inherits name='com.mobilecostudios.gamelibrary.GameLibrary' />
Above, I am assuming that GameLibrary.gwt.xml is the GWT module XML file for the project that contains com.mobilecostudios.gamelibrary.Domain.BaseSprite.
Basically, when you want to use an external GWT module in your own project on the client side you need to import it into your project by adding the sources and binaries to your build path and you also need to add an <inherits name='...'> to your .gwt.xml file of your project.
For projects that have more than one package you have to add an .gwt.xml for every package that you are using :
as you can see in above picture i add controller.gwt.xml for controller objects.gwt.xml for objects and so on ... and inside these .gwt.xml files you must write something like this :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
<source path="com/me/controller" />
</module>
for example this is my controller.gwt.xml then add an inherit tag to your GwtDefinition.gwt.xml file like this :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name='com.badlogic.gdx.backends.gdx_backends_gwt' />
<inherits name='MyGdxGame' />
<inherits name='objects' />
<inherits name='settings' />
<inherits name='controller' />
<entry-point class='com.me.mygdxgame.client.GwtLauncher' />
<set-configuration-property name="gdx.assetpath" value="../cannongame-android/assets" />
</module>
Some Android libraries such as Google Analytics use resources for configuration purposes (e.g. ga_trackingId).
In these cases, I have different values for debug and production. What I currently do is manually comment the production values when I'm debugging, and viceversa. It looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- DEBUG -->
<string name="ga_trackingId">UA-12345678-1</string>
<integer name="ga_dispatchPeriod">1</integer>
<bool name="ga_debug">true</bool>
<!-- PRODUCTION -->
<!--string name="ga_trackingId">UA-87654321-1</string>
<integer name="ga_dispatchPeriod">120</integer>
<bool name="ga_debug">false</bool-->
</resources>
This way of switching configuration is tedious and error-prone, and generates unnecessary repository changes if I'm not careful. Is there a better way?
(e.g.: on iOS I use conditional compilation with the IF DEBUG macro)
Under the src folder you probably have a main folder where you store all shared stuff. But you can have specific resources for flavours or build types.
Put a folder named debug under the src folder where you will place a copy of your xml file but with with proper content. You have to maintain the folder structure under debug so the global_tracker.xml needs to be placed in ../src/debug/res/xml
Your folder structure should look like this:
Android Studio will notice that this xml file have multiple versions.
This is what you should see in AS:
You can use this for all kind of resources, i.e., have multiple versions of the same file and it will be "magically" chosen properly.
I had a similar issue with Google Maps keys where they depend on the signature. What I did was to use the ant script which generates/copies resources to the project conditionally. You can include the ant script in Eclipse under the Project>Properties>Builders
If you need to use the DEBUG value in the code, you can create a java file with static values that will be included conditionally too.
Please comment if ant environment variables worked properly (you can see the "Build type: " message in console after execution of the script).
<project name="build-res">
<property name="conditional.resources.dir" value="myresources" />
<property name="keys_file" value="res/values/keys.xml" />
<target name="copy-release" if="${build.mode.release}" >
<property name="build.type" value="Release" />
<echo message="Build type: ${build.type}" />
<property name="google.maps.key" value="nanana-value-for-release" />
<copy file="${conditional.resources.dir}/Release.java" tofile="gen/com/example/project/BuildInfo.java" />
</target>
<target name="copy-debug" if="${build.mode.debug}">
<property name="build.type" value="Debug" />
<echo message="Build type: ${build.type}" />
<property name="google.maps.key" value="lalala-value-for-debug" />
<copy file="${conditional.resources.dir}/Debug.java" tofile="gen/com/example/project/BuildInfo.java" />
</target>
<target name="build-res" depends="copy-debug,copy-release">
<echo file="${keys_file}" message="<?xml version='1.0' encoding='utf-8'?><resources><string name='google_maps_key'>${google.maps.key}</string></resources>" />
</target>
</project>
I'm looking to optimize generating of slightly different APKs of the same Android app, the only difference being the http API server it's using (dev/staging/prod).
Ideally, I'd just want my Eclipse to build 2 APKs, one with the prod server and one with the dev one.
I'm even OK with having 2 Run configurations, but I haven't been able to figure out how to pass parameters to the app and read them from the code.
I want to target 1.5, BTW, and I'd like to use Eclipse auto-build tools, so I'm looking for the most generic solution.
Thank you.
I think using ant build script would be the easiest solution. Eclipse supports ant build, so you can run ant command in eclipse.
You can solve your problem with ant like this.
prepare two xml android resource file.
build a package with resource #1
overwrite resource #1 with content of resource #2
build another package
xml would be like this:
resource #1:
<resources>
<string name="target">dev</string>
</resources>
resource #2:
<resources>
<string name="target">staging</string>
</resources>
and ant script would be like this:
<project>
<target name="build_all">
<copy file="res1.xml" to="res/values/target.xml"/>
<ant antfile="build.xml" target="debug"/>
<copy file="res2.xml" to="res/values/target.xml"/>
<ant antfile="build.xml" target="debug"/>
</target>
</project>
Move all you code to a library project see
http://developer.android.com/guide/developing/projects/projects-eclipse.html#SettingUpLibraryProject
Then create separate projects in eclipse for test and production each with a unique package name. You can then use the package name to distinguish between versions.
Something like:
public static boolean isProductionVersion(){
return context.getPackageName().toLowerCase().contains("production");
}
This may seem like overkill for managing different http end points but it will make the code more manageable. You can also do useful things like:
flag the test version with a different application icon
run test and production versions side by side on one device
This can all be done in eclipse without using and third party tools.
Its not really what you want:
private static Boolean isSignedWithDebugKey = null;
protected boolean signedWithDebug() {
if(isSignedWithDebugKey == null) {
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(getPackageName(), 0);
isSignedWithDebugKey = (pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
catch(NameNotFoundException nnfe) {
nnfe.printStackTrace();
isSignedWithDebugKey = false;
}
}
return isSignedWithDebugKey;
}
You could then hit a dev/staging server if the app is signed with a debug key, and production with a release certificate.
For passing parameters, you could always create a file in android's directory system and have your code read it from it.
In my case I just wanted to change a few values in strings.xml between different versions.
First I have to load the ant-contrib library, to define the for loop task:
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="lib/ant-contrib-1.0b5-SNAPSHOT.jar" />
</classpath>
</taskdef>
I put my list of configurations, config.names, in a properties file:
config.url.root=http://projectserver.aptivate.org/
config.names=student-production, teacher-production, student-testing, teacher-testing
And define a build-all target, that loops over the config.names:
<target name="build-all">
<for param="config.name" trim="true" list="${config.names}">
<sequential>
Defining a custom resources directory for each one, saving the directory name in the config.resources property:
<var name="config.resources" unset="true" />
<property name="config.resources" value="bin/res-generated/#{config.name}" />
Delete it, and copy the global resources from res into it:
<delete dir="${config.resources}" />
<copy todir="${config.resources}">
<fileset dir="res"/>
</copy>
Change - to / in the config name, to make it a path in the URL parameter:
<var name="config.path" unset="true" />
<propertyregex property="config.path"
input="#{config.name}" regexp="-"
replace="/" casesensitive="true" />
Run an XSLT transform to modify the strings.xml file:
<xslt in="res/values/strings.xml"
out="${config.resources}/values/strings.xml"
style="ant/create_xml_configs.xslt"
force="true">
<param name="config.url.root" expression="${config.url.root}" />
<param name="config.name" expression="#{config.name}" />
<param name="config.path" expression="${config.path}" />
</xslt>
This is the XSLT stylesheet that I use:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="config.url.root" />
<xsl:param name="config.name" />
<xsl:param name="config.path" />
<!-- http://my.safaribooksonline.com/book/xml/9780596527211/creating-output/xslt-id-4.6 -->
<xsl:template match="/">
<!--
This file is automatically generated from res/values/strings.xml
by ant/custom_rules.xml using ant/create_xml_configs.xslt.
Do not modify it by hand; your changes will be overwritten.
-->
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:for-each select="#*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<!-- the value of update_server_url must end with a slash! -->
<xsl:template match="string[#name='update_server_url']/text()">
<xsl:value-of select="$config.url.root" /><xsl:value-of select="$config.path" />/
</xsl:template>
<xsl:template match="string[#name='app_version']/text()">
<xsl:value-of select="." />-<xsl:value-of select="$config.name" />
</xsl:template>
</xsl:stylesheet>
And back to custom_rules.xml where I then extract the app_version from the original (unmodified) res/values/strings.xml:
<xpath input="res/values/strings.xml"
expression="/resources/string[#name='app_version']"
output="resources.strings.app_version" />
And use the antcall task to call the debug build:
<antcall target="debug">
<param name="resource.absolute.dir" value="${config.resources}" />
<param name="out.final.file" value="${out.absolute.dir}/${ant.project.name}-${resources.strings.app_version}-#{config.name}.apk" />
</antcall>
with two changed property values:
resource.absolute.dir tells the debug target to use my modified res directory, defined in the config.resources property above;
out.final.file tells it to produce an APK with a different name, including the configuration name (e.g. student-testing) and the version number extracted from strings.xml.
And then, finally, I can run ant build-all from the command line and build all four targets. A little bit more script, just before the end of the build-all target, lists the compiled APK files together for reference:
<echo message="Output packages:" />
<for param="config.name" trim="true" list="${config.names}">
<sequential>
<echo message="${out.absolute.dir}/${ant.project.name}-${resources.strings.app_version}-#{config.name}.apk" />
</sequential>
</for>