Build multiple (test/prod) versions of Android APKs in Eclipse

前端 未结 5 472
鱼传尺愫
鱼传尺愫 2020-12-24 07:38

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).

相关标签:
5条回答
  • 2020-12-24 07:46

    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.

    0 讨论(0)
  • 2020-12-24 07:47

    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.

    1. prepare two xml android resource file.
    2. build a package with resource #1
    3. overwrite resource #1 with content of resource #2
    4. 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>
    
    0 讨论(0)
  • 2020-12-24 07:48

    For passing parameters, you could always create a file in android's directory system and have your code read it from it.

    0 讨论(0)
  • 2020-12-24 07:52

    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>
    
    0 讨论(0)
  • 2020-12-24 07:58

    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.

    0 讨论(0)
提交回复
热议问题