Android 安卓&x2013;同一应用程序的多个自定义版本

Android 安卓&x2013;同一应用程序的多个自定义版本,android,automation,Android,Automation,部署多个定制版本的Android应用程序的最佳方式是什么 目前,我有一个脚本来交换资源文件夹,以获得我的应用程序的自定义版本。它工作得很好,但是所有自定义版本在AndroidManifest.xml中仍然具有相同的包名。因此,不可能同时安装两个自定义版本的应用程序 你能想出一个更简单的解决方案,或者如何将其构建到SKcript中 (顺便说一句:它不适用于色情/垃圾邮件/任何应用程序,甚至不适用于付费应用程序)链接到解决方案不必手动完成。请记住,元素中的package属性不必位于代码所在的位置,

部署多个定制版本的Android应用程序的最佳方式是什么

目前,我有一个脚本来交换资源文件夹,以获得我的应用程序的自定义版本。它工作得很好,但是所有自定义版本在AndroidManifest.xml中仍然具有相同的包名。因此,不可能同时安装两个自定义版本的应用程序

你能想出一个更简单的解决方案,或者如何将其构建到SKcript中


(顺便说一句:它不适用于色情/垃圾邮件/任何应用程序,甚至不适用于付费应用程序)

链接到解决方案不必手动完成。请记住,
元素中的
package
属性不必位于代码所在的位置,只要您在清单中的其他位置拼写出完全限定的类(例如,
activity android:name=“com.commonware.android.MyActivity”
而不是
activity android:name=“.MyActivity”
)。编写清单更改脚本并使用Ant构建新的APK。好的,那应该行。

对于类似的事情,我所做的只是使用一个antlib任务,然后遍历所有java和xml文件,将旧的包字符串替换为新的包字符串。根据包,文件是否不在正确的src路径中并不重要。只要对所有的文件做一个正则表达式替换就足够让它工作了

例如,要在src目录下的所有java文件中替换它:

 <replaceregexp flags="g" byline="false">
    <regexp pattern="old.package.string" /> 
    <substitution expression="new.package.string" />
    <fileset dir="src" includes="**/*.java" /> 
 </replaceregexp>

我要实现这一点。为生成的源目标指定一个AndroidManifest.xml,为最终apk目标指定另一个AndroidManifest.xml。这样,在生成R类和构建阶段,源代码项目将保留实际的源代码包名称,而适应市场的清单包名称位于最终apk文件中包含的第二个AndroidManifest.xml中。

支持多个合作伙伴 准备config.xml

为不同的合作伙伴构建项目

<!--partner.dir, pkg.name, ver.code, ver.name are input from command line when execute 'ant' -->

<!-- set global properties for this build -->
<property name="build.bin" location="bin"/>
<property name="build.gen" location="gen"/>
<property name="src" location="src"/>
<property name="res" location="res"/>

<target name="preparefiles" description="Prepare files for different partner" >
    <delete dir="${build.bin}" />
    <delete dir="${build.gen}" />

    <copy todir="${res}" overwrite="true" />
        <fileset dir="${partner.dir}/res" /> 
    </copy>

    <!-- change the import in all Java source files -->
    <replaceregexp file="AndroidManifest.xml"
        match='android.versionCode="(.*)"'
        replace='android.versionCode="${ver.code}"'
        byline="false">

    <replaceregexp file="AndroidManifest.xml"
        match='android.versionName="(.*)"'
        replace='android.versionName="${ver.name}"'
        byline="false">

    <replaceregexp file="AndroidManifest.xml"
        match='package="(.*)"'
        replace='package="${pkg.name}"'
        byline="false">

    <!-- change the package name in AndroidManifest -->
    <replaceregexp flags="g" byline="false">
        <regexp pattern="import(.*)com.myproject.com.R;" /> 
        <substitution expression="import com.${pkg.name}.R;" />
        <fileset dir="${src}" includes="**/*.java" /> 
    </replaceregexp>

    <replaceregexp flags="g" byline="false">
        <regexp pattern="(package com.myproject.com;)" /> 
        <substitution expression="\1&#10;import com.${pkg.name}.R;" />
        <fileset dir="${src}" includes="**/*.java" /> 
    </replaceregexp>
</target>

准备文件 $ant-f config.xml-Dpartner.dir=“xxx”-Dpkg.name=“xxx”-Dver.code=“xxx”-Dver.name=“xxx”准备文件

创建build.xml 建造 $ant调试 或
$ant版本

也许在最初发布文章时,内置的Android“库”概念还没有完全成熟,但从2011年起,它可能是首选的方法。对于ant构建,请遵循以下步骤:

从一个工作应用程序(我们称之为目录“myOrigApp”,package com.foo.myapp)开始,只需将这一行添加到“default.properties”以使其成为一个库:

android.library=true
现在,以您喜欢的任何方式在同级目录中创建一个新应用程序(让我们称之为目录“sibling”,package com.foo.myVariant)。例如,使用Intellij Idea,“从头开始”创建一个包含目录“sibling”的项目,它将创建您通常需要的所有文件/目录

在新的同级目录中,编辑“default.properties”以添加依赖项:

android.library.reference.1=../myOrigApp
从原始目录复制清单:

cd sibling
cp ../myOrigApp/AndroidManifest.xml  ../myOrigApp/local.properties ../myOrigApp/build.properties  .
编辑复制的清单文件,将其包名更改为新变量“com.foo.myVarient”;这是唯一的改变

如果您只是运行ant构建脚本,您可能已经完成了。(我只需要设置签名密钥。)

如果要设置类似IDE的IDE,使库项目作为变体项目的从属项目,请按照以下步骤将库项目添加到变体项目中(假设已经为这两个项目设置了项目):

  • 打开原始项目,打开项目设置,选择您的方面,选中“是库项目”并保存
  • 打开变体项目,调出项目设置,选择模块
  • 添加模块
  • 选择“导入现有模块”
  • 浏览到原始目录(myOrigApp)并选择其.iml文件(IntelliJ项目源文件)
  • 单击“完成”。(库项目作为模块添加到变体项目中。)
  • 在模块列表中,单击变体项目以将其选中
  • 在右侧选择“依赖项”选项卡
  • 单击“添加…”
  • 选择“Module dependency…”(应显示一个列表,其中包括您先前添加到项目中的模块/库的名称——可能是列表中唯一的条目)
  • 选择添加的库项目,然后按“确定”。(它将被添加到项目的依赖项列表中。)
  • 按“确定”完成项目的配置。(您应该看到两个模块,其中库的资源和类在变体项目中可用并得到认可。)

我最后编写了一个脚本来修补源代码;修补源代码听起来有风险,但在版本控制中,风险是可以接受的

所以我制作了一个版本,提交了源代码,制作了另一个版本,提交了源代码,然后查看diff,用Python编写了一个修补脚本

我不确定这是否是最好的解决办法。(代码遗漏了一些os.path.join)

脚本的核心是以下功能:

# In the file 'fname',
# find the text matching "before oldtext after" (all occurrences) and
# replace 'oldtext' with 'newtext' (all occurrences).
# If 'mandatory' is true, raise an exception if no replacements were made.
def fileReplace(fname,before,newtext,after,mandatory=True):
    with open(fname, 'r+') as f:
    read_data = f.read()
    pattern = r"("+re.escape(before)+r")\w+("+re.escape(after)+r")"
    replacement = r"\1"+newtext+r"\2"
    new_data,replacements_made = re.subn(pattern,replacement,read_data,flags=re.MULTILINE)
    if replacements_made and really:
        f.seek(0)
        f.truncate()
        f.write(new_data)
        if verbose:
            print "patching ",fname," (",replacements_made," occurrence", "s" if 1!=replacements_made else "",")"
    elif replacements_made:
        print fname,":"
        print new_data
    elif mandatory:
        raise Exception("cannot patch the file: "+fname)
您可能会发现以下用途之一:

# Change the application resource package name everywhere in the src/ tree.
# Yes, this changes the java files. We hope that if something goes wrong,
# the version control will save us.
def patchResourcePackageNameInSrc(pname):
    for root, dirs, files in os.walk('src'):
    if '.svn' in dirs:
        dirs.remove('.svn')
    for fname in files:
        fileReplace(os.path.join(root,fname),"import com.xyz.",pname,".R;",mandatory=False)
还有一个函数可以将资产从
x-assets-cfgname
复制到
assets
(之前的结果表明,对于我来说,在
assets
中有一个子目录更方便)


好吧,你明白了。现在您可以编写自己的脚本了。

我认为最好的方法是创建一个新项目并复制内容。步骤, -创建没有类的新android项目 -创建包(包名应与清单文件中的包名相对应),或仅将包名复制到“gen”文件夹中 -复制java文件 -复制可绘制文件夹 -复制布局文件 -复制您的项目中使用的任何其他文件 -复制清单文件的数据

<
def copyAssets(vname,force=False):
    assets_source = "x-assets-"+vname+"/xxx"
    assets_target = "assets/xxx"
    if not os.path.exists(assets_source):
        raise Exception("Invalid variant name: "+vname+" (the assets directory "+assets_source+" does not exist)")
    if os.path.exists(assets_target+"/.svn"):
        raise Exception("The assets directory must not be under version control! "+assets_target+"/.svn exists!")
    if os.path.exists(assets_target):
        shutil.rmtree(assets_target)
    shutil.copytree(assets_source, assets_target, ignore=shutil.ignore_patterns('.svn'))