配置NDK环境,进行简单Native开发

NDK下载
环境变量配置

为ndk和jdk配置环境目录保证javah命令和ndk-build命令可以直接在命令行使用。

为AndroidStudio工程配置NDK路径

打开local.properties文件,添加ndk目录:



sdk.dir=C\:\\Users\\realhe\\AppData\\Local\\Android\\Sdk
ndk.dir=D\:\\ndk\\android-ndk-r10c

打开build.gradle,在defaultConfig中添加ndk{}:

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.0"

    defaultConfig {
        applicationId "com.example.realhe.myapplication"
        minSdkVersion 19
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
      //配置处如下
        ndk{
            moduleName "test"            //生成的so名字
            abiFilters "armeabi", "armeabi-v7a", "x86"    //输出指定三种abi体系结构下的so库
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        //此处为调试配置,可选项
            ndk {
                debuggable = true
            }
        }
        debug {
            debuggable = true
        //此处为调试配置,可选项
            jniDebuggable = true
        }
    }

}

保存后可能发生

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin

解决方法为在gradle.properties 中添加一行:


android.useDeprecatedNdk=true
JNI初步
创建文件夹

new > Folder >JNI Folder创建jni文件夹,默认目录为

app/src/main/jni

新建一个使用jni的类
public class Test {
    static {
        System.loadLibrary("test");//需要与前面的so文件名保持一致
    }
    public native String get();
    public native void set(String str);
    public native int getToken(int token);
}
导出Test类的native方法对应的头文件:
C:\Users\realhe\AndroidStudioProjects\MyApplication>
javah -classpath 
app\build\intermediates\classes\debug\ 
-d 
app\src\main\jni 
com.example.realhe.myapplication.Test

上面参数的含义依次是javah命令,classpath路径

.class文件所在的文件夹app\build\intermediates\classes\debug\

-d:输出.h到目标文件夹app\src\main\jni (即前面我们制定的默认jni文件夹)

com.example.realhe.myapplication.Test:含有native方法的类

注意这个地方一定要在项目根目录下使用,而不能切换到 Test类的.class文件所在目录直接使用

之后可以看到生成的头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_realhe_myapplication_Test */

#ifndef _Included_com_example_realhe_myapplication_Test
#define _Included_com_example_realhe_myapplication_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    get
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_realhe_myapplication_Test_get
  (JNIEnv *, jobject);

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    set
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_example_realhe_myapplication_Test_set
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    getToken
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_example_realhe_myapplication_Test_getToken
  (JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif
实现头文件中的方法

在默认的JNI文件夹中新建一个test.c文件,包含上述头文件并实现其中的方法:

//
// Created by realhe on 2016/7/18.
//
#include "com_example_realhe_myapplication_Test.h"
static int count = 0;
JNIEXPORT jstring JNICALL Java_com_example_realhe_myapplication_Test_get
        (JNIEnv *env, jobject obj){
return (*env)->NewStringUTF(env,"This is a test for NDK!");
}

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    set
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_example_realhe_myapplication_Test_set
(JNIEnv *env, jobject ibj, jstring jsr){}

/*
 * Class:     com_example_realhe_myapplication_Test
 * Method:    getToken
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_example_realhe_myapplication_Test_getToken
        (JNIEnv *env, jobject obj, jint jinvar){
    return count++;
}

注意:此处由于ndk的一个BUG,在编译单个.c文件时会报错:

com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:ndkandroid-ndk-r10ndk-build.cmd'' finished with non-zero exit value 2

解决方法为在同级目录下增加一个empty.c的空文件即可。

使用Native方法

在MainActivity中使用Nativce方法设置TextViewText:

TextView textView = (TextView)findViewById(R.id.tv_hello);
Test test = new Test();
String content = test.get();
for (int i = 0;i<10;i++){
  content += ("\n("+ test.getToken(1) + ")");
}
textView.setText(content);

最后效果如下:

clipboard.png


两岸风景
142 声望8 粉丝

I am NaOH