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

发布于 2024-09-28 13:08:47 字数 278 浏览 0 评论 0原文

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

理想情况下,我只希望我的 Eclipse 构建 2 个 APK,一个包含产品服务器,另一个包含开发服务器。

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

顺便说一句,我想以 1.5 为目标,并且我想使用 Eclipse 自动构建工具,所以我正在寻找最通用的解决方案。

谢谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

涫野音 2024-10-05 13:08:47

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

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

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

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>

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>
烦人精 2024-10-05 13:08:47

将所有代码移至库项目,请参阅
http://developer.android.com/guide/developing/projects /projects-eclipse.html#SettingUpLibraryProject

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

类似这样的:

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

这对于管理不同的 http 端点来说似乎有点矫枉过正,但它会让代码更易于管理。您还可以做一些有用的事情,例如:

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

这一切都可以在 eclipse 中完成,无需使用第三方工具。

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.

獨角戲 2024-10-05 13:08:47

这并不是您真正想要的:

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

如果应用程序使用调试密钥进行签名,并使用发布证书进行生产,那么您可以访问开发/登台服务器。

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.

离线来电— 2024-10-05 13:08:47

为了传递参数,您始终可以在 android 的目录系统中创建一个文件,并让您的代码从中读取它。

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

在巴黎塔顶看东京樱花 2024-10-05 13:08:47

就我而言,我只想在不同版本之间更改 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< /code> 目录,将目录名称保存在 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,然后从原始(未修改的)res/values/strings.xml< 中提取 app_version /code>:

<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 告诉 < code>debug 目标使用我修改后的 res 目录,该目录在上面的 config.resources 属性中定义;
  • out.final.file 告诉它生成一个具有不同名称的 APK,包括配置名称(例如 student-testing)和从 字符串中提取的版本号.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>

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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文