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

gre*_*gko 11 android native build android-ndk apk

有没有一种简单的方法可以为不同的处理器架构为Android构建单独的APK文件,使用旧的ANT或新的Gradle构建过程?我这样做的方法是构建一个包含所有支持的本机库的"胖"APK,然后将它们拆分为单独的APK,如我在此处解释的那样.然而,似乎应该有一个更直接的方法来做到这一点......

gre*_*gko 6

我决定这里的其他地方重新发布我的答案,以便所有这些都放在一页上以便于访问。如果这违反了SO政策,请告诉我并从此处删除此信息。

这是我关于如何为每种受支持的处理器体系结构创建单独的APK文件的想法:

  1. 使用您使用的任何工具构建一个“胖” APK,其中包含您支持的所有本机代码库,例如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”子文件夹即可为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的APKExtractor,http://code.google.com/p/apk-extractor/。我是老派,对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
Run Code Online (Sandbox Code Playgroud)

附加保障

我在Google Play开发者控制台收到一些错误报告,指出找不到本机方法。这很可能是由于用户在ARM设备上安装了错误的APK(例如Intel或MIPS APK)引起的。向我的应用添加了额外的代码,对照Build.CPU_ABI检查VersionCode编号,然后在不匹配的情况下显示错误消息,要求用户从Google Play(或我自己的网站上重新安装,我在该网站上发布“胖” APK) )。

格雷格


And*_*rew 5

在这篇文章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
    }
}
Run Code Online (Sandbox Code Playgroud)

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