JNI编译成Android能使用的so库,与Java工程所能使用的jnilib库不同,需要借助NDK(Native Development Kit)完成。
JNI在Java工程中的步骤参考:Java-OS X系统下JNI步骤
通过NDK编译so库, 步骤如下:
安装NDK
下载NDK,解压
打开命令行,输入:
pico .bash_profile
设置环境变量,如下图
按Control+X退出,并按Y保存
重启命令行,输入
cd ANDROID_NDK_ROOT
如果能跳到对应的目录,说明设置成功
编写Demo代码
注意,Android的Java文件必须有包名,例如下例:
package com.baidu.carlife;
import java.util.ArrayList;
public class KeyboardService {
public native void initService(String dbPath);
public native ArrayList<String> search(String key);
public native ArrayList<String> relateWords(String keyWord);
}
编译生成.H文件
在项目根目录下,创建jni文件夹,与src同级
注意必须根目录下。
在命令行中cd到根目录,执行命令
javac -d ./jni/ src/com/baidu/carlife/KeyboardService.java -classpath /Users/YI/Documents/JavaWorkSplace/Android/platforms/android-21/android.jar
完成后,在jni目录下,会生成文件:
KeyboardService.class
在命令行中cd到jni目录,执行命令
javah -jni com.baidu.carlife.KeyboardService
完成后,在jni目录下,会生成文件:
com_baidu_carlife_KeyboardService.h
其内容如下:
1 | /* DO NOT EDIT THIS FILE - it is machine generated */ |
编写CPP实现文件
新建KeyboardService.cpp文件,包含.h头文件并实现函数
1 | #include <iostream> |
具体实现,可以参考Java-JNI对象构造和字符串转换。
这里,注意在实现.h文件定义的函数时,不要调用全局变量,否则可能识别不到。同时,函数名不要与系统函数同名。
创建Android.mk
在jni目录下,创建Android.mk文件
1 | LOCAL_PATH := $(call my-dir) |
这里的:
1 | LOCAL_MODULE:最后生成的so名称,会自动加上"lib"前缀和"so"后缀,本例是libKeyboardService.so |
根据需要可以加上:
1 | LOCAL_C_INCLUDES:=头文件的搜索路径 |
创建Application.mk
在jni目录下,创建Application.mk文件
1 | APP_PLATFORM := android-21 |
这里的:
1 | APP_PLATFORM:Android版本 |
如果不设置APP_STL,会编译出错,标准库的头文件将找不到。
编译生成so库
cd到项目的根目录,执行命令
NDK-BUILD
可以看到,针对多个CPU平台的so库,都编译成功。
1 | Android NDK: WARNING: Rebuilding STLport libraries from sources! |
根目录下,生成了libs文件夹:
使用so库
加载so库
static {
System.loadLibrary("KeyboardService");
System.load("/data/data/com.baidu.carlife/libKeyboardService.so");
}
这里,有两种加载so文件的方式:
(1)用loadLibrary调用的时候需要去掉”lib”前缀和”so”后缀;
(2)用load调用的时候需要写全路径名且不能去掉前缀和后缀.
调用Demo
KeyboardService service = new KeyboardService();
service.initService(“”);
service.search("");
service.relateWords("");