Android Studio JNI 的静动态注册开发以及C/C++ JNIEnv的理解
2016-09-30 10:10
435 查看
看到这个题目似乎有点啰嗦,分两块:一是关于JNI开发的静动态注册,因为涉及到一点逆向上的安全问题,因此有必要进行细细的琢磨和加以区别;二是在关于JNI的开发过程中对于用.c与.cpp不同文件时注意的一系列问题和原理。由于也没有太多的原理可讲,我们直接拿例子说事,直接从实现篇说起比较好,这块我不会选择像网上那些简单的输出字符串的这种例子,因为起不到一定的理解作用。由于作者编辑水平太差,如果觉得看的费劲直接点击这里下文档:点击打开链接实现篇:Android Studio JNI 的静态注册:第一步:在MainActivity.java下面新建一个类addadd.java代码如下:package com.example.zbb.jniregister;/*** Created by ZBB on 2016/9/30.*/public class addadd {static {System.loadLibrary("add");}public static native int addint(int a,int b);} 这里就是java层与本地层交互时的使用System.loadLibrary()来进行加载add.so这个文件;第二步:Java的native方法与C/C++代码函数是通过Java_<包名>_<类名>_<方法名>这种方式对应的,即它是静态注册的;因此下一步我们要使用javah命令生成以上的头文件:在main目录下新建jni目录把对应生成的头文件拷贝进去,然后新建与上面
System.loadLibrary("add")相同的add.c文件,在里面实现addint这个方法;
<strong>第三步</strong>:
在app目录下面实现更改build.gradle文件;在defaultConfig里面增加:
<pre name="code" class="cpp" style="font-size: 24px;">ndk{ moduleName "add" abiFilters "armeabi", "armeabi-v7a", "x86" }
因为Android studio中是凭借 build.gradle来自动编译这个add.c文件
当然这一点是与eclipse有点区别,但是也可以手动编译这个文件:
具体如下:
1.在jni目录下面新建Android.mk文件与eclipse下一样;
2.在build.gradle下面android{}里面加以下 :
sourceSets { main { jni.srcDirs = [] jniLibs.srcDirs = ['src/main/libs'] }}
3.在jni目录下进行ndk-build编译第四步:编译的时候可能出现这个错误:因此在gradle.properties文件下面加一句:
android.useDeprecatedNdk=true;
<strong>第五步</strong>:
在MainActivity下面补充完整功能,调用本地层功能,就OK了,总之比较简单,
有问题百度就一定可以解决。
<strong>Android studio JNI的动态注册</strong>:<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
静态注册不好处有二: 其一:比较麻烦,函数名长不好管理,形式固定; 其二:正如前一篇文章说到的对于逆向着来说比较容易找到你的核心函数,没有看的可以点击:http://blog.csdn.net/feibabeibei_beibei/article/details/52668534 因此我们下来讲动态注册: 直接上代码 将上面的代码改为: #include "com_example_zbb_jniregister_addadd.h"#include <stdlib.h>#include <string.h>#include <stdio.h>#include <jni.h>#include <assert.h>//静态注册JNI/*JNIEXPORT jint JNICALL Java_com_example_zbb_jniregister_addadd_addint (JNIEnv *env, jobject obj, jint a, jint b){ return a+b; }*///动态注册JNI/*** 方法对应表*/jint addint1(JNIEnv *env, jobject obj, jint a, jint b){ return a+b;}static JNINativeMethod gMethods[] = { {"addint", "(II)I", (void*)addint1},//绑定};/** 为某一个类注册本地方法*/static int registerNativeMethods(JNIEnv* env , const char* className , JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE;}/** 为所有类注册本地方法*/static int registerNatives(JNIEnv* env) { const char* kClassName = "com/example/zbb/jniregister/addadd";//指定要注册的类 return registerNativeMethods(env, kClassName, gMethods, sizeof(gMethods) / sizeof(gMethods[0]));}/** System.loadLibrary("lib")时调用* 如果成功返回JNI版本, 失败返回-1*/JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){ JNIEnv* env = NULL; jint result = -1; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) { return -1; } assert(env != NULL); if (!registerNatives(env)) {//注册 return -1; } //成功 result = JNI_VERSION_1_6; return result;}很简单也很好理解,唯一注意的就是在方法注册映射表这一块,在前一篇已经说过这里就不说了。最后的运行结果一样的就是:OK,完成了上面的问题,但是这里有个问题困扰了我好长时间,在使用.c和.cpp文件时的关于JNIEnv这个问题:在C中:使用JNIEnv* env要这样 (*env)->方法名(env,参数列表)使用JavaVM* vm要这样 (*vm)->方法名(vm,参数列表)在C++中:使用JNIEnv* env要这样 env->方法名(参数列表)使用JavaVM* vm要这样 vm->方法名(参数列表)上面这二者的区别是,在C中必须先对env和vm间接寻址(得到的内容仍然是一个指针),在调用方法时要将env或vm传入作为第一个参数。C++则直接利用env和vm指针调用其成员。至于具体的原因请看下面这篇博客我觉得讲的比较好: http://blog.csdn.net/freechao/article/details/7692239 总结篇:JNI静态注册:第一步:在MainActivity.java下面新建一个类XXX.java,形式如下:public class addadd { static { System.loadLibrary("add"); } public static native int addint(int a,int b);}第二步:使用javah命令生成以上的头文件Java_<包名>_<类名>_<方法名>.h的头文件;第三步:在app目录下面实现更改build.gradle文件:在defaultConfig{}里面增加: ndk{ moduleName "add" abiFilters "armeabi", "armeabi-v7a", "x86" }手动编译的具体步骤:1.在jni目录下面新建Android.mk文件与eclipse下一样;2.在build.gradle下面android{}里面加以下sourceSets { main { jni.srcDirs = [] jniLibs.srcDirs = ['src/main/libs'] }}3.在jni目录下进行ndk-build编译第四步:在gradle.properties文件下面加一句:android.useDeprecatedNdk=true;第五步:在MainActivity下面补充完整功能,调用本地层功能***************************************************************************************************JNI的动态注册:代码形式是固定的,见上面。附件:源码:点击打开链接 最后吐槽一下这个编辑器太特么难用了,每次都花好长时间在这上面!!!!!
相关文章推荐
- Android JNI开发(1)--JavaVM和 JNIEnv 动态注册本地方法
- Android Studio Jni开发(三)Native方法动态注册
- Android JNI编程(一)——JNI概念以及C语言Dev-C++开发环境搭建、编写HelloWorld
- 实现Android Studio JNI开发C/C++使用__android_log_print输出Log
- Android Studio NDK 入门教程(8)--JNI动态注册本地方法
- [安卓开发笔记二]android Studio通过jni调用C++代码
- Android整合网上资源以及个人对GreenDao数据库框架的理解与使用(android-studio开发)
- android jni 的编写二 (NDK 开发中动态注册Jni)
- Android深入理解JNI(一)JNI原理与静态、动态注册
- Android Studio jni动态注册步骤
- AndroidStudio JNI开发时,javah生成c/c++头文件出现找不到android 的类文件问题
- android studio C/C++ jni 编写以及调试方法
- Android深入理解JNI(一)JNI原理与静态、动态注册
- Android深入理解JNI(一)JNI原理与静态、动态注册
- 实现Android Studio JNI开发C/C++使用__android_log_print输出Log
- Android Studio 通过JNI机制和 ndk开发的C/C++ 互相沟通
- 【Android 系统开发】Android JNI 之 JNIEnv 解析
- Android与JNI(二) ---- Java调用C++ 动态调用
- android JNI C++开发时调试输出信息
- windows+eclipse做android开发 jni找不到标准C++的头文件问题