11

古い ANT または新しい Gradle ビルド プロセスを使用して、異なるプロセッサ アーキテクチャ用に Android 用の個別の APK ファイルをビルドする簡単な方法はありますか? これを行う私の方法は、サポートされているすべてのネイティブ ライブラリを含む 1 つの「ファット」APK をビルドし、ここで説明したようにそれらを個別の APK に分割することです。ただし、これを行うためのより直接的な方法があるはずです...

4

3 に答える 3

6

ここの他の場所から回答を再投稿することにしました。これにより、これらすべてが 1 つのページにまとめられ、簡単にアクセスできるようになります。これが SO ポリシーに違反している場合は、私に知らせて、この投稿をここから削除してください。

サポートされているプロセッサ アーキテクチャごとに個別の APK ファイルを作成する方法についての私の考えは次のとおりです。

  1. サポートするすべてのネイティブ コード ライブラリ (armeabi、armeabi-v7a、x86、mips など) を含む、使用するツールを使用して 1 つの「ファット」APK をビルドします。これを「元の」APK ファイルと呼びます。

  2. 任意の zip/unzip ユーティリティを使用して、元の APK を空のフォルダーに解凍します。後でシェル スクリプトまたはバッチ ファイルを使用して自動化できるように、コマンド ライン ツールを最適に使用します。実際、以下に掲載したサンプル バッチ スクリプトが示すように、APK を完全に解凍するのではなく、コマンド ラインの zip/unzip ツールを使用して APK を直接操作していますが、効果は同じです。

  3. 元の APK が解凍されたフォルダー (または元の .apk/.zip) で、META-INF サブフォルダーを削除します (これには署名が含まれています。すべての変更後に APK に再署名する必要があるため、元の META-INF は削除する必要があります)。

  4. lib サブフォルダーに変更し、新しい APK ファイルで不要なプロセッサ アーキテクチャのサブフォルダーを削除します。たとえば、「x86」サブフォルダーのみを残して、Intel Atom プロセッサー用の APK を作成します。

  5. 重要: 異なるアーキテクチャの各 APK は、AndroidManifest.xml で異なる「versionCode」番号を持つ必要があります。たとえば、armeabi-v7a のバージョン コードは、armeabi のバージョン コードよりもわずかに高くする必要があります (複数の APK を作成するための Google の指示をここで読んでください: http://developer.android.com/google/play/publishing/multiple-apks.html )。残念ながら、マニフェスト ファイルは APK 内でコンパイルされたバイナリ形式になっています。そこで versionCode を変更するための特別なツールが必要です。下記参照。

  6. マニフェストが新しいバージョン コードで変更され、不要なディレクトリとファイルが削除されたら、小さい APK を再圧縮し、署名して調整します (Android SDK の jarsigner ツールと zipalign ツールを使用します)。

  7. サポートする必要がある他のすべてのアーキテクチャについてこのプロセスを繰り返し、バージョン コードがわずかに異なる (ただしバージョン名は同じ) 小さい APK ファイルを作成します。

唯一の未解決の問題は、バイナリ マニフェスト ファイルで「versionCode」を変更する方法です。私は長い間これに対する解決策を見つけることができなかったので、ついに腰を下ろして自分のコードをクランキングしてこれを行う必要がありました。出発点として、Java で記述された Prasanta Paul によるhttp://code.google.com/p/apk-extractor/のAPKExtractor を使用しました。私はオールドスクールで、C++ に慣れているので、C++ で書かれた私の小さなユーティリティ プログラム 'aminc' は、GitHub の次の場所にあります。

https://github.com/gregko/ainc

そこに Visual Studio 2012 ソリューション全体を投稿しましたが、プログラム全体が単一の .cpp ファイルであり、おそらくどのプラットフォームでもコンパイルできます。そして、これは私が atVoice.apk という名前の「太った」apk を atVoice_armeabi.apk、atVoice_armeabi-v7a.apk、atVoice_x86.apk、atVoice_mips.apk という名前の 4 つの小さなファイルに分割するために使用する Windows バッチ スクリプト ファイルのサンプルです。私は実際にこれらのファイルを Google Play に送信し ( https://play.google.com/store/apps/details?id=com.hyperionics.avarで私のアプリを参照)、すべてが完全に機能します。

@echo off
REM    My "fat" apk is named atVoice.apk. Change below to whatever or set from %1
set apkfile=atVoice
del *.apk

REM    My tools build atVoice-release.apk in bin project sub-dir. 
REM    Copy it herefor splitting.
copy ..\bin\%apkfile%-release.apk %apkfile%.apk

zip -d %apkfile%.apk META-INF/*

REM ------------------- armeabi ------------------------
unzip %apkfile%.apk AndroidManifest.xml
copy/y %apkfile%.apk %apkfile%.zip
zip -d %apkfile%.zip lib/armeabi-v7a/* lib/x86/* lib/mips/*
aminc AndroidManifest.xml 1
zip -f %apkfile%.zip
ren %apkfile%.zip %apkfile%_armeabi.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.android\Hyperionics.keystore -storepass MyPass %apkfile%_armeabi.apk MyKeyName
zipalign 4 %apkfile%_armeabi.apk %apkfile%_armeabi-aligned.apk
del %apkfile%_armeabi.apk
ren %apkfile%_armeabi-aligned.apk %apkfile%_armeabi.apk

REM ------------------- armeabi-v7a ---------------------
copy/y %apkfile%.apk %apkfile%.zip
zip -d %apkfile%.zip lib/armeabi/* lib/x86/* lib/mips/*
aminc AndroidManifest.xml 1
zip -f %apkfile%.zip
ren %apkfile%.zip %apkfile%_armeabi-v7a.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.android\Hyperionics.keystore -storepass MyPass %apkfile%_armeabi-v7a.apk MyKeyName
zipalign 4 %apkfile%_armeabi-v7a.apk %apkfile%_armeabi-v7a-aligned.apk
del %apkfile%_armeabi-v7a.apk
ren %apkfile%_armeabi-v7a-aligned.apk %apkfile%_armeabi-v7a.apk

REM ------------------- x86 ---------------------
copy/y %apkfile%.apk %apkfile%.zip
zip -d %apkfile%.zip lib/armeabi/* lib/armeabi-v7a/* lib/mips/*
aminc AndroidManifest.xml 9
zip -f %apkfile%.zip
ren %apkfile%.zip %apkfile%_x86.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.android\Hyperionics.keystore -storepass MyPass %apkfile%_x86.apk MyKeyName
zipalign 4 %apkfile%_x86.apk %apkfile%_x86-aligned.apk
del %apkfile%_x86.apk
ren %apkfile%_x86-aligned.apk %apkfile%_x86.apk

REM ------------------- MIPS ---------------------
copy/y %apkfile%.apk %apkfile%.zip
zip -d %apkfile%.zip lib/armeabi/* lib/armeabi-v7a/* lib/x86/*
aminc AndroidManifest.xml 10
zip -f %apkfile%.zip
ren %apkfile%.zip %apkfile%_mips.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:\users\greg\.android\Hyperionics.keystore -storepass MyPass %apkfile%_mips.apk MyKeyName
zipalign 4 %apkfile%_mips.apk %apkfile%_mips-aligned.apk
del %apkfile%_mips.apk
ren %apkfile%_mips-aligned.apk %apkfile%_mips.apk


del AndroidManifest.xml
del %apkfile%.apk
:done

追加の保護手段

Google Play デベロッパー コンソールで、ネイティブ メソッドが見つからないというエラー レポートがいくつか表示されます。ほとんどの場合、これはユーザーが誤った APK (Intel または MIPS APK など) を ARM デバイスにインストールしたことが原因です。アプリに余分なコードを追加し、Build.CPU_ABI に対して VersionCode 番号をチェックし、不一致の場合はエラー メッセージを表示して、ユーザーに Google Play (または「太い」APK を投稿する自分の Web サイト) から再インストールするように求めました。 ) このような場合には。

グレッグ

于 2013-11-14T13:14:53.920 に答える
6

この記事Android NDK: アーキテクチャごとに APK を公開するためのバージョン コード スキーム で、この問題に対する優れた解決策を見つけました。次のコードを追加することで構成されます

 splits {
    abi {
        enable true
        reset()
        include 'x86', 'armeabi', 'armeabi-v7a'
        universalApk true
    }
}

project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]

android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        output.versionCodeOverride =
            project.ext.versionCodes.get(output.getFilter(
                com.android.build.OutputFile.ABI), 0) * 10000000 + android.defaultConfig.versionCode
    }
}

android{...}build.gradle スクリプトのセクションに。詳細を理解したい場合は、その記事を読むことを強くお勧めします。読む価値があります。

于 2016-10-12T12:40:52.147 に答える