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
}
}
}
Related
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.
My Android studio is version 3.3.2 and i trying to link gradle to my native library, my module's build.gradle is:
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 18
targetSdkVersion 28
versionCode 1
versionName "1.0"
ndk {
moduleName "MyModule"
abiFilters 'x86', 'armeabi-v7a'
}
}
externalNativeBuild {
cmake {
version "3.10.2" // The key line
path file('CMakeLists.txt')
}
}
}
If i don't specify the cmake version to '3.10.2', I am getting the following error:
CMake '3.6.0' was not found in PATH or by cmake.dir property.
- CMake '3.10.2' found in SDK did not match requested version '3.6.0'.
- CMake '3.12.1' found in PATH did not match requested version '3.6.0'.
Install CMake 3.6.0
So I'am confused why is so! Why does it ask for the version of cmake itself to be 3.6.0.
Kindly review and give feedback.
Try to add the configuration below to your gradle:
externalNativeBuild {
cmake {
version "3.10.2" // here
}
}
I am trying to make use of the "Multiple NDK Projects" feature of the experimental gradle plugin. I am using Android Studio 2.1 and gradle plugin 0.7.0 stable. The blog seems to say that the header files specified in the exportedHeaders section of the native library will be included during compilation
exportedHeaders {
srcDir "src"
}
This does not seem to work for me. Say for example I have the following folder structure, I would expect Addition.h to be available in native.cpp, ie I should be able to say
#include <Addition.h>
but only
#include "../../../../../../../Framework/Addition/src/Addition.h"
works. Adding cppFlags to include the headers makes no difference.
Here's how some relevant files look for an example project. The example project module "app" depends on a native library module "addition" to add 2 numbers. The native library uses the new native plugin.
settings.gradle
include ':app'
include ':Addition'
project (":Addition").projectDir = new File("../../../Framework/Addition")
gradle-wrapper.properties
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
build.gradle (:app)
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
ndk {
moduleName = 'native'
platformVersion = 17
toolchain "clang"
cppFlags.addAll(['-I' + file('src/main/jni'),
'-I' + file('../../../Framework/Addition')])
}
sources {
main {
jni {
dependencies {
project ':Addition' linkage 'static'
}
}
}
}
defaultConfig {
applicationId "com.harkish.nativepluginexample"
minSdkVersion.apiLevel 21
targetSdkVersion.apiLevel 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
}
build.gradle (:Addition)
apply plugin: 'com.android.model.native'
model {
android {
compileSdkVersion = 23
buildToolsVersion = '23.0.2'
defaultConfig {
minSdkVersion.apiLevel = 21
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = '1.0'
}
ndk {
moduleName = 'addition'
}
sources {
main {
jni {
source {
srcDir "src"
}
exportedHeaders {
srcDir "src"
}
}
}
}
}
}
Anyone solved this problem? ideas?
I am using android studio and openning the hello-jni sample project.
However when I trying to compile the project,it prompts:
Error:Cause: failed to find target with hash string 'android-23' in:
/Users/xx/opensource/android-sdk-macosx
Open Android SDK Manager
I had installed the android 6.0 (api 23).Why still prompts failed to find?
I looked up in the preference in android stuido ,in android SDK tab it seems android 6.0 (api level 23 revision 1) can be found.
Belows is my gradle file:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.0"
defaultConfig.with {
applicationId = "com.example.hellojni"
minSdkVersion.apiLevel = 3
targetSdkVersion.apiLevel = 23
}
}
/*
* native build settings
*/
android.ndk {
moduleName = "hello-jni"
/*
* Other ndk flags configurable here are
* cppFlags += "-fno-rtti"
* cppFlags += "-fno-exceptions"
* ldLibs = ["android", "log"]
* stl = "system"
*/
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.txt')
}
}
android.productFlavors {
// for detailed abiFilter descriptions, refer to "Supported ABIs" #
// https://developer.android.com/ndk/guides/abis.html#sa
create("arm") {
ndk.abiFilters += "armeabi"
}
create("arm7") {
ndk.abiFilters += "armeabi-v7a"
}
create("arm8") {
ndk.abiFilters += "arm64-v8a"
}
create("x86") {
ndk.abiFilters += "x86"
}
create("x86-64") {
ndk.abiFilters += "x86_64"
}
create("mips") {
ndk.abiFilters += "mips"
}
create("mips-64") {
ndk.abiFilters += "mips64"
}
// To include all cpu architectures, leaves abiFilters empty
create("all")
}
}
This worked for me:
I removed the application I was working on in home directory under AndroidStudioProjects
Restarted Android Studio
It prompt the Android Studio Wizard, I went through the Android
Studio Setup Wizard where it downloaded some SDK Build-tools for
revision 23.0.1.
I also clicked on update link when the "Platform and Plugin Updates" message show up while downloading Android SDK Build-tools, to update
some components.
"Welcome to Android Studio" in the Android Setup Wizard will show up,
click on Configure, it will show the Android SDK Manager fetching
some packages as shown in the previous answer, click on new or
updates links
Once the packages are done loading you can go ahead and Install the
available packages. After installing the default selected packages
you may get more that are selected. Install Android SDK License. You
should select each one and then click on accept license. Android
Studio will the go through a gradle build process
I just encountered same problem and I think it is a bug. But I managed to make it work with the following workaround:
First be sure you both install the api and also build-tools (see figure below)
Than in build.gradle, change versions for api and build tools to previous ones: i.e.
android{ compileSdkVersion = 22
buildToolsVersion = "22.0.1"
defaultConfig.with {
applicationId = "com.sample.teapot"
minSdkVersion.apiLevel = 11
targetSdkVersion.apiLevel = 22
}
}
Sync gradle successfully
Change versions back
I also restarted android studio several times but not sure whether it is required or not.
I need to develop an audio app in NDK using Android Studio. I have added
the ndk path to local.properties -
ndk.dir=/opt/android-ndk-r10
sdk.dir=/opt/adt-bundle-linux-x86_64-20140702/sdk
In build.gradle I added an entry for OpenSLES -
apply plugin: 'com.android.application'
android {
compileSdkVersion 20
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.example.hellojni"
minSdkVersion 8
targetSdkVersion 21
ndk {
moduleName "HelloJNI"
ldLibs "OpenSLES" // Link with these libraries!
stl "stlport_shared"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile 'com.android.support:support-v4:20.0.0'
compile 'com.android.support:appcompat-v7:20.0.0'
}
Next I tried to add #includes for opensl -
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
but the IDE is not recognising the headers saying it cannot find the include files. I also tried importing the native-audio project into android studio but that too did not compile or run. I am aware that the official support is still not there for using NDK with Android Studio. But I have seen some videos that show how to integrate ndk with android studio.
Is there a way to do it.
Thanks in advance
OpenSL library is available for android platforms with API 9+, so you may want to change the mininimum required sdk.
Not sure how NDK chooses for which platform to compile, but you may need to compile yourself also using a custom Application.mk file like this:
APP_ABI := armeabi
APP_PLATFORM := android-9
TARGET_PLATFORM := android-9
Also, you should always target and compile with the highest available sdk.
Here's an example of what your build file should look like:
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.example.hellojni"
minSdkVersion 9
targetSdkVersion 22
ndk {
moduleName "HelloJNI"
ldLibs "OpenSLES" // Link with these libraries!
stl "stlport_shared"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.1'
}
Note: With the above configuration, the libraries are found for me (with the built-in ndk configurations).