Android JNI開(kāi)發(fā)系列之配置

在老早以前就想要去接觸了解這一塊的知識(shí)了,奈何在工作中一直都沒(méi)有機(jī)會(huì)去接觸,就遲遲沒(méi)有去學(xué)習(xí)這一塊的知識(shí)。到現(xiàn)在終于開(kāi)始去學(xué)習(xí)了,簡(jiǎn)單的搜索了一下,都沒(méi)有太明確的博客去學(xué)習(xí),都是很零碎的,而且在最新的版本中也有問(wèn)題,到最后只能去看官方的文檔,當(dāng)然這才正確的選擇,其實(shí)一開(kāi)始就該去看的。廢話(huà)不多說(shuō),這一個(gè)系列因?yàn)槲也砰_(kāi)始學(xué)習(xí),不知道會(huì)有多長(zhǎng),但是會(huì)將常用的東西全部總結(jié)學(xué)習(xí)完。

首先來(lái)學(xué)習(xí)一下官方的配置。

一、必要的下載

這一條沒(méi)啥說(shuō)的,就是下載一些工具方便開(kāi)發(fā),當(dāng)然是在Android Studio中。

對(duì)于ndk的開(kāi)發(fā),需要下載:

  • NDK(Native Development Kit):用來(lái)讓你調(diào)用c或者c++代碼的工具
  • cmake:方便在gradle中構(gòu)建的,不再使用以前的ndk-build(比較麻煩)
  • LLDB:可以調(diào)試c或者c++代碼的

這三個(gè)都可以直接在SDK Manager中去下載(當(dāng)然也可以手動(dòng)下載配置好)。目前我使用的版本對(duì)應(yīng)分別是:

NDK : 17.1.4828580
cmake : 3.6.4111459
LLDB : 3.1.4508709

二、在項(xiàng)目中配置NDK

這一點(diǎn)分為兩種情況:

  • 新建項(xiàng)目時(shí)配置
  • 在已有項(xiàng)目中配置

第一種情況沒(méi)啥說(shuō)的,就是在新建項(xiàng)目時(shí),選中第一個(gè)界面的include C++ support這個(gè)選擇框,之后一直默認(rèn)next(最后finish)即可。

重點(diǎn)是第二種情況,因?yàn)榇蠖鄶?shù)在在項(xiàng)目一開(kāi)始時(shí)可能沒(méi)有想著要使用ndk開(kāi)發(fā)功能,后來(lái)需要了,那么就去配置即可。

1、創(chuàng)建cpp文件夾

在已有項(xiàng)目的main目錄下創(chuàng)建cpp文件夾

2、創(chuàng)建一個(gè)c文件

在cpp文件夾下創(chuàng)建一個(gè)c文件,右鍵->new->c/c++ Source File,例如取名叫做Hello,后綴名為.c,不創(chuàng)建.h文件,點(diǎn)擊ok。

注:內(nèi)部暫時(shí)可以不用寫(xiě)代碼。

3、創(chuàng)建CMakeLists.txt

在當(dāng)前module中創(chuàng)建一個(gè)CMakeLists.txt文件,右鍵->new->File,取名叫做CMakeLists.txt,點(diǎn)擊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方法:

  • 第一個(gè)參數(shù):Hello,就是lib的名稱(chēng),之后在gradle中的ndk ModuleName一致
  • 第二個(gè)參數(shù)暫時(shí)不管
  • 第三個(gè)參數(shù)要與上文中創(chuàng)建的c文件路徑和名字完全相同,后綴相同

4、使用cmake配置gradle關(guān)聯(lián)

選擇Android視圖,在需要構(gòu)建的module下,右鍵->Link C++ Project with Gradle->選擇CMakeLists.txt的路徑,就是上文中創(chuàng)建的CMakeLists.txt,點(diǎn)擊ok。

構(gòu)建完成,可以看到在當(dāng)前module下的build.gradle文件中多了以下這段話(huà):

externalNativeBuild {
    cmake {
        path 'CMakeLists.txt'
    }
}

這時(shí)候再在當(dāng)前的build.gradle中,android模塊,defaultConfig下,添加以下代碼:

ndk{
    moduleName 'Hello'
}

這里的moduleName就是要與CMakeLists.txt中定義的libraryName一致,這里加入叫Hello吧。

到此基本配置就算是完成了。下面就開(kāi)始寫(xiě)代碼,先從java調(diào)用c開(kāi)始。

三、Java調(diào)用C代碼

1、定義Java方法

到這一步,終于回到熟悉的Java代碼,我們?cè)趯?duì)應(yīng)的包名中創(chuàng)建一個(gè)類(lèi),例如取名叫做Hello,加入一個(gè)簡(jiǎn)單的本地方法,只比普通抽象方法多了一個(gè)native關(guān)鍵字,如下:

public native String stringFromC();

2、定義C方法

這時(shí)候這個(gè)方法是找不到的,還需要在之前的Hello.c文件中寫(xiě)上對(duì)應(yīng)的方法,如下:

#include<jni.h>

jstring Java_net_arvin_androidstudy_jni_Hello_stringFromC(JNIEnv *env, jobject instance) {
    return (*env)->NewStringUTF(env, "I am from c!");
}

代碼不長(zhǎng),以此來(lái)解釋?zhuān)?strong>首先必須要引入的是jni.h,下邊的JNIEnv和jstring,jobject等都是在這里邊去定義的。

函數(shù)的申明部分,jstring表示在java中定義的String,這個(gè)位置也就是返回值,然后Java_net_arvin_androidstudy_jni_Hello_stringFromC這一部分看起來(lái)很長(zhǎng)其實(shí)就是三個(gè)部分:Java_類(lèi)的完全限定名_方法名,只是完全限定名中的點(diǎn)改為了下劃線(xiàn),后邊的兩個(gè)參數(shù)env和instance,env是一個(gè)環(huán)境,用它可以操作Java類(lèi),創(chuàng)建字符串之類(lèi)的;instance就是當(dāng)前調(diào)用這個(gè)代碼的類(lèi)的實(shí)例,這里就是Hello類(lèi)的實(shí)例。

最后就是函數(shù)的實(shí)現(xiàn)內(nèi)容,這里是返回一個(gè)字符串然后,看一看env這個(gè)變量的類(lèi)型,JNIEnv的定義可以看到是一個(gè)typedef const struct JNINativeInterface* JNIEnv;。本身就是指針,然后在方法中的env又是指針,相當(dāng)于二級(jí)指針,所以調(diào)用的時(shí)候使用的就是(*env)->函數(shù)。

3、Java代碼與C代碼關(guān)聯(lián)

回到Hello類(lèi)中,在類(lèi)中加一段靜態(tài)初始化的代碼:

static {
    System.loadLibrary("Hello");
}

其中Hello是上文中在build.gradle中ndk下配置的moduleName。

到這里就可以在其他地方創(chuàng)建Hello類(lèi)的實(shí)例,然后調(diào)用stringFromC的方法了。

例如:

Hello jni = new Hello();
System.out.println(jni.stringFromC());

就會(huì)在run tab下看到I am from c!這樣一句話(huà)的輸出。

至此Android JNI開(kāi)發(fā)系列之配置就告一段落了。當(dāng)然后邊肯定還有進(jìn)一步的配置學(xué)習(xí),例如需要引入多個(gè)c文件,需要引用其他c++庫(kù)等,肯定也是需要配置的,那些都會(huì)在之后的文章中講到。

感謝

借鑒官方教程

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容