開發環境搭建
- Windows下Eclipse+NDK+Cygwin方式:NDK r7之前的版本,必須要安裝Cygwin才能使用NDK。而在NDKr7開始,Google簡化了這個過程,在Eclispe中為NDK提供了一個ndk-build.cmd的腳本,就可以直接利用這個腳本編譯,而不用再安裝Cygwin(Cygwin的作用就是在Windows下模擬Linux環境)了。只需要為Eclipse Android工程添加一個Builders,而為Eclipse配置的builder,其實就是在執行Cygwin,然后傳遞ndk-build作為參數,這樣就能讓Eclipse自動編譯NDK了,這就簡化了我們的開發流程。
- Windows下eclipse+NDKBundle+Ant:Windows下Eclipse使用ndk-build方式構建NDK開發環境
- Android Studio 2.3+CMake(AS NDK開發默認的編譯腳本)方式
不得不感慨下,Google對NDK的支持越來越好,到上面提到的第三種方式時,NDK的開發,已經不需要你在環境方面麻煩了。使用CMake方式創建的支持DNK的項目大概長這樣
這樣方式下,在JNICall中新建一個本地方法然后“Make Project”,Gradle自動會使用CMake腳本創建本地方法對應的頭文件到native-lib.cpp文件中。這樣就可以將更多注意力放在業務相關的C/C++開發上面。
ndk-build腳本方式下通用開發流程
- 在類中定義native方法
public class JNIUnit {
public static native String getStringFormC();
}
- 使用javac命令或者AS的編譯工程,生成.class文件
- 使用javah命令將生成.class文件 --> .h頭文件
cd class文件所在目錄
javah -jni 包名.類名(如com.ns.jnistudy.JNICall)
生成文件 com_ns_jnistudy_JNICall.h如下
/* DO NOT EDIT THIS FILE - it is machine generated */
_#include <jni.h>
...
extern "C" {
//注意到函數名完全按照:java_pacakege_class_mathod 形式來命名。
//Class: com_example_hellojni_HelloJni
//Method: stringFromJNI
//Signature: ()Ljava/lang/String;
JNIEXPORT jstring JNICALL Java_com_ns_jnistudy_JNICall_getStringFormC
(JNIEnv *, jobject);
...
}
...
- 將上述文件移動到的項目的jni目錄下并實現.h文件對應的.c文件
JNIEXPORT jstring JNICALL Java_com_ns_jnistudy_JNICall_getStringFormC
(JNIEnv *, jobject){
return (*env)->NewStringUTF(env,"just have a test");
}
- 在jni目錄下增加Android.mk和Application.mk文件,關于這兩個文件的含義以及如何配置參見NDK編程--鳥瞰。
- 環境配置
在 file ->project structure 中增加 ndk的路徑,或者在local.properties 中增加ndk路徑。在 gradle.preperties 中增加android.useDeprecatedNdk=true
修改build.gradle在 defaultConfig 節增加如下配置
ndk {
moduleName "NdkJniDemo" //生成的so庫的名字
abiFilters "armeabi", "armeabi-v7a", "x86"http://ABI平臺
}
配置完成之后,當程序構建時,Gradle(一種自動化構建工具,如完成編譯,打包,測試等功能)so文件打包進APK中。 - cd到ndk目錄下執行ndk-build命令(ndk-build把.c文件編譯,鏈接生成各平臺對應的.so文件)
- 在程序的入口處(Application或者MainActivity或定義本地方法的類中)
static {
System.loadLibrary("so庫名字");
}
注意:第3步與第6步使用了javah和ndk-build命令,可以將命令配置成eclipse工具或將命令配置成Android Studio工具。
運行時Java通過JNI調用流程
- 當本地放在所在的類被第一次加載的時候,靜態代碼塊會先行加載。
- 調用的時候通過本地方法調用so文件的C/C++實現
關于ndk-build與cmake:
NDK本身是用來Android下編譯C/C++代碼的一個編譯器和庫的集合。這兩個家伙都是基于NDK的編譯系統(編譯腳本),使用項目里的Java代碼,將本地代碼編譯到共享庫中,兩個門干的事同一件事,解決的是同一個問題。ndk-build是NDK的包含的編譯系統,使用Android.mk;cmake使用CMakeLists.txt,在你的Module app的build.gradle中你可以看到這句話
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
那有哥們或者妹子就不同意了,既然都一樣,該如何選呢?ok,這問題Google已經幫我們做選擇了,AS默認是支持CMake。且CMake腳本在非Android開發者中很流行。CMake的主要便利在于你可以使用一套編譯文件構建所有的目標平臺(Android,Linux,Windows,IOS,etc)。
但是Google幫我們做了很多開發效率上的改進,但是們仍需要知道DNK開發背后的邏輯,這里以ndk-build腳本的角度來講。
參考
NDK Official tutorials
Add C and C++ Code to Your Project
Android NDK--everything you need to know
windows下Eclipse+NDK bundle開發
windows下Android Studio+NDK bundle開發