web-dev-qa-db-ja.com

Android –同じアプリの複数のカスタムバージョン

Androidアプリケーションのいくつかのカスタマイズされたバージョンをデプロイする最良の方法は何ですか?

現在、アプリのカスタマイズバージョンを取得するためにリソースフォルダーを交換するスクリプトがあります。これはうまく機能しますが、すべてのカスタムバージョンはAndroidManifest.xmlで同じパッケージ名を持っています。したがって、アプリの2つのカスタマイズされたバージョンを同時にインストールすることはできません。

これはこの問題の1つの解決策ですが、手動で行う必要があります

より簡単な解決策、またはこれをスクリプトに組み込む方法を考えられますか?

(ところで、それはポルノ/スパム/あらゆるアプリのためではなく、有料のもののためでもありません)

47
Ulrich Scheller

おそらく、組み込みのAndroid "library"の概念は、元の投稿の時点では完全には焼き付けられていませんでしたが、2011年の時点で推奨される方法である可能性があります。antビルドの場合は、次の手順に従ってください。

動作中のアプリ(ディレクトリ「myOrigApp」、パッケージcom.foo.myappと呼びます)から開始して、次の行を「default.properties」に追加してライブラリにします。

Android.library=true

次に、好きな方法で兄弟ディレクトリに新しいアプリを作成します(ディレクトリを「兄弟」と呼びましょう。パッケージ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のように、ライブラリプロジェクトをバリアントプロジェクトの依存プロジェクトとして設定する場合は、次の手順に従ってライブラリプロジェクトをバリアントプロジェクトに追加します(すでに両方に設定されたプロジェクト):

  • 元のプロジェクトを開き、プロジェクト設定を表示して、ファセットを選択し、「Is Library Project」にチェックを入れて保存します。
  • バリアントプロジェクトを開き、プロジェクト設定を呼び出し、モジュールを選択します。
  • モジュールを追加する
  • 「既存のモジュールをインポート」を選択します
  • 元のディレクトリ(myOrigApp)を参照し、その.imlファイル(IntelliJプロジェクトソースファイル)を選択します。
  • 「完了」をクリックします。 (ライブラリプロジェクトは、バリアントプロジェクト内のモジュールとして追加されます。)
  • モジュールリストで、Variantプロジェクトをクリックして選択します。
  • 右側で、[依存関係]タブを選択します。
  • 「追加…」をクリックします
  • [モジュールの依存関係...]を選択します(以前にプロジェクトに追加したモジュール/ライブラリの名前を含むリストが表示されます。おそらくリスト内の唯一のエントリです)。
  • 追加したライブラリプロジェクトを選択し、[OK]を押します。 (プロジェクトの依存関係のリストに追加されます。)
  • OKを押してプロジェクトの構成を終了します。 (ライブラリのリソースとクラスが利用可能で、Variantプロジェクトで認識されている2つのモジュールが表示されます。)
24
larham1

あなた間違いなく使用したい Gradle flavors ネイティブで、推奨されるAndroid Studio。

すべての基本を本当にうまく説明しているようです。今日Gradleへの変換を終了しました。カスタムアプリのアイコン、名前、文字列など.

ウェブサイトが説明しているように、この設計の背後にある目的の一部は、よりダイナミックで、基本的に同じコードで複数のAPKを簡単に作成できるようにすることでした。

私はおそらくそれを最もよく説明しなかったでしょう、しかしそのウェブサイトはかなり良い仕事をします。

6
craned

これに似たもののために私がしたことは、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>
6
Prashast

リンク先のソリューションは手動で行う必要はありません。マニフェスト内の他の場所に完全修飾クラス(たとえば、<manifest>ではなくactivity Android:name="com.commonsware.Android.MyActivity")を指定する限り、activity Android:name=".MyActivity"要素のpackage属性がコードが存在する場所である必要はないことに注意してください。マニフェストの変更をスクリプト化し、Antを使用して新しいAPKをビルドします。私の知る限り、それはうまくいくはずです。

4
CommonsWare

複数のパートナーをサポートする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" preparefiles

Build.xmlを作成します$ ant debugまたは$ ant releaseをビルドします

2
figofuture

私は maven-Android-pluginを使用 でこれを達成しています。 generated-sourcesゴール用に1つのAndroidManifest.xmlを指定し、最終的なapkゴール用に別のAndroidManifest.xmlを指定します。そうすることで、ソースクラスプロジェクトは、Rクラスの生成とビルドフェーズ中に実際のソースコードパッケージ名を保持しますが、市場に適合したマニフェストパッケージ名は、最終的なapkファイルに含まれる2番目のAndroidManifest.xmlにあります。

1
Fredrik Jonson

一番いい方法は、新しいプロジェクトを作成してコピーすることだと思います。手順、-新規作成Androidプロジェクト-パッケージを作成(パッケージ名はマニフェストファイル内のものに対応している必要があります)、またはパッケージ名を「gen」フォルダーにコピーします- Javaファイルをコピー-描画可能なフォルダをコピー-レイアウトファイルをコピー-プロジェクトで使用されている他のファイルをコピー-マニフェストファイルのデータをコピー

これは私にとってはタスクの方が簡単です

0
M. Usman Khan

ソースにパッチを当てるスクリプトを作成しました。ソースにパッチを当てることは危険に聞こえますが、バージョン管理が存在する場合、リスクは許容できます。

そのため、1つのバージョンを作成し、ソースをコミットし、もう1つのバージョンを作成し、ソースをコミットし、diffsを確認して、Pythonでパッチスクリプトを作成しました。

それが最善の解決策かどうかはわかりません。 (そしてコードはいくつかのos.path.joinsを見逃しています)

スクリプトの中心は次の関数です。

# 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にサブディレクトリがある方が便利でした)。

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

さて、あなたはアイデアを得ます。これで、独自のスクリプトを作成できます。