Есть ли простой способ создать отдельные файлы APK для Android для разных архитектур процессоров с помощью старого ANT или нового процесса сборки Gradle? Мой способ сделать это - создать один «толстый» APK со всеми поддерживаемыми встроенными библиотеками, а затем разделить их на отдельные APK, как я объяснил здесь. Однако кажется, что должен быть более прямой способ сделать это ...
Android - создавайте отдельные APK для разных архитектур процессоров
Ответы (3)
Я решил повторно опубликовать свой ответ из другого места здесь, чтобы все это было на одной странице для облегчения доступа. Если это противоречит политике SO, сообщите мне и удалите этот пост отсюда.
Вот моя идея о том, как создавать отдельные файлы APK для каждой поддерживаемой архитектуры процессора:
Создайте один «толстый» APK с любыми используемыми вами инструментами, содержащими все библиотеки собственного кода, которые вы поддерживаете, например armeabi, armeabi-v7a, x86 и mips. Я назову его «оригинальным» файлом APK.
Разархивируйте исходный APK в пустую папку с помощью любой утилиты zip / unzip, лучше всего используйте инструменты командной строки, чтобы вы могли автоматизировать его позже с помощью сценария оболочки или пакетного файла. На самом деле, как показывает мой пример пакетного скрипта, опубликованный ниже, я просто использую инструменты командной строки для zip / unzip для непосредственного управления APK-файлами, вместо того, чтобы полностью распаковывать их, но эффект тот же.
В папке, в которую был распакован исходный APK (или в исходном .apk / .zip), удалите подпапку META-INF (она содержит подписи, нам нужно будет повторно подписать APK после всех изменений, поэтому исходный META-INF должен быть удален).
Перейдите в подпапку lib и удалите подпапки для любых архитектур процессоров, которые вам не нужны в новом файле APK. Например, оставьте только подпапку «x86» для создания APK для процессоров Intel Atom.
Важно: каждый APK для другой архитектуры должен иметь другой номер versionCode в AndroidManifest.xml и код версии, например, armeabi-v7a должен быть немного выше, чем armeabi (см. инструкции Google по созданию нескольких APK здесь: http://developer.android.com/google/play/publishing/multiple-apks.html). К сожалению, файл манифеста находится в скомпилированном двоичном виде внутри APK. Нам понадобится специальный инструмент для изменения versionCode там. См. ниже.
После того, как манифест изменен с использованием кода новой версии и ненужные каталоги и файлы удалены, повторно заархивируйте, подпишите и выровняйте меньший APK (используйте инструменты jarsigner и zipalign из Android SDK).
Повторите процесс для всех других архитектур, которые вам необходимо поддерживать, создав файлы APK меньшего размера с немного разными кодами версий (но с тем же именем версии).
Единственная нерешенная проблема - это способ изменить "versionCode" в двоичном файле манифеста. Я долго не мог найти решение для этого, поэтому, наконец, пришлось сесть и провернуть свой собственный код, чтобы сделать это. В качестве отправной точки я взял APKExtractor от Прасанты Пола, http://code.google.com/p/apk-extractor/, написанный на Java. Я представитель старой школы, и мне еще удобнее работать с C ++, поэтому моя небольшая служебная программа aminc, написанная на C ++, теперь находится на GitHub по адресу:
https://github.com/gregko/aminc
Я разместил там все решение Visual Studio 2012, но вся программа представляет собой единый файл .cpp, который, вероятно, можно скомпилировать на любой платформе. А вот пример файла пакетного сценария Windows, который я использую для разделения моего «толстого» apk с именем atVoice.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, в которых говорится, что не удалось найти собственный метод. Скорее всего, это вызвано тем, что пользователь установил неправильный APK, например Intel или MIPS APK на устройстве ARM. В мое приложение добавлен дополнительный код, проверяющий номер VersionCode на Build.CPU_ABI, затем отображающий сообщение об ошибке в случае несоответствия с просьбой к пользователю переустановить из Google Play (или моего собственного веб-сайта, где я публикую "толстый" APK ) в таком случае.
Грег
В этой статье 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. Если вы хотите разобраться в деталях, настоятельно рекомендую прочитать эту статью, ее действительно стоит прочитать.
Начните с сборки Android NDK с помощью сценария ANT с минимальными изменениями:
<target name="-pre-build">
<exec executable="${ndk.dir}/ndk-build" failonerror="true"/>
<arg value="APP_ABI=${abi}"/>
</target>
и используйте командный файл для запуска цикла (я использую простой 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"
.
Обратите внимание, что технически нет причин изменять versionCode для вариантов armeabi и mips, но может быть важно сохранить armeabi ‹armeabi-v7a‹ x86 strong >.
Обновление Благодарим Эшвина С. Ашока за предложение еще лучшей схемы нумерации: VERSION+10000*CPU
.
APP_ABI
за раз, вы создаете один и тот же код для каждой инструментальной цепочки отдельно. Но вы определенно ничего не получите, если соберете APP_ABI=all
- тот же цикл происходит внутри ndk_build.
- person Alex Cohn; 19.11.2013