您的位置:首页 > 编程语言 > C语言/C++

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的动态注册:代码形式是固定的,见上面。附件:源码:点击打开链接 最后吐槽一下这个编辑器太特么难用了,每次都花好长时间在这上面!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: