??
一、什么是JNI
- Java本地开发接口(Java Native Interface);
- 用来沟通Java代码和外部的本地代码(c/c++)。通过这个协议,Java代码就可以调用外部的c/c++代码,外部的c/c++也可以调用Java代码;
二、为什么使用JNI
- Java语言装载到虚拟机中,不能和硬件交互,不能驱动开发。JNI扩展了Java虚拟机的能力,驱动开发(如wifi-hotspost)无线热点共享;
- Native Code效率高,数学运算、实时渲染的游戏,音视频处理(如极品飞车,opengl);
- C代码手动回收内存,程序员可以控制,及时回收内容;
- Java代码自动回收,程序员没法控制,基于算法;
- 复用代码(文件压缩,人脸识别Opencv,7zip,ffmpeg);
- 特殊应用场景,如电视、车载系统、微波炉等;
- 汽车监控系统,传感器基于电信号;
三、NDK是什么
- Native develop kits工具链,提供了交叉编译的工具链;
- C语言不跨平台,在Windows系统下使用NDK编译在Linux下能执行的函数库;
- dll:Windows系统下的函数库文件;
- so:Linux系统下的函数库文件;
- 在Linux电脑(x86架构)开发,需要使用NDK编译在手机cpu(arm架构)能执行的函数;
四、怎么使用NDK
- 在官网下载适应版本的Ndk包(android-ndk-r10e-windows-x86_64.exe文件),双击改文件即会自动解压(android-ndk-r10e文件夹,非中文目录);
- 在环境变量path中添加ndk的目录(D:\DevelopTools\android-ndk-r10e);
- 在cmd命令窗口执行ndk-build命令,有如下输出则安装成功;
五、NDK目录结构
- Builds:ndk搭建的环境;
- Docs:ndk开发的文档;
- Platform:
- arm:英国arm公司,不生产cpu,卖cpu的架构转移,功耗比较低;
- Mips:cpu架构,龙心;
- X86:inter,没有特别明显的优势,运行效率高点,功耗比较大;
- Samples:提供示例代码;
- Sources:ndk的源码;
- Toolchains:交叉工具的工具链;
- ndk-build.cmd:交叉编译的批处理文件;
六、JNI协议规范
- 规定了Java类型和c类型的转化;
java |
在jni中的别名 |
c代码 |
boolean |
jboolean |
unsigned char |
float |
jfloat |
float |
double |
jdouble |
double |
byte |
jbyte |
signed char |
char |
jchar |
unsigned short |
short |
jshort |
short |
int |
jint/jsize |
int |
long |
jlong |
long long |
Object |
jobject |
void * |
String |
jstring |
void * |
- Struct JNINativeInterface 结构体重定义了java的底层方法,底层方法通过c代码实现的;
- Runtime虚拟机 对之前的虚拟机做了优化;
七、JNI的开发流程
- 写c代码突破口native,类似于抽象方法,具体实现由c代码来实现;
public native String helloFromC();
- 创建jni目录,在jni目录中创建c代码,让c代码找到对应的native方法;
#include <jni.h>
jstring Java_com_example_hellojni_MainActivity_helloFromC(JNIEnv* env,jobject obj){
jstring jstr=(*env)->NewStringUTF(env,"Hello");
return jstr;
}
- 在jni目录下,创建Android.mk文件;
#$ linux执行方法的符号 返回当前的工程目录
LOCAL_PATH := $(call my-dir)
# 清除所有之前的缓存,清除是local开头的变量 唯一不会清除LOCAL_PATH
include $(CLEAR_VARS)
#代表打包生成的函数库的名字 前面自动生成lib 后面自动生成.so 如果前面+上lib 不会再生成lib
LOCAL_MODULE:= hello-jni
# 代表要把哪个c文件打包成函数库
LOCAL_SRC_FILES:= hello.c
# BUILD_SHARED_LIBRARY 生成动态函数库 .so 体积小 把系统的c程序动态加载
# BUILD_STATIC_LIBRARY 生成静态函数库 .a 体积大 把用到的系统的c代码 一次性加载到函数库中
include $(BUILD_SHARED_LIBRARY)
- 交叉编译,在cmd控制台,进入当前工程目录下,执行ndk-build指令;
- 在java在代码中引入函数库,直接调用native方法;
static{
//不管android.mk文件是怎么写的 就是去掉已有的函数库的lib .so
System.loadLibrary("hello-jni");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(getApplicationContext(), helloFromC(), 0).show();
}
八、NDK的简单开发流程
- 配置Eclipse的NDK路径;
- 创建Android项目,右键Android项目->Android Tools->Add Native Support;
- 添加完成native方法,在PrjectDir/scr目录下执行javah命令。生成标头文件com_example_hellojni2_MainActivity.h,并且拖拽到jni目录下;
- 将hellojni2.cpp文件修改为hello.c文件,并且将com_example_hellojni2_MainActivity.h文件中生成的方法,粘贴到hellojni2.c文件中,如下;
#include "com_example_hellojni2_MainActivity.h"
jstring Java_com_example_hellojni2_MainActivity_helloFromC(JNIEnv *env, jobject obj){
jstring jstr=(*env)->NewStringUTF(env,"Hello");
return jstr;
}
- 修改Android.mk文件中的相关配置后,点击“小锤子”生成hello-jni2.so文件;
- 同上,在MainActivity中调用hello-jni2.so文件中的c方法;
九、NDK常见错误
- 没有引入函数库/c代码和java代码不对应
11-02 14:47:33.259: E/AndroidRuntime(1185): java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.example.hellojni2.MainActivity.helloFromC() (tried Java_com_example_hellojni2_MainActivity_helloFromC and Java_com_example_hellojni2_MainActivity_helloFromC__)
- 没有Android.mk文件
D:\DevelopTools\android-ndk-r10e\ndk-build.cmd all
Android NDK: WARNING: APP_PLATFORM android-21 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml
Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
D:/DevelopTools/android-ndk-r10e/build/core/add-application.mk:199: *** Android NDK: Aborting... . Stop.
- c代码有编译时错误
Android NDK: WARNING: APP_PLATFORM android-21 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml
[armeabi] Compile thumb : hello-jni2 <= hello.c
jni/hello.c: In function ‘Java_com_example_hellojni2_MainActivity_helloFromC‘:
jni/hello.c:4:2: error: unknown type name ‘a‘
a
^
jni/hello.c:5:10: error: expected ‘=‘, ‘,‘, ‘;‘, ‘asm‘ or ‘__attribute__‘ before ‘jstr‘
jstring jstr=(*env)->NewStringUTF(env,"Hello");
- c代码有运行时异常
十、跨CPU的开发
- 在jni目录下添加Application.mk文件,定义支持的CPU类型;
APP_ABI := x86
APP_PLATFORM := android-8
- 重新交叉编译项目的so文件,会看见在支持的平台下,都会生成so文件,然后运行模拟器;
版权声明:本文为博主原创文章,未经博主允许不得转载。