1、準備工作:
(1)Android Studio
(2)Android SDK
(3)Android NDK(必須是r9+版本的,至於爲什麼,最後會提到)
2、具體開發流程:
在Android Studio中新建一個project或者在project中新建一個module都行,然後在Project Structure–>SDK Location中配置NDK的位置
然後新建一個類NdkJniUtils,在內部聲明native方法
package com.scutee.victor.ndktest;
public class NdkJniUtils {
public native String getCLanguageString();
}
接着,新建一個MainActivity,在佈局文件中添加一個TextView,用於顯示調用JNI的方法返回的結果
public class MainActivity extends AppCompatActivity {
private TextView tvNDK = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvNDK = (TextView) findViewById(R.id.tvNDK);
NdkJniUtils jniUtil = new NdkJniUtils();
tvNDK.setText(jniUtil.getCLanguageString());
}
}
然後build project,得到我們需要的字節碼文件(即.class文件),編譯成功後,class文件所在目錄爲:MyApplication\app\build\intermediates\classes\debug。
打開AS的Terminal(或者windows下的cmd),轉到上述目錄,然後執行javah命令生成頭文件
xxx\debug>javah -jni com.scutee.victor.ndktest.NdkJniUtils
執行成功後,在該目錄下會生成一個頭文件:com_scutee_victor_ndktest_NdkJniUtils.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_scutee_victor_ndktest_NdkJniUtils */
#ifndef _Included_com_scutee_victor_ndktest_NdkJniUtils
#define _Included_com_scutee_victor_ndktest_NdkJniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_scutee_victor_ndktest_NdkJniUtils
* Method: getCLanguageString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_scutee_victor_ndktest_NdkJniUtils_getCLanguageString
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
接着,在工程main目錄下新建一個jni目錄,將上述的.h頭文件剪切進來;然後在jni根目錄下新建一個c文件,名字隨意,內容代碼如下:
#include "com_scutee_victor_ndktest_NdkJniUtils.h"
JNIEXPORT jstring JNICALL Java_com_scutee_victor_ndktest_NdkJniUtils_getCLanguageString
(JNIEnv *env, jobject obj) {
return (*env)->NewStringUTF(env, "Hello JNI");
}
(注:env是接口指針;obj是“this”指針)
接下來,需要配置一下在app module中的build.gradle,找到其中的defaultConfig,具體配置如下:
defaultConfig {
ndk {
moduleName "JniTestLib"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
(注:moduleName是生成的so庫的名字,隨意取,最後編譯出來的.so文件會在該名字前加lib;ldLibs:添加依賴庫文件;abiFilters:輸出指定三種abi體系結構下的so庫)
最後,回到一開始新建的NdkJniUtils這個類,添加靜態初始化加載本地library的代碼:
static {
System.loadLibrary("JniTestLib");
}
到此AS下NDK JNI開發的代碼編寫和設置就ok了,編譯運行即可
3、JNI開發中遇到的錯誤及解決方法:
(1)編譯報錯:
Error:Execution failed for task ':app:compileDebugNdk'. > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\android\android-ndk-r10d\ndk-build.cmd'' finished with non-zero exit value 2
據說這是ndk在windows的一個bug,通常解決方案:在jni根目錄下新建一個空的c文件,如:test.c
(2)編譯報錯:
Error:Execution failed for task ':app:compileDebugNdk'. > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\android\android-ndk-r10d\ndk-build.cmd'' finished with non-zero exit value 2
原因:在Android Studio下進行JNI開發,NDK必須要r9+版本
(3)編譯報錯:
Error:(14, 1) A problem occurred evaluating project ':app'.
> Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.
解決方法:在project的gradle.properties下加一行代碼:“android.useDeprecatedNdk=true”:
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useDeprecatedNdk=true
開發過程中參考的博文:
http://yanbober.github.io/2015/02/14/android_studio_jni_1/