Android Jni 例程
1.Jni的作用
Java是一種比較高階的語言,Java呼叫c庫,呼叫c++庫是必不可少的,所以Jni就應運而生了。
- NDK:NDK是Native Development Kit的縮寫,是Google提供的一套工具集,可以讓你其他語言(C、C++或彙編)開發 Android的 JNI。NDK可以編譯多平臺的so,開發人員只需要簡單修改 mk 檔案說明需要的平臺,不需要改動任何程式碼,NDK就可以幫你編譯出所需的so庫。
- JNI:JNI是Java本機介面(Java Native Interface),是一個本機程式設計介面,它是Java軟體開發工具箱(Java Software Development Kit,SDK)的一部分。JNI允許Java程式碼使用以其他語言編寫的程式碼和程式碼庫。Invocation API(JNI的一部分)可以用來將Java虛擬機器(JVM)嵌入到本機應用程式中,從而允許程式設計師從本機程式碼內部呼叫Java程式碼。不過,對Java外部的呼叫通常不能移植到其他平臺,在applet中還可能引發安全異常。實現原生代碼將使您的Java應用程式無法通過100%純Java測試。但是,如果必須執行本地呼叫,則要考慮幾個準則:
1、將您的所有本地方法都封裝到一個類中,這個類呼叫單個的DLL。對每一種目標作業系統平臺,都可以用特定於適當平臺的版本的DLL。這樣可以將原生代碼的影響減少到最小,並有助於將以後所需要的移植問題考慮在內。
2、本地方法儘量簡單。儘量使您的本地方法對第三方(包括Microsoft)執行時DLL的依賴減少到最小。使您的本地方法儘量獨立,以將載入您的DLL和應用程式所需的開銷減少到最小。如果需要執行時DLL,必須隨應用程式一起提供.
2.生成一個JNI 的libjni.so庫
我這個例子主要是在有android原始碼的編譯環境下測試的,我有Android 7.1的開發編譯環境,如果大家做Android 系統開發或者應用開發,有一個Android的開發環境非常有必要,或者需要自己下載Android NDK。
2.1.在原始碼位置下新建一個原始碼路徑
HelloWorld.java原始碼如下
package com.wqf.hellojni; public class HelloWorld{ public static native String helloWorld(); public static native int add(int a,int b); }
2.2 用命令編譯生成標頭檔案
1、用命令javac com/wqf/hellojni/HelloWorld.java,生成HelloWorld.class
2、用命令javah -classpath . -jni com.wqf.hellojni.HelloWorld生成標頭檔案
注意:
網上很多說明用javah -jni com.wqf.hellojni.HelloWorld 生成標頭檔案,我試過很多次,都是失敗,還是用我上面那個命令,可以看看javah的命令幫助
2.3 編譯生成libjni.so庫步驟
2.3.1 在jni目錄裡面建立幾個檔案如下
1、把上面生成的com_wqf_hellojni_HelloWorld.h放到這個目錄來
2、新建一個jni.c檔案用來實現上面標頭檔案裡面的方法
3、新建一個Android.mk檔案用來編譯
Android.mk的內容如下
#########################################
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= jni.c
LOCAL_MODULE := libjni
include $(BUILD_SHARED_LIBRARY)
2.3.2 jni.c的內容如下
//自己建立一個c檔案,實現自己定義的native方法,也就是.h檔案中的方法
//引入自己生成的.h標頭檔案
#include "com_wqf_hellojni_HelloWorld.h"
//返回一個字串
JNIEXPORT jstring JNICALL Java_com_wqf_hellojni_HelloWorld_helloWorld(JNIEnv *env, jclass jobj) {
return (*env)->NewStringUTF(env,"HelloWorld 我是用jni調用出來的字串");
}
//返回 a+b的結果
JNIEXPORT jint JNICALL Java_com_wqf_hellojni_HelloWorld_add(JNIEnv *env, jclass jobj, jint a, jint b){
return a+b;
}
2.3.3 編譯
使用mm -B 命令編譯生成so檔案編譯結果如下圖
說個小細節,我們編譯生成的libjni.so,我們要會看他的幾個引數
1、檔案型別,使用file命令檢視是32位的庫還是64位的庫
2、使用md5sum命令檢視md5碼,這個可以檢視檔案的唯一md5碼,以後遇到一個檔名字一樣的可以用這個方式知道是不是同一個檔案
3. 寫個簡單的apk測試一下
我們的APK編寫用的是android studio來編寫的,現在android studio是非常主流的android開發工具,如果大家想自己做一個小的DEMO的話,建議裝這個工具,網上安裝流程非常多了,下載SDK後,最好不要放在C盤,要不然重灌系統後又沒有了。
3.1先來一個整體的執行效果圖片
我們在圖片上可以看到add = 9,這個是我們在JNI裡面的輸出結果
3.2 APK編譯步驟和幾個注意的細節
我是在Android 7.1上編寫APK進行測試的,相比其他Android版本,Android 7.1的問題更多,我說下操作步驟和細節。
1、我們先編寫一個可以執行的APK
我們需要編寫一個helloworld的簡單apk,這個apk不需要引用庫檔案,直接輸出一個helloworld。
2、然後我們引用我們的庫檔案
這裡注意的是HelloWorld.java 裡面的內容
載入庫的程式碼
package com.wqf.hellojni;
public class HelloWorld{
static {
//名字必須和libjni.so 名字對應起來
System.loadLibrary("jni");
}
public static native String helloWorld();
public static native int add(int a,int b);
}
在MainActivity.java裡面匯入包並呼叫add函式
4. 原始碼連線
原始碼我放在github上面,方面檢視,有原始碼的例程大家研究起來更加得心應手
https://github.com/weiqifa0/androidjni
參考:
https://blog.csdn.net/a_zhon/article/details/53097512#
5.鳴謝
覺得不錯的可以關注我的微信公眾號【嵌入式Linux】關注後可以獲取二維碼加入微信技術群