在Eclipse中构buildAndroid APK的多个(testing/产品)版本

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

理想情况下,我只想让我的Eclipse构build2个APK,一个是产品服务器,另一个是开发者。

我甚至可以有2个运行configuration,但我一直无法弄清楚如何将parameter passing给应用程序,并从代码中读取它们。

我想定位1.5,顺便说一句,我想使用Eclipse自动生成工具,所以我正在寻找最通用的解决scheme。

谢谢。

Solutions Collecting From Web of "在Eclipse中构buildAndroid APK的多个(testing/产品)版本"

我认为使用ant构build脚本将是最简单的解决scheme。 Eclipse支持ant build,所以你可以在eclipse中运行ant命令。

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

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

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> 

把你所有的代码移动到一个库项目中去看http://developer.android.com/guide/developing/projects/projects-eclipse.html#SettingUpLibraryProject

然后在eclipse中创build单独的项目进行testing和生产,每个项目都有一个唯一的包名称。 然后您可以使用软件包名称来区分版本。

就像是:

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

这对于pipe理不同的http端点似乎有些过分,但它会使代码更易于pipe理。 你也可以做一些有用的事情,比如:

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

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

它不是你想要的:

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

如果应用程序使用debugging密钥进行签名,然后使用发行证书进行生产,则可以击中开发/暂存服务器。

为了传递参数,你总是可以在android的目录系统中创build一个文件,并让你的代码读取它。

就我而言,我只是想在不同版本的strings.xml改变一些值。

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

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

我把configuration列表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> 

更改-在configuration名称中,使其成为URL参数中的path:

 <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

 <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目标使用我在上面的config.resources属性中定义的修改后的res目录;
  • out.final.file告诉它产生一个不同名称的APK,包括configuration名称(例如student-testing )和从strings.xml提取的版本号。

然后,最后,我可以从命令行运行ant build-all并构build全部四个目标。 稍微多一点的脚本,在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>