欢迎来吐槽
小编最近遇到一个需求,寻思着用平常(Android)的解决方案去解决但是没找到,还好小编曾经的曾经学过C/C++,虽然很多都已经忘记,但是语言嘛,想再去学习就不那么难了。需求是:在你应用被卸载的完毕后,弹出一个网页,这种需求并不少见,但是仔细一推敲,本应用程序都已经被卸载了,随之进程也肯定被杀死了不在内存了,进程没了,怎么去实现弹出一个网页呢?于是救命稻草来了,JNI,使用java+c的模式来开发自己的应用程序,大家应该知道在C中,进程是可以自己fork出来的,因为在C中是没有GC机制的,需要手动去申请和释放内存,那么接下来就学学JNI吧。
NDK开发工具
NDK的理解
1.其实NDK就是一系列的工具的集合它提供了一系列的工具,帮助开发者去快速的开发C/C++的动态库,并且可以自动的将so和java应用一起打包成apk。帮助很大
2.NDK集成了交叉编译器,开发人员只需要简单的修改mk文件,就可以创建出so
3.NDK发布以后,官方也支持了java+c的这种模式
4.java的包都是可以进行反编译的,使用NDK我们可以将需要保密的应用逻辑使用C开发。这样提高了安全性。
接下来就使用NDK工具来进行JNI开发吧,这里使用eclipse(studio的方式暂时还没研究过,虽然小编早已经不用eclipse了)
===============================
首先你需要下载NDK并解压到一个文件夹下面:
1.打开eclipse下preference中android下的NDK,将NDK工具关联进来
2.右击工程,android tools下的 add Native suport
3.命名,xxxx-jni ,
4.会生成jni文件夹,将.cpp文件后缀改成.c,同时将android.mk中的.cpp,改成.c
5.为了支持更多平台,在jni文件夹中创建一个Application.mk,写入APP_ABI := all
6.右击 demo-jni.c 文件 选择properties,C/C++ 下的 path and symble 添加iclude文件夹
7.在本工程下的src下打开ndk-builde.cmd命令窗口(先配置环境变量,在path下配置ndk-builde.cmd目录),然后输入javah 包名.类名,在该目录下生成一个文件,该文件中有native方法的名字,拷贝方法名,然后将该文件添加到jni文件夹中,并在src中删除,然后在xxx-jni.c文件里粘贴上刚刚复制的方法名,在该方法中用C实现即可。
8.动态加载库文件
//生成的是动态的os文件 要动态的加载库文件
static{
System.loadLibrary("demo-jni");
}
JNI常见的几个错误
- 找不到库 java.lang.UnsatisfiedLinkError: Couldn’t load calc-jn1:
- 原因1 : 加载的库名不正确
原因2 : 库的代码与运行平台的不符合,新建 Application.mk其中添所有支持平台的库的生成APP_ABI := all
找不方法 java.lang.UnsatisfiedLinkError: Native method not found: com.itheima.resultfromc.MainActivity.resultFromC:(II)I
- 原因1 : 本地方法名没按jni规范
- 原因2 : 没有加载库
eg1:将java中的字符串传递到C中,进行逆向加密,然后到java中
char *rever_string(char *s){
//传入的是指针变量,地址传递,将S中的元素 逆向排序 然后直接将S返回去
//s是一个字符数组 s这个数组名就代表数组的首地址
char *p = s; //分成两句就是:char *p; p = &s;
char *q = s;
char temp = 0;
//让q指向字符数组中 \0的位置
while( *q != '\0'){
q++; //q是char类型指针,加1,一次数值上 也是加1,一次往后面移动直到\0
}
q--; //让q移动到\0前一个的位置上
//交换p q的位置
while(p < q){
temp = *p;
*p = *q;
*q = temp;
p++; //前面的往后面移动
q--; //后面的往前面移动
}
return s;
}
JNIEXPORT jstring JNICALL Java_com_example_jnidemo_MainActivity_code
(JNIEnv *evn, jobject obj, jstring jstr){
//加密 逆向加密
//首先获取字符串的长度
jstring len = (*evn)->GetStringLength(evn, jstr);
char *ch = NULL;
jstring jNewStr;
//动态申请内存 字符指针<=>声明一个字符数组 c中字符数组要多申请一个字节来存储 \0,
ch = (char *)malloc(len + 1);
//将java传递过来的字符串jstr中的内容拷贝到C中的字符数组中
(*evn)->GetStringUTFRegion(evn,jstr,0,len,ch);
//将字符数组中的元素逆向排序 定义一个方法 返回值 是 char *, 传入的参数是 char *
ch = rever_string(ch);
jNewStr = (*evn)->NewStringUTF(evn,ch);
//申请了内存空间一定要自己手动释放掉
free(ch);
return jNewStr;
}
回到正题,上面说哪个需求,接下来就是实现的代码了,直接上:
希望大家多多回馈项目中使用JNI开发的案例,多多交流多多学习。Thanks