主要參考文獻(xiàn):
深入理解Android,卷1
Android 5.0 源碼
http://blog.csdn.net/sodino/article/details/41946607
學(xué)識(shí)尚淺,錯(cuò)誤之處請(qǐng)指正。
為什么需要JNI?
JNI(Java Native Interface的簡(jiǎn)稱),中文翻譯為java本地調(diào)用接口,名字已經(jīng)很形象的說(shuō)明了這個(gè)技術(shù)的作用,就是支持java這種高級(jí)編程語(yǔ)言對(duì)本地函數(shù)的調(diào)用,主要包括C/C++等語(yǔ)言編寫的函數(shù)。
那么對(duì)于Java而言,為什么設(shè)計(jì)這樣一種技術(shù)去調(diào)用本地函數(shù)呢?理由是顯而易見(jiàn)的:
- 操作系統(tǒng)是由C/C++實(shí)現(xiàn)的。
- 作為Java語(yǔ)言跨平臺(tái)支持的Java虛擬機(jī)是由C/C++實(shí)現(xiàn)的,它使用C/C++屏蔽不同平臺(tái)的實(shí)現(xiàn),使用JNI提供Java編程接口。
- 因?yàn)樘摂M機(jī)的存在,Java語(yǔ)言在性能要求較高的場(chǎng)景下并不適用,很多情況下要求整合C/C++模塊一同使用。
- Java語(yǔ)言存在之初已經(jīng)存在C/C++實(shí)現(xiàn)的優(yōu)秀的功能和應(yīng)用,沒(méi)必要重復(fù)造輪子。
與此可見(jiàn),JNI技術(shù)的出現(xiàn)是由于Java語(yǔ)言所處的境地和其自身的局限性必然要求。
對(duì)于Android而言,所有的android的學(xué)習(xí)者都曾經(jīng)接觸過(guò)這樣的一張經(jīng)典的android體系結(jié)構(gòu)圖。JNI是連接java層代碼和Native層的關(guān)鍵橋梁,想要了解android,就無(wú)法避免時(shí)時(shí)處處與JNI打交道。

Android Studio中JNI的簡(jiǎn)單使用
<p>
1. java代碼加載庫(kù)和聲明
首先不得不說(shuō),JNI對(duì)Java程序員來(lái)說(shuō)是非常寬容和仁慈的,因?yàn)樵贘ava中使用JNI調(diào)用本地函數(shù)非常簡(jiǎn)單。
(1) System.loadLibrary("Native");加載庫(kù)文件
(2) 使用Native聲明本地函數(shù)。
package com.jiesean.jnidemo;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
static {
//加載本地動(dòng)態(tài)庫(kù)
//JNI為本地動(dòng)態(tài)庫(kù)的名稱,在win中會(huì)自動(dòng)擴(kuò)展為.dll,在linux中會(huì)自動(dòng)擴(kuò)展為.so
System.loadLibrary("jnidemo");
}
//使用native聲明本地set函數(shù)
private native void set(int i);
//使用native聲明本地get函數(shù)
private native int get();
}
2. javah靜態(tài)注冊(cè),生成.h頭文件
Make這個(gè)工程,找到MainActivity生成的.class文件,目錄在本工程目錄下的build/intermediates/classes/debug/包名這個(gè)目錄下,以我的為例:
build/intermediates/classes/debug/com/jiesean/jnidemo/MainActivity.class
退回到工程的main目錄下,進(jìn)行javah生成.h頭文件
命令的格式為
javah-d jni -classpath <SDK_android.jar path>:<APP_classes path> com.jiesean.jnidemo.MainActivity
特別注意:<SDK_android.jar>:<APP_classes>中間的冒號(hào)為linux下的用法,windows平臺(tái)下使用分號(hào)。
以我的為例:
javah -d jni -classpath ../../../../../bin/Android/Sdk/platforms/android-24/android.jar:../../build/intermediates/classes/debug com.jiesean.jnidemo.MainActivity
這樣在android工程目錄下看到:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jiesean_jnidemo_MainActivity */
#ifndef _Included_com_jiesean_jnidemo_MainActivity
#define _Included_com_jiesean_jnidemo_MainActivity
#ifdef __cplusplus
/*
* Class: com_jiesean_jnidemo_MainActivity
* Method: set
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_jiesean_jnidemo_MainActivity_set
(JNIEnv *, jobject, jint);
/*
* Class: com_jiesean_jnidemo_MainActivity
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_jiesean_jnidemo_MainActivity_get
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
3. 配置NDK
(1) local.properties中填寫NDK路徑
ndk.dir=/home/tstz4/bin/Android/Sdk/ndk-bundle
sdk.dir=/home/tstz4/bin/Android/Sdk
(2) jnidemo/build.gradle中加入ndk
defaultConfig {
applicationId "com.jiesean.jnidemo"
minSdkVersion 17
targetSdkVersion 24
versionCode 1
versionName "1.0"
ndk {
moduleName "jnidemo"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
(3) gradle.properties文件中添加,如果不存在在工程根目錄下創(chuàng)建他。
android.useDeprecatedNdk=true
4. 生成動(dòng)態(tài)庫(kù)
配置好ndk后,再次make工程,如果顯示沒(méi)有錯(cuò)誤,說(shuō)明生成動(dòng)態(tài)庫(kù)成功。
注意:在linux下為.so文件,在windows下為.dll文件
android studio的動(dòng)態(tài)庫(kù)的輸出目錄為:
/build/intermediates/ndk/debug/lib
5. 安裝運(yùn)行,得到輸出結(jié)果
09-05 09:18:41.744 2378-2378/com.jiesean.jnidemo D/MainActivity: 得到native函數(shù)的返回值11
6. 總有些坑要我們?nèi)ゲ?/h5>
(1) javah命令使用時(shí),前面不添加SDK_android.jar path,會(huì)導(dǎo)致Activity.class找不到的錯(cuò)誤。
(2) javah命令使用時(shí),SDK_android.jar path和APP_classes path之間冒號(hào)和分號(hào)的誤用,這里前面已經(jīng)提到。
(3) linux下動(dòng)態(tài)庫(kù)會(huì)是libjnidemo.so,但是加載的時(shí)候不能根據(jù)寫這個(gè)名字,應(yīng)該根據(jù)ndk中聲明的來(lái)寫。
ndk {
moduleName "jnidemo"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
否則會(huì)出現(xiàn)
java.lang.UnsatisfiedLinkError: com.android.tools.fd.runtime
小結(jié)
本文主要說(shuō)明了在android studio中使用JNI調(diào)用native方法的簡(jiǎn)單實(shí)例。
還有一點(diǎn)不得不說(shuō),遇到問(wèn)題stackoverflow中去查,大部分很快就解決了,中文資料真的很浪費(fèi)時(shí)間。