Import hello-neon (ndk samples) to Android Studio with MAC OS X

时间:2016-04-04 17:58:32

标签: android android-studio gradle android-ndk android-gradle

I am new to NDK, gradle, and Android Studio (AS) and meet some problem while importing hello-neon (ndk samples) to AS. My operating system is MAC OS X Yosemite.

After seting ndk.dir and sdk.dir in local.properties and write android.useDeprecatedNdk=true to gradle.properties, I still cannot make this program because I cannot find the cpu-features.h in helloneon.c.

I have searched for several methods. The only valid method is to add

sourceSets.main {
    jni.srcDirs = []
}

to build.gradle.

After that, we can Make Project and install it on Android VM. However, the app will crash when I open it. To find the reason, I found that public native String stringFromJNI() at HelloNeon.java cannot be linked to its implementation at helloneon.c. ("cannot resolve corresponding Jni functions")

Still following the instruction provided at stackoverflow, I use ndk-build to build the source code (need to add environment variable pointing to cpufeatures) and add .so files to this project, like screen shot of the structure of my project

After doing so (adding .so files), it is still said "cannot resolve corresponding Jni functions" at stringFromJNI in HelloNeon.java. But it can be "Make Project" and can be successfully run on my VM!

I don't know whether it is a good solution because AS still report errors at HelloNeon.java even it can be compile.

Then I try add following sentences to build.gradle

sourceSets.main {
    jniLibs.srcDir 'src/main/jinLibs' 
}

It does not change any thing. (these code can be delete. --by bullsy)

I also try to copy cpu-features.h and cpu-features.c to /main/jni , then we can find the cpu-features.h but miss other files.

As a result, I come here to find some help. Can you help point out the mistakes we have made and the correct way to solve it? Although this is a naive problem for experts to this area, I really appreciate your help as a new man to this area.

Thank you very much!


This is my build.gradle (Module: app) :

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "com.example.neon"
        minSdkVersion 4
        targetSdkVersion 4

        ndk {
            moduleName "helloneon"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    sourceSets.main {
        jni.srcDirs = []
    }

    sourceSets.main {
        jniLibs.srcDir 'src/main/jinLibs' // <-- Set your folder here!
    }

}

This is my another build.gradle (Project: hello-neon) :

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

This is my settings.gradle :

include ':app'
include ':cpufeatures'

My Android Studio version is 1.5.1

My ndk version (./ndk-build -version) is GNU Make 3.81

Thanks again.


UPDATE

Thank you bullsy. I added following code in my build.gradle :

task ndkBuild(type: Exec) {
    commandLine 'ndk-build', '-C', commandLine 'ndk-build', '-C', file('/Users/zhu/AndroidStudioProjects/hello-neon/app/src/main')
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn ndkBuild
}

And got some error information when "Make Project" in ndk-build:

Information:Gradle tasks [:app:generateDebugSources, :app:generateDebugAndroidTestSources, :app:compileDebugSources, :app:compileDebugAndroidTestSources]
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
:app:checkDebugManifest
:app:prepareDebugDependencies
:app:compileDebugAidl UP-TO-DATE
:app:compileDebugRenderscript UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:processDebugManifest UP-TO-DATE
:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
:app:preDebugAndroidTestBuild UP-TO-DATE
:app:prepareDebugAndroidTestDependencies
:app:compileDebugAndroidTestAidl UP-TO-DATE
:app:processDebugAndroidTestManifest UP-TO-DATE
:app:compileDebugAndroidTestRenderscript UP-TO-DATE
:app:generateDebugAndroidTestBuildConfig UP-TO-DATE
:app:generateDebugAndroidTestAssets UP-TO-DATE
:app:mergeDebugAndroidTestAssets UP-TO-DATE
:app:generateDebugAndroidTestResValues UP-TO-DATE
:app:generateDebugAndroidTestResources UP-TO-DATE
:app:mergeDebugAndroidTestResources UP-TO-DATE
:app:processDebugAndroidTestResources UP-TO-DATE
:app:generateDebugAndroidTestSources UP-TO-DATE
:app:ndkBuild
make: *** /Users/zhu/AndroidStudioProjects/hello-neon/app/main: No such file or directory.  Stop.
Error:Execution failed for task ':app:ndkBuild'.
> Process 'command 'ndk-build'' finished with non-zero exit value 2
Information:BUILD FAILED

Then I use /Applications/Android\ Studio.app/Contents/MacOS/studio to start the AS so that AS can read environment variable from bash, these code works!

However, this .so files will be store in "/Users/zhu/AndroidStudioProjects/hello-neon/app/src/main/libs" and these .so file cannot be loaded directly (It seems that the project will only load the .so file in jniLibs/).

As a result, should I add

sourceSets.main {
    jniLibs.srcDir 'src/main/libs' 
}

If not, what should I do?

1 个答案:

答案 0 :(得分:0)

Remove this code:

sourceSets.main {
    jniLibs.srcDir 'src/main/jinLibs' // <-- Set your folder here!
}

Because you're using Android.mk, setting jniLibs.srcDir to empty is correct. This tells the build system not to override your Android.mk file. In order to build properly, you'll need to call ndk-build from your build.gradle and point it to your jni directory. Setting up the call to ndk-build might look like this:

// call regular ndk-build(.cmd) script from app directory
task ndkBuild(type: Exec) {
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
    } else {
        commandLine 'ndk-build', '-C', file('src/main').absolutePath
    }
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn ndkBuild
}

These examples are pulled from ph0b's excellent tutorial on working with the older version of the NDK. If you are interested in trying the experimental NDK support at some point in the future when you're a little more comfortable, ph0b has posted some great stuff on that too.