在Eclipse中构建Android APK的多个(测试/产品)版本

时间:2010-10-21 00:53:30

标签: android eclipse build settings

我希望优化同一Android应用的稍微不同的APK生成,唯一的区别是它正在使用的http API服务器(dev / staging / prod)。

理想情况下,我只想让我的Eclipse构建2个APK,一个使用prod服务器,另一个使用dev服务器。

我有2个运行配置即可,但我无法弄清楚如何将参数传递给应用程序并从代码中读取它们。

我想定位1.5,BTW,我想使用Eclipse自动构建工具,所以我正在寻找最通用的解决方案。

谢谢。

5 个答案:

答案 0 :(得分:9)

我认为使用ant build脚本是最简单的解决方案。 Eclipse支持ant build,因此您可以在eclipse中运行ant命令。

你可以像这样解决你的问题。

  1. 准备两个xml android资源文件。
  2. 使用资源#1
  3. 构建一个包
  4. 用资源#2的内容覆盖资源#1
  5. 构建另一个包
  6. xml会是这样的:

    资源#1:

    <resources>
        <string name="target">dev</string>
    </resources>
    

    资源#2:

    <resources>
        <string name="target">staging</string>
    </resources>
    

    和ant脚本会是这样的:

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

答案 1 :(得分:4)

将所有代码移到库项目中查看 http://developer.android.com/guide/developing/projects/projects-eclipse.html#SettingUpLibraryProject

然后在eclipse中为测试和生产创建单独的项目,每个项目都有一个唯一的包名。然后,您可以使用包名称来区分版本。

类似的东西:

public static boolean isProductionVersion(){
  return context.getPackageName().toLowerCase().contains("production");
}

这对于管理不同的http端点似乎有些过分,但它会使代码更易于管理。您还可以执行以下有用的操作:

  • 使用不同的应用程序图标标记测试版本
  • 在一台设备上并排运行测试和生产版本

这可以在不使用第三方工具的情况下在eclipse中完成。

答案 2 :(得分:1)

它不是你想要的:

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;
    }

如果应用程序使用调试密钥签名,并且使用发布证书生成,则可以访问dev / staging服务器。

答案 3 :(得分:0)

对于传递参数,您总是可以在android的目录系统中创建一个文件,并让您的代码从中读取它。

答案 4 :(得分:0)

在我的情况下,我只是想在不同版本之间更改strings.xml中的一些值。

首先我必须加载ant-contrib库,以定义for循环任务:

<taskdef resource="net/sf/antcontrib/antcontrib.properties">
    <classpath>
        <pathelement location="lib/ant-contrib-1.0b5-SNAPSHOT.jar" />
    </classpath>
</taskdef>

我将配置列表config.names放在properties文件中:

config.url.root=http://projectserver.aptivate.org/
config.names=student-production, teacher-production, student-testing, teacher-testing

定义一个build-all目标,该目标循环遍历config.names

<target name="build-all">
    <for param="config.name" trim="true" list="${config.names}">
        <sequential>

为每个目录定义自定义resources目录,将目录名保存在config.resources属性中:

<var name="config.resources" unset="true" />
<property name="config.resources" value="bin/res-generated/@{config.name}" />

删除它,并将全局资源从res复制到其中:

<delete dir="${config.resources}" />

<copy todir="${config.resources}">
    <fileset dir="res"/>
</copy>

在配置名称中将-更改为/,使其成为URL参数中的路径:

<var name="config.path" unset="true" />
<propertyregex property="config.path"
    input="@{config.name}" regexp="-"
    replace="/" casesensitive="true" />

运行XSLT转换以修改strings.xml文件:

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

这是我使用的XSLT样式表:

    <?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>

然后返回custom_rules.xml,然后我从原始(未修改)app_version中提取res/values/strings.xml

<xpath input="res/values/strings.xml" 
    expression="/resources/string[@name='app_version']" 
    output="resources.strings.app_version" />

并使用antcall任务调用debug版本:

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

有两个更改的属性值:

  • resource.absolute.dir告诉debug目标使用我在res属性中定义的修改后的config.resources目录;
  • out.final.file告诉它生成一个名称不同的APK,包括配置名称(例如student-testing)和从strings.xml中提取的版本号。

然后,最后,我可以从命令行运行ant build-all并构建所有四个目标。在build-all目标结束之前,稍微多一点的脚本将已编译的APK文件列在一起以供参考:

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