在老早以前就想要去接觸瞭解這一塊的知識了,奈何在工作中一直都沒有機會去接觸,就遲遲沒有去學習這一塊的知識。到現在終於開始去學習了,簡單的搜尋了一下,都沒有太明確的部落格去學習,都是很零碎的,而且在最新的版本中也有問題,到最後只能去看官方的文件,當然這才正確的選擇,其實一開始就該去看的。廢話不多說,這一個系列因為我才開始學習,不知道會有多長,但是會將常用的東西全部總結學習完。
首先來學習一下官方的配置。
一、必要的下載
這一條沒啥說的,就是下載一些工具方便開發,當然是在Android Studio中。
對於ndk的開發,需要下載:
- NDK(Native Development Kit):用來讓你呼叫c或者c++程式碼的工具
- cmake:方便在gradle中構建的,不再使用以前的ndk-build(比較麻煩)
- LLDB:可以除錯c或者c++程式碼的
這三個都可以直接在SDK Manager中去下載(當然也可以手動下載配置好)。目前我使用的版本對應分別是:
NDK : 17.1.4828580
cmake : 3.6.4111459
LLDB : 3.1.4508709
複製程式碼
二、在專案中配置NDK
這一點分為兩種情況:
- 新建專案時配置
- 在已有專案中配置
第一種情況沒啥說的,就是在新建專案時,選中第一個介面的include C++ support
這個選擇框,之後一直預設next(最後finish)即可。
重點是第二種情況,因為大多數在在專案一開始時可能沒有想著要使用ndk開發功能,後來需要了,那麼就去配置即可。
1、建立cpp資料夾
在已有專案的main目錄下建立cpp資料夾
2、建立一個c檔案
在cpp資料夾下建立一個c檔案,右鍵->new->c/c++ Source File,例如取名叫做Hello,字尾名為.c,不建立.h檔案,點選ok。
注:內部暫時可以不用寫程式碼。
3、建立CMakeLists.txt
在當前module中建立一個CMakeLists.txt檔案,右鍵->new->File,取名叫做CMakeLists.txt
,點選ok。加上以下程式碼:
cmake_minimum_required(VERSION 3.4.1)
add_library( # Specifies the name of the library.
Hello
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/Hello.c )
複製程式碼
add_library方法:
- 第一個引數:Hello,就是lib的名稱,之後在gradle中的ndk ModuleName一致
- 第二個引數暫時不管
- 第三個引數要與上文中建立的c檔案路徑和名字完全相同,字尾相同
4、使用cmake配置gradle關聯
選擇Android檢視,在需要構建的module下,右鍵->Link C++ Project with Gradle->選擇CMakeLists.txt的路徑,就是上文中建立的CMakeLists.txt,點選ok。
構建完成,可以看到在當前module下的build.gradle檔案中多了以下這段話:
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
複製程式碼
這時候再在當前的build.gradle中,android模組,defaultConfig下,新增以下程式碼:
ndk{
moduleName 'Hello'
}
複製程式碼
這裡的moduleName就是要與CMakeLists.txt中定義的libraryName一致,這裡加入叫Hello吧。
到此基本配置就算是完成了。下面就開始寫程式碼,先從java呼叫c開始。
三、Java呼叫C程式碼
1、定義Java方法
到這一步,終於回到熟悉的Java程式碼,我們在對應的包名中建立一個類,例如取名叫做Hello,加入一個簡單的本地方法,只比普通抽象方法多了一個native關鍵字,如下:
public native String stringFromC();
複製程式碼
2、定義C方法
這時候這個方法是找不到的,還需要在之前的Hello.c檔案中寫上對應的方法,如下:
#include<jni.h>
jstring Java_net_arvin_androidstudy_jni_Hello_stringFromC(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, "I am from c!");
}
複製程式碼
程式碼不長,以此來解釋,首先必須要引入的是jni.h
,下邊的JNIEnv和jstring,jobject等都是在這裡邊去定義的。
函式的申明部分,jstring
表示在java中定義的String,這個位置也就是返回值,然後Java_net_arvin_androidstudy_jni_Hello_stringFromC
這一部分看起來很長其實就是三個部分:Java_類的完全限定名_方法名,只是完全限定名中的點改為了下劃線,後邊的兩個引數env和instance,env是一個環境,用它可以操作Java類,建立字串之類的;instance就是當前呼叫這個程式碼的類的例項,這裡就是Hello類的例項。
最後就是函式的實現內容,這裡是返回一個字串然後,看一看env這個變數的型別,JNIEnv的定義可以看到是一個typedef const struct JNINativeInterface* JNIEnv;
。本身就是指標,然後在方法中的env又是指標,相當於二級指標,所以呼叫的時候使用的就是(*env)->函式。
3、Java程式碼與C程式碼關聯
回到Hello類中,在類中加一段靜態初始化的程式碼:
static {
System.loadLibrary("Hello");
}
複製程式碼
其中Hello是上文中在build.gradle中ndk下配置的moduleName。
到這裡就可以在其他地方建立Hello類的例項,然後呼叫stringFromC的方法了。
例如:
Hello jni = new Hello();
System.out.println(jni.stringFromC());
複製程式碼
就會在run tab下看到I am from c!
這樣一句話的輸出。
至此Android JNI開發系列之配置就告一段落了。當然後邊肯定還有進一步的配置學習,例如需要引入多個c檔案,需要引用其他c++庫等,肯定也是需要配置的,那些都會在之後的文章中講到。
感謝
借鑑官方教程