搭建環(huán)境
搭建好android studio的ndk環(huán)境其實(shí)就是一行代碼的問題:在你的local.properties中加入這一行代碼就好前提是你已經(jīng)下載好了ndk的包
ndk.dir=/Users/NingSo/android-ndk-r10e
JNI 開發(fā)流程主要分為以下 6 步:
- 編寫聲明了 native 方法的 Java 類
- 將 Java 源代碼編譯成 class 字節(jié)碼文件
- 將 Java 源代碼編譯成 class 字節(jié)碼文件
- 用 javah -jni 命令生成.h頭文件
javah 是 jdk 自帶的一個(gè)命令锦担,-jni 參數(shù)表示將 class 中用native 聲明的函數(shù)生成 JNI 規(guī)則的函數(shù)
- 用本地代碼實(shí)現(xiàn).h頭文件中的函數(shù)
注意實(shí)現(xiàn)函數(shù)時(shí)參數(shù)要自己定義聲明
- 執(zhí)行ndk-build 將本地寫好的C代碼編譯成動(dòng)態(tài)庫
-
拷貝動(dòng)態(tài)庫至 java.library.path 本地庫搜索目錄下委乌,并運(yùn)行 Java 程序
Paste_Image.png
通過上面的介紹,相信大家對(duì) JNI 及開發(fā)流程有了一個(gè)整體的認(rèn)識(shí)扫茅,下面通過一個(gè) HelloWorld 的示例偶宫,再深入了解 JNI 開發(fā)的各個(gè)環(huán)節(jié)及注意事項(xiàng).
代碼演示
第一步:
在自己項(xiàng)目中創(chuàng)建一個(gè)包含native的方法類HelloWorld.java
-->包名com.ningso.ningsodemo
public class HelloWorld {
public native String sayHello(String name); // 1.聲明這是一個(gè)native函數(shù),由本地代碼實(shí)現(xiàn)
static {
System.loadLibrary("hello"); // 2.加載實(shí)現(xiàn)了native函數(shù)的動(dòng)態(tài)庫,只需要寫動(dòng)態(tài)庫的名字
}
}
第二步:
在終端執(zhí)行javac命令將.java
源文件編譯成.class
字節(jié)碼文件
執(zhí)行javac命令
-d 表示將編譯后的class文件放到指定的文件夾下面
結(jié)果圖:
編譯后的字節(jié)碼文件
以上也可以直接執(zhí)行./gradlew build 不過文件就要自己去找了饶号,該class在你的
/app/build/intermediates/classes/debug
文件夾對(duì)應(yīng)的包名下
第三步:
繼續(xù)在終端執(zhí)行javah -jni
命令 根據(jù)class文件生產(chǎn).h
頭文件
Paste_Image.png
注意:-d和-o只能使用其中一個(gè)參數(shù)。
參數(shù)說明:classpath:類搜索路徑季蚂,這里表示從當(dāng)前的 bin 目錄下查找
-d:將生成的頭文件放到當(dāng)前的 jni 目錄下
-o: 指定生成的頭文件名稱茫船,默認(rèn)以類全路徑名生成(包名+類名.h)
結(jié)果圖:
對(duì)應(yīng)的兩條命令生產(chǎn)的.h文件,位置不同扭屁,名稱不同而已算谈。但是內(nèi)容一樣
Hello.h內(nèi)容:
/* DO NOT EDIT THIS FILE - it is machine generated *
/#include <jni.h>
/* Header for class com_ningso_ningsodemo_HelloWorld */
#ifndef _Included_com_ningso_ningsodemo_HelloWorld
#define _Included_com_ningso_ningsodemo_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/* * Class: com_ningso_ningsodemo_HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_ningso_ningsodemo_HelloWorld_sayHello
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus}
#endif
#endif
第四步:
在main目錄下新建一個(gè)jin文件夾將.h文件拖至此目錄下并在這做如下操作:
- 實(shí)現(xiàn).h中的函數(shù)
#include "hello.h"
#include <stdio.h>
#ifdef __cplusplh
extern "C" {
#endif
/* * Class: com_ningso_ningsodemo_HelloWorld * Method: sayHello * Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_ningso_ningsodemo_HelloWorld_sayHello
(JNIEnv *env, jclass cls, jstring j_str)
{
const char *c_str = NULL;
char buff[128] = { 0 };
c_str = (*env)->GetStringUTFChars(env, j_str, NULL);
if (c_str == NULL) {
printf("out of memory.\n");
return NULL;
}
printf("Java Str:%s\n", c_str);
sprintf(buff, "hello %s", c_str);
(*env)->ReleaseStringUTFChars(env, j_str, c_str);
return (*env)->NewStringUTF(env, buff);
}
#ifdef __cplusplus}
#endif
- 編寫Android.mk文件 內(nèi)容如下:
LOCAL_PATH := $(call my-dir) ## 定義 LOCAL_PATH 環(huán)境變量為本文件的目錄,mydir 表示當(dāng)前目錄料滥。
include $(CLEAR_VARS) ## 清除除了 LOCAL_PATH 以外其他的 LOCAL_ 環(huán)境變量
LOCAL_MODULE := hello ## 動(dòng)態(tài)庫名字為hello
LOCAL_SRC_FILES := hello.c ## 源文件名字
include $(BUILD_SHARED_LIBRARY) ## 編譯生成共享動(dòng)態(tài)庫
- 編寫Application.mk文件內(nèi)容如下:
APP_ABI := all ## 表示生成所有平臺(tái)的動(dòng)態(tài)庫然眼。
結(jié)果圖:
編譯成功的結(jié)果圖
第五步:
在終端cd進(jìn)入到j(luò)ni目錄下,執(zhí)行ndk-build
命令:
編譯成功的結(jié)果顯示圖
然后回到項(xiàng)目main目錄下會(huì)發(fā)現(xiàn)已經(jīng)生產(chǎn)好的so文件躺在那等你調(diào)用了葵腹。
看W镏巍!礁蔗!結(jié)果>跻濉!
最后運(yùn)行apk了
在你的代碼里面執(zhí)行如下代碼:
HelloWorld helloWorld = new HelloWorld();
textView.setText(helloWorld.sayHello("終于運(yùn)行起來了浴井。"));
完結(jié)