JNI 開發詳細初體驗 (Mac Android Studio 3.1+)

前言:第一次寫JNI,因爲搜索到的教程不少都比較舊,有些配置在新版的Android Studio 3.1+ 有點變化,所以,這裏寫一篇用截止2018年9月開學季最新版的Android Studio 3.1+ 版本的JNI入門教程。java

一、配置環境變量android

在 .bash_profile 配置文件增長如下配置:bash

export PATH=${PATH}:/Users/hebin.yang/Library/Android/sdk/ndk-bundle函數

注:以上的 ndk 路徑可直接在 Android Studio -- Open module setting 打開 Module 設置頁面,複製 ndk 安裝路徑,如圖:測試

而後輸入如下命令使修改生效:gradle

source .bash_profileui

若是報 command not found, 須要在配置文件裏增長如下配置(該配置和本文的 ndk 開發無關,這是使用Mac命令行所需的配置)spa

export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"命令行

到此,配置結束。能夠在終端輸入 ndk-build 驗證一下配置是否成功,若是成功,顯示以下圖:3d

二、JNI 文件編寫

(1)、 建立JAVA源文件,編寫 native 方法

package com.ben.ndk.jni;

public class Encrypt {

    public static native String encrypt(String source);

}
複製代碼

(2)、 經過 javah 命令生成 .h 文件

首先得cd 進入當前module 的 java 路徑:cd ndklib/src/main/java

javah -d ../jni com.ben.ndk.jni.Encrypt

生成.h文件如圖所示(jni 路徑也是自動生成的)

這個自動生成的 .h 文件內容以下圖所示:

其中紅圈裏的方法和JAVA 文件裏寫的 native 方法相對應,下一步須要用到。

(3)、 建立 .c 文件

直接複製黏貼一份 .h 文件副本,後綴改成 .c 便可(將.c 內容清空),以下圖所示:

在 .c 文件中實現c函數:導包,並將 .h 文件裏圈圈的代碼複製黏貼進來,記得增長一下參數名JNIEnv * enc, jclass cls, jstring inputStr,.c 文件的所有代碼以下:

#include "com_ben_ndk_jni_Encrypt.h"

JNIEXPORT jstring JNICALL Java_com_ben_ndk_jni_Encrypt_encrypt
  (JNIEnv * enc, jclass cls, jstring inputStr) {
        return inputStr; //For 演示,此處忽略具體邏輯,直接返回輸入的字符串
  }
  
複製代碼

(4)、 在jni目錄下建立 Android.mk 文件

寫入如下配置:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := NDKTest
LOCAL_SRC_FILES := com_ben_ndk_jni_Encrypt.c

include $(BUILD_SHARED_LIBRARY)

複製代碼

注:其中須要改動的有兩點

a. LOCAL_MODULE := NDKTest 這裏的 NDKTest 本身命名,這是將要生成的 .so庫的名字,會自動加上 lib前綴,最終生成庫文件:libNDKTest.so

引用該庫的代碼:System.loadLibrary("NDKTest");//這裏用到的就是 NDKTest

b. LOCAL_SRC_FILES := com_ben_ndk_jni_Encrypt.c 這裏也要替換爲你本身的 .c 文件名。

(5)、 在jni目錄下建立 Application.mk 文件

寫入如下配置:

APP_ABI := all

這個配置會生成全部主流 ABI 類型的 .so 庫。

至此,全部 ndk 相關的文件建立完畢,以下圖所示:

(6)、 在當前 Module 下的 build.gradle 文件配置

a. 在 defaultConfig{} 下增長如下配置:

ndk {
    moduleName "NDKTest" //System.loadLibrary("NDKTest");
}
複製代碼

b. 備註一下

不少教程比較舊,都說須要在 gradle.properties 文件里加上下面的配置:

android.useDeprecatedNdk=true

以上配置在Android Studio 3 以後就廢棄了(不須要加上)。

(7)、 最後一步

a. 在終端cd 進入前面生成的jni路徑 cd ndkhelloworld/src/main/jni,即咱們上面寫的 c 源文件的目錄

b. 輸入如下命令,生成 .so 庫:

ndk-build

若是成功,打印如圖所示:

同時,生成的 .so 庫以下圖所示(生成會稍微延遲一下,1分鐘內):

備註:會同時生成 libs 和 obj 兩個帶有 .so 庫的目錄,只須要保存 libs 目錄便可。

三、調用 .so 庫

這裏爲了更詳細的演示,咱們直接建立一個新module來演示 .so 庫的調用。

(1)、 建立jniLibs 目錄,複製以上生成的整個 libs 目錄下的.so文件到該目錄下,如圖:

(2)、 在 java 源文件下建立一個和上一步驟寫的 Encrypt native 方法類所在包名 一致的包名和 java 文件,如圖:

注意:這個路徑必須一致,不然報錯,編譯器是根據這個路徑去調用 .so 庫的 c 代碼。

在建立的 Encrypt.java 中,加載 .so 庫,代碼以下:

package com.ben.nkd.jni; //包名要和建立 .so 庫所寫的Encrypt.java 類所在包名一致。

//類名也要一致
public class Encrypt {
    
    static  {
        System.loadLibrary("NDKTest");
    }

    public static native String encrypt(String source); //這個方法和建立 .so 庫所寫的 native 代碼一致。
}
複製代碼

(3)、 測試

結果如圖:

相關文章
相關標籤/搜索