1.在公司开发JNI程序的步骤:
1.得到别人给.so文件和开发文档;
2.根据开发文档的说明,在java代码中创建本地方法;
3.把so文件放到工程的lib/armeabi/目录;
4.在java代码中加载动态库;
5.调用本地方法;
2.JNI第一个HelloWorld程序
NDK 开发环境:
下载NDK, 最新版本android-ndk-r9.
Windows 32-bit 版本下载地址:
http://dl.google.com/android/ndk/android-ndk-r9-windows-x86.zip
Windows 64-bit 版本下载地址:
http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64.zip
解压压缩包.
配置环境变量.
3.开发jni程序流程
1.在java代码中写一个本地方法:public native String sayHelloFromC();
2.在工程的根目录下创建jni文件夹;
3.在jni目录下写一个c文件:
4.在c文件中实现C方法:
#include #include #include // public native String sayHelloFromC(); // String cn.itcast.hellojni.MainActivity.sayHelloFromC() // 方法:返回值 Java_ 方法的全名(把里面的.换成_),接收两个参数:NIEnv* env,jobject obj jstring Java_cn_itcast_hellojni_MainActivity_sayHelloFromC(JNIEnv* env,jobject obj){ // 声明一个c中的爱富川 char* text = "hello from C!!!"; // 把c中的字符串转换成jstring:jstring (*NewStringUTF)(JNIEnv*, const char*); jstring jstr = (*env)->NewStringUTF(env,text); return jstr; }
5.在jni目录下创建一个Android.mk文件:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello // 动态库的名称 LOCAL_SRC_FILES := hello.c // c文件 include $(BUILD_SHARED_LIBRARY)
6.在jni目录下创建一个Application.mk文件:
APP_ABI := all
7.在命令行窗口切换工程的根目录下,执行ndk-build命令生成动态库;
8.在java代码中加载动态库:
// 加载动态库 System.loadLibrary("hello");
9.在java代码中调用本地方法;
4.jni开发常见错误
1.缺少Android.mk文件, 在jni目录下创建一个Android.mk文件.
Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk
2.c文件没有include导入jni.h的头文件, 导致某些类型找不到.
"Compile thumb : itheima31 <= Hello.c
jni/Hello.c:4:1: error: unknown type name 'JNIEXPORT'
jni/Hello.c:4:19: error: expected '=', ',', ';', 'asm' or '__attribute__' before
'JNICALL'
jni/Hello.c:4:19: error: unknown type name 'JNICALL'
3.方法的形参没有指定名称. 加上名字就可以了.
jni/Hello.c:6:3: error: parameter name omitted
4.没有加载动态库.so文件.
No implementation found for native Lcom/itheima31/commonerrordemo/MainActivity;.helloFromC ()Ljava/lang/String;
5.加载动态链接库错误, 名字写错. 加载时一定要写: Android.mk文件中的LOCAL_MODULE对应的名字.
Caused by: java.lang.UnsatisfiedLinkError: Couldn't load libitheima31.so: findLibrary returned null
6、 确定加载.so库文件的名字没有错误, 还是报一下错误. 是模拟器问题. 把生成的arm下的.so文件防盗x86模拟器上运行就报此错误.
Caused by: java.lang.UnsatisfiedLinkError: Couldn't load itheima31: findLibrary returned null
解决方法: 在jni目录下创建一个Application.mk文件, 声明以下内容:
APP_ABI := all
// 当前只能在x86的模拟器上运行, 因为生成的so文件是x86机器的机器码
APP_ABI := x86
5.Android.mk文件说明
// $表示调用本地的方法(JNI里面的方法),my-dir表示工程中的jni目录
LOCAL_PATH := $(call my-dir)
//下次构建动态库时先清除上次构建产生的变量
include $(CLEAR_VARS)
//指定动态库的名称
LOCAL_MODULE := hello
//指定本地的c文件
LOCAL_SRC_FILES := hello.c
// 构建动态库.so,.a静态库
include $(BUILD_SHARED_LIBRARY)
6.简便的开发流程
1.检查NDK的目录是否配置了:window-preferences-Android-NDK-NDK Location: 自己NDK的目录;
2.在java代码中创建一个本地方法;
3.右键工程->Android Tools->add native support...,设置动态库的名称,会创建jni目录和Android.mk,Cpp文件;
4.把cpp文件改成c文件,把Android.mk中的cpp改成c;
5.在 命令行窗口中,切换到工程src的目录下,使用javah 类的全名,生成头文件;
6.把头文件拖到jni目录下;
7.把头文件导入到c文件中,实现c方法,设置路径与符号: 右键工程->properties->C/C++ General ->Paths and Symbols->includes->
add->File system:D:developsandroid-ndk-r9dplatformsandroid-16arch-armusrinclude;
代码:
#include
#include
#include "cn_itcast_simplejni_MainActivity.h"
/**
*JNIEnv * env 是jni.h文件中指定的结构体二级指针,里面定义了很多函数指针,如果想使用这些函数指针,就需要使用到env
* jobject obj 是在java代码中调用给本地方法的对象
*/
JNIEXPORT jstring JNICALL Java_cn_itcast_simplejni_MainActivity_hellFromC
(JNIEnv * env, jobject obj){
char* text = "hello from C????";
// 把c中的字符串转换成jstring,调用:jstring (*NewStringUTF)(JNIEnv*, const char*);
jstring jstr = (*env)->NewStringUTF(env,text);
return jstr;
}
8.选中工程,砸一锤子,生成动态库
9.在Java代码加载动态库;
10.在Java代码调用本地方法;
7.java传递数据给c
#include #include #include "cn_itcast_passdatademo_JNI.h"/** * 把jstr转换成char* */char* _JString2CStr(JNIEnv* env, jstring jstr) { char* rtn = NULL; jclass clsstring = (*env)->FindClass(env, "java/lang/String"); jstring strencode = (*env)->NewStringUTF(env, "GB2312"); jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes