Android - 为不同的处理器架构构建单独的 APK

标签 android build android-ndk apk native

是否有一种简单的方法可以使用旧的 ANT 或新的 Gradle 构建过程为不同的处理器架构为 Android 构建单独的 APK 文件?我这样做的方法是构建一个包含所有受支持的 native 库的“胖”APK,然后将它们拆分为单独的 APK,如我 explained here .不过,似乎应该有更直接的方法来做到这一点……

最佳答案

我决定重新发布我的 answer from elsewhere在这里,所有这些都在一个页面上,以便于访问。如果这违反了 SO 政策,请告诉我并从此处删除此帖子。

以下是我对如何为每个支持的处理器架构创建单独的 APK 文件的想法:

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

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

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

  4. 更改为 lib 子文件夹,并删除新 APK 文件中不需要的任何处理器架构的子文件夹。例如,只保留“x86”子文件夹来为英特尔凌动处理器制作 APK。

  5. 重要提示:针对不同架构的每个 APK,在 AndroidManifest.xml 中必须有不同的 'versionCode' 编号,以及例如版本号。 armeabi-v7a 必须比 armeabi 略高(请阅读 Google 在此处创建多个 APK 的说明:http://developer.android.com/google/play/publishing/multiple-apks.html)。不幸的是, list 文件在 APK 中是编译后的二进制形式。我们需要一个特殊的工具来修改那里的 versionCode。见下文。

  6. 使用新版本代码修改 list 并删除不必要的目录和文件后,重新压缩、签名并对齐较小的 APK(使用 Android SDK 中的 jarsigner 和 zipalign 工具)。

  7. 对您需要支持的所有其他架构重复该过程,创建版本代码略有不同(但版本名称相同)的较小 APK 文件。

唯一突出的问题是在二进制 list 文件中修改“versionCode”的方式。很长一段时间我都找不到解决方案,所以最后不得不坐下来编写自己的代码来做到这一点。作为起点,我使用了 Prasanta Paul 的 APKExtractor,http://code.google.com/p/apk-extractor/ ,用Java编写。我是老派,更喜欢 C++,所以我用 C++ 编写的小实用程序“aminc”现在在 GitHub 上:

https://github.com/gregko/aminc

我在那里发布了整个 Visual Studio 2012 解决方案,但整个程序是一个 .cpp 文件,可能可以在任何平台上编译。这是一个示例 Windows 批处理脚本文件,我使用它将名为 atVoice.apk 的“胖”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 开发者控制台收到一些错误报告,指出找不到 native 方法。这很可能是由于用户安装了错误的 APK,例如ARM 设备上的 Intel 或 MIPS APK。向我的应用程序添加了额外的代码,对照 Build.CPU_ABI 检查 VersionCode 编号,然后在不匹配的情况下显示错误消息,要求用户从 Google Play(或我自己的网站,我在其中发布“胖”APK)重新安装) 在这种情况下。

格雷格

关于Android - 为不同的处理器架构构建单独的 APK,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19954156/

相关文章:

android - android :versionName have to be numeric (of the form 0. 0.0 等)?

android - PID : 15208 java. lang.UnsatisfiedLinkError : dalvik. system.PathClassLoader

android - 我可以在 Android 中用匹配的组进行正则表达式替换吗?

java - 进度条增量

由于 shrinkReleaseMultiDexComponents,Android 版本构建失败

android - 为 Android 构建 bspatch

java - 显示或隐藏 fragment 菜单

java - 错误:In <declare-styleable> ForegroundView,无法找到属性前景

node.js - 通过 npm run 为 Reactjs 项目运行构建命令时出错

android - 一个或多个插件需要更高的 Android SDK 版本