Android – 为不同的处理器架构build立单独的APK

有没有一种简单的方法来为Android为不同的处理器体系结构创build单独的APK文件,旧的ANT或新的Gradle构build过程? 我这样做的方法是构build一个包含所有支持的本机库的“胖”APK,然后将它们分解成单独的APK,如我在这里解释的 。 但是,似乎应该有一个更直接的方法来做到这一点…

Solutions Collecting From Web of "Android – 为不同的处理器架构build立单独的APK"

我决定在这里的其他地方重新发布我的答案 ,以便所有这些都在一个页面上,以方便访问。 如果这是违反SO政策,请告诉我,并从这里删除这篇文章。

这里是我的想法如何为每个支持的处理器体系结构创build单独的APK文件:

  1. 用您使用的任何工具构build一个“胖”APK,包含您支持的所有本地代码库,例如armeabi,armeabi-v7a,x86和mips。 我将其称为“原始”APK文件。

  2. 将您的原始APK解压缩到一个空的文件夹中,使用任何压缩/解压缩实用程序,最好使用命令行工具,以便稍后使用shell脚本或batch file自动执行。 其实,正如我在下面发布的示例批处理脚本所示,我只是使用命令行zip / unzip工具来直接操纵APK,而不是完全解压缩它们,但效果是一样的。

  3. 在原始APK解压缩到的文件夹中(或原始.apk / .zip中),删除META-INF子文件夹(包含签​​名,我们需要在所有修改后重新签名APK原始的META-INF必须被删除)。

  4. 更改为lib子文件夹,然后删除不需要的新处理器体系结构的子文件夹。 例如,只留下“x86”子文件夹来制作适用于英特尔凌动处理器的APK。

  5. 重要提示:不同体系结构的每个APK在AndroidManifest.xml文件中必须具有不同的“versionCode”编号,例如armeabi-v7a的版本代码必须略高于armeabi的版本代码(请参阅Google的创build多个APK的方向: http://developer.android.com/google/play/publishing/multiple-apks.html )。 不幸的是,清单文件在APK中是以编译的二进制forms存在的。 我们需要一个特殊的工具来修改versionCode。 见下文。

  6. 一旦清单被新版本代码修改,并删除不必要的目录和文件,重新压缩,签名和alignment您的小型APK(使用Android SDK中的jarsigner和zipalign工具)。

  7. 为所有需要支持的其他体系结构重复这个过程,使用稍微不同的版本代码(但版本名称相同)创build更小的APK文件。

唯一突出的问题是在二进制清单文件中修改“versionCode”的方法。 我很长一段时间找不到解决scheme,所以最后不得不坐下来,自己动手编写代码。 作为起点,我用Prasanta Paul编写了APKExtractor, http://code.google.com/p/apk-extractor/ ,用Java编写。 我是一所老学校,对C ++还是比较放心的,所以用C ++编写的小程序“aminc”现在在GitHub上:

https://github.com/gregko/aminc

我发布了整个Visual Studio 2012解决scheme,但整个程序是一个单一的.cpp文件,可能可以在任何平台上编译。 下面是一个示例Windows批处理脚本文件,我用它将名为atVoice.apk的“fat”apk分成4个小文件,分别命名为atVoice_armeabi.apk,atVoice_armeabi-v7a.apk,atVoice_x86.apk和atVoice_mips.apk。 实际上,我将这些文件提交给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开发者控制台收到一些错误报告,指出找不到本机方法。 这很可能是由于用户在ARM设备上安装了错误的APK,例如Intel或MIPS APK造成的。 添加额外的代码到我的应用程序,检查VersionCode编号对Build.CPU_ABI,然后显示错误消息,如果不匹配,要求用户重新安装从谷歌播放(或我自己的网站,我张贴“胖”APK )在这种情况下。

格雷格

在本文中Android NDK:每个架构发布APK的版本代码scheme我已经find了一个很好的解决这个问题的方法。 它包括添加下面的代码

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

到build.gradle脚本的android{...}部分。 如果你想了解细节,我强烈推荐阅读那篇文章,这真的值得一读。

从Android NDK开始, 使用ANT脚本构build ,只需要很less的更改:

 <target name="-pre-build"> <exec executable="${ndk.dir}/ndk-build" failonerror="true"/> <arg value="APP_ABI=${abi}"/> </target> 

并使用batch file来运行循环(我使用一个简单的sed脚本; sed在%NDK_ROOT%\prebuilt\windows\bin\和所有其他平台上可用):

 sed -i -e "s/versionCode=\"\([0-9]*\).]\"/versionCode=\"\11\"/" AndroidManifest.xml ant -Dsdk.dir=%SDK_ROOT% -Dndk.dir=%NDK_ROOT% -Dabi=armeabi release ren %apkfile%.apk %apkfile%_armeabi.apk sed -i -e "s/versionCode=\"\([0-9]*\).\"/versionCode=\"\12\"/" AndroidManifest.xml ant -Dsdk.dir=%SDK_ROOT% -Dndk.dir=%NDK_ROOT% -Dabi=mips release ren %apkfile%.apk %apkfile%_mips.apk sed -i -e "s/versionCode=\"\([0-9]*\).\"/versionCode=\"\13\"/" AndroidManifest.xml ant -Dsdk.dir=%SDK_ROOT% -Dndk.dir=%NDK_ROOT% -Dabi=armeabi-v7a release ren %apkfile%.apk %apkfile%_armeabi-v7a.apk sed -i -e "s/versionCode=\"\([0-9]*\).\"/versionCode=\"\14\"/" AndroidManifest.xml ant -Dsdk.dir=%SDK_ROOT% -Dndk.dir=%NDK_ROOT% -Dabi=x86 release ren %apkfile%.apk %apkfile%_x86.apk 

这假定清单文件中的android.verisonCode的最后一位数字为零,例如android:versionCode="40260"

请注意,技术上没有理由为armeabimips变体更改versionCode,但保留armeabi <armeabi-v7a <x86可能很重要。

更新感谢Ashwin S Ashok提出了一个更好的编号scheme: VERSION+10000*CPU

一个非常简单的方法是使用像Intel XDK这样的跨平台框架。

它有能力build立适用于所有版本的Android(2.3 +),iOS,Windows Phone 8,Tizen,Google Chrome和Mozilla Firefox的应用程序。

一个源代码将为你做魔术。