I have Android app which builds armeabi-v7a and arm64-v8a. Here is the build.gradle:
apply plugin: 'com.android.library'
allprojects {
repositories {
jcenter()
google()
}
}
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
// Linker flags and Visibility options keeps the size of the library small
cppFlags "-std=c++11"
arguments "-DANDROID_STL=gnustl_static",
"-DANDROID_CPP_FEATURES=rtti exceptions",
"-DANDROID_TOOLCHAIN=gcc"
}
}
}
buildTypes {
release {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
externalNativeBuild {
cmake {
cppFlags "-Wl,--exclude-libs=ALL -Wl,--gc-sections -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections"
}
}
}
debug {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
I am using the minSdkVersion = 21 to support arm64. I would like to change the minSdkVersion based on the abiFilters i.e., use 16 for v7 and use 21 for arm64.
You don't need to do anything mentioned in the selected answer. Just set minSdkVersion 16 and the 64-bit ABIs will automatically use minSdkVersion 21 because that's the lowest available API for 64-bit.
For how the minSdkVersion property works, see below quotes from official documentation:
If there exists a platform version for the ABI equal to minSdkVersion, CMake uses that version.
Otherwise,
if there exists platform versions lower than minSdkVersion for the ABI, CMake uses the highest of those platform versions. This is a reasonable choice because a missing platform version typically means that there were no changes to the native platform APIs since the previous available version.
Otherwise, CMake uses the next available platform version higher than minSdkVersion.
And it has ever been mentioned in may answer to your another question: Android Studio CMake/Ninja Not Used for Building an NDK project.
I am using the minSdkVersion = 21 to support arm64. I would like to change the minSdkVersion based on the abiFilters i.e., use 16 for v7 and use 21 for arm64.
My understanding is that you are trying to support older (api level lower than 21) 32-bit devices without 64-bit native binaries. I would like to say "productFlavor" is the right direction to go. E.g. you can have your gradle configuration like below to achieve what you expect:
android {
...
flavorDimensions "api", "mode"
productFlavors {
minApi16 {
dimension "api"
minSdkVersion 16
versionCode android.defaultConfig.versionCode
versionNameSuffix "-minApi16"
ndk {
abiFilters 'armeabi-v7a'
}
}
minApi21 {
dimension "api"
minSdkVersion 21
versionCode android.defaultConfig.versionCode
versionNameSuffix "-minApi21"
ndk {
abiFilters 'arm64-v8a'
}
}
}
...
}
The minSdkVersion 16 and minSdkVersion 21 will help you choose the best suitable NDK version.
Edit #1
How to choose different minSdkVersion for different android ABI?
minSdkVersion is the property telling the minimum Android version that your app can install on. For one single APK, this is an unconditional characteristic. So:
If you want to have one single APK to support all the devices starting from api 16, then you have to set your minSdkVersion to 16.
If you want to have one single APK to support both 32-bit devices and 64-bit devices, you have to provide a complete set of ALL the shared libraries both 32-bit and 64-bit.
Or else, you have to provide different APKs split by ABIs and minSdkVersion.
Related
The following APKs or App Bundles are available to 64-bit devices, but they only have 32-bit native code: 5.
Includes 64-bit and 32-bit native code in your app.
Use the Android App Bundle publishing format to automatically ensure that each device architecture receives only the native code that it needs. This avoids increasing the overall size of your app. Learn More
My Gradle:
defaultConfig {
applicationId "com.all.effect.photo.editor"
minSdkVersion 16
targetSdkVersion 29
versionCode 6
versionName "1.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
}
How can I build an apk which is compatible with both 64 bit and 32 bit architectures?
ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
change to
ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86_64'
need to remove x86 from ndk filters and my problem is solved now.
defaultConfig {
...
ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86_64'
...
}
Please make sure this settings should be included in the defaultConfig. If there are external framework/library, then ALSO add in cmake
I am using NDK libraries in my app, these are the settings in my gradle file.
defaultConfig {
applicationId 'com.aa.aa'
minSdkVersion 21
targetSdkVersion 27
versionCode 1
versionName "1.0.0"
multiDexEnabled true
resConfigs "en"
ndk {
abiFilters 'armeabi-v7a','x86'
}
}
But now if i upload my apk on play store, it give me error message that, my app is cont complaint with 64-bit architecture.
Now if i add arm64-v8a, i am able to upload the build on playstore.
defaultConfig {
applicationId 'com.aa.aa'
minSdkVersion 21
targetSdkVersion 27
versionCode 1
versionName "1.0.0"
multiDexEnabled true
resConfigs "en"
ndk {
abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
}
}
My questions is that is that is it necessary to add arm64-v8a in build.gradle file when using NDK libraries.
If taken literally, your question can be answered "No". If you remove the whole abiFilters line from build.gradle, your app will be built for 64-bit as well.
To have native 64-bit compatibility is a Play Store requirement, and for app updates it is being enforced since August 2019. If you use other mechanisms to deliver your app, arm64-v8a is not necessary.
According to the new Play Store policy * that will take effect in August * I need to ensure that my app provides not only the 32-bit version, but also a 64-bit version, but when I try to generate that version through NDK, I always get the same libs. After trying and trying and trying, I just received an apk without any kind of "lib" folder.
I've tried to set NDK with abiFilters on gradle and got no changes...
defaultConfig {
applicationId "com.myproject.supermidia"
minSdkVersion 17
targetSdkVersion 26
versionCode 20192201
versionName "2.4"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
}
In order to build for ARM (and the x86 emulator), the splits should look alike this. x86_64 might be a little useless, because the x86_64 emulator is slow and there is no hardware I'd be aware of ...
android {
defaultConfig {
...
externalNativeBuild {
cmake {
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_CPP_FEATURES=rtti exceptions"
}
}
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
}
}
splits {
abi {
enable true
reset()
include "armeabi-v7a", "arm64-v8a", "x86"
universalApk true
}
}
}
The project i am working on has around 180k Methods. I have read blogs, and articles where its written that if you set your Min SDK to 21, then you don't need MultiDex. But if i remove MultiDex from here it gives me the 65k MultiDex error message. Following is my gradle file. I don't know whether i failed to understand the concept or something else. Kindly guide me.
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId 'com.myapp.app'
minSdkVersion 21
targetSdkVersion 23
versionCode 59
versionName "1.0.1"
multiDexEnabled true
ndk {
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
dexOptions {
javaMaxHeapSize "4g" //specify the heap size for the dex process
}
lintOptions {
abortOnError false
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
if you set your Min SDK to 21, then you don't need MultiDex
As per the "Multidex support for Android 5.0 and higher" instructions in the MultiDex guide, even if you minSdk 21 then you still need compile with multiDexEnabled true. What you don't need to do is include the MultiDex support library via:
compile 'com.android.support:multidex:1.0.0'
or call MultiDex.install(Context) in your Application class.
The 64K method problem is a limitation of the DEX file format and not of the Android Platform itself. The difference between the two versions is that Android 5.0+ knows how to automatically load multiple DEX files into a single OAT file and load classes from it while Android versions prior to 5.0 require the support library in order to load classes from secondary DEX files (e.g. classes2.dex, classes3.dex, etc).
In the past I used eclipse for NDK projects, the Android.mk file was perfectly suited for compiling the NDK with API level 9 while letting the app (SDK) compile on API level 22. But it seems that this is not possible when using the experimental Gradle build system (2.5) with Android Studio 1.3 RC1.
What can I do to compile ONLY the NDK on API level 9?
My typical Android.mk file looks like this:
APP_PLATFORM := android-9
APP_STL := stlport_static
APP_ABI := all
# Enable c++11 extentions in source code
APP_CPPFLAGS += -std=c++11
#Enable optimalization in release mode
APP_OPTIM := release
My new gradle file looks like this:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 22
buildToolsVersion = "23.0.0 rc3"
defaultConfig.with {
applicationId = "com.example"
minSdkVersion.apiLevel = 9
targetSdkVersion.apiLevel = 22
versionCode = 1
versionName = "1.0"
}
}
android.ndk {
moduleName = "NativeLibrary"
cppFlags += "-I${file("src/main/jni/some_folder")}".toString()
cppFlags += "-std=c++11"
//What should be added here to compile the NDK on API 9???
CFlags += "-DNDEBUG"
CFlags += "-fvisibility=hidden"
cppFlags += "-fvisibility=hidden"
ldLibs += ["log"]
stl = "stlport_static"
}
android.buildTypes {
release {
isMinifyEnabled = true
proguardFiles += file('D:/path/proguard-rules.pro')
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-v4:22.2.0'
}
I investigated the Gradle source and it seems that the NDK build target is hard-coded the same as the compileSdkVersion. Is there an method to avoid or alter this behavior?
NdkCompile.groovy (make file creation)
// target
IAndroidTarget target = getPlugin().loadedSdkParser.target
if (!target.isPlatform()) {
target = target.parent
}
commands.add("APP_PLATFORM=" + target.hashString())
Sdk.groovy (target is fetched form the compileSdkVersion)
public SdkParser loadParser() {
checkNotNull(extension, "Extension has not been set")
// call getParser to ensure it's created.
SdkParser theParser = getParser()
if (!isSdkParserInitialized) {
String target = extension.getCompileSdkVersion()
if (target == null) {
throw new IllegalArgumentException("android.compileSdkVersion is missing!")
}
FullRevision buildToolsRevision = extension.buildToolsRevision
if (buildToolsRevision == null) {
throw new IllegalArgumentException("android.buildToolsVersion is missing!")
}
theParser.initParser(target, buildToolsRevision, logger)
isSdkParserInitialized = true
}
return theParser
}
If you are using the experimental plugin version 0.4. you can set
android.ndk {
platformVersion = "19"
}
Ok, this is a terrible hack, but it is very easy. Find the NDK, it should be in android-sdk/ndk-bundle. Go into the platforms folder. Rename android-21 to something else. Make a copy of android-19, and then copy the three 64-bit folders from android-21 into it, then rename it android-21. Gradle will THINK it's using android-21, and it will for 64-bit targets, but for 32-bit targets it will use android 19.
I'm not 100% sure this is safe, but I tested it on a few devices and I've got an app in Beta Test right now. I think it's cleaner than making gradle tasks for ndk-build. Whenever Google fixes experimental gradle, nothing needs to change other than to reinstall the ndk.
model {
android {
compileSdkVersion = 22
buildToolsVersion '20'
defaultConfig.with {
applicationId = "com.example"
minSdkVersion.apiLevel = 9
targetSdkVersion.apiLevel = 22
versionCode = 1
versionName = "1.0"
}
}
gradle version is 3.1.2
defaultConfig {
applicationId "com.xxx.player"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters 'armeabi-v7a'
arguments "-DANDROID_PLATFORM=android-21" //config ANDROID_PLATFORM version on here
}
}
}