Android Studio JNI 的静动态注册开发以及C/C++ JNIEnv的理解
来源:互联网 发布:python 日志时间格式 编辑:程序博客网 时间:2024/06/06 03:25
看到这个题目似乎有点啰嗦,分两块:
一是关于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编译
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 Studio JNI 的静动态注册开发以及C/C++ JNIEnv的理解
- Android Studio下的NDK开发(三):C中通过JNIEnv访问Java中的内容
- Android JNI开发(1)--JavaVM和 JNIEnv 动态注册本地方法
- Android JNI的动态注册
- C语言调用jni中JNIEnv指针使用和理解
- 【Android JNI】JNIEnv和JavaVM的区别
- Android Studio Jni开发(三)Native方法动态注册
- Android Studio3.0开发JNI流程------JNI静态注册和动态注册(多个类的native动态注册-经典篇)
- Chap16:JNI的c代码中,另外一个线程获取 JNIEnv
- Android Studio 通过JNI机制和 ndk开发的C/C++ 互相沟通
- android jni 的编写二 (NDK 开发中动态注册Jni)
- Android Studio jni动态注册步骤
- Android Studio cmake方式jni开发,在c层使用其它动态链接库*.so
- Android JNI 使用的数据结构JNINativeMethod详解 动态注册JNI
- Android studio下的Android JNI调用以及动态链接库.so的生成
- ANDROID jni 中的事件回调机制JNIenv的使用
- ANDROID jni 中的事件回调机制JNIenv的使用
- ANDROID jni 中的事件回调机制JNIenv的使用
- 微服务模式系列之二:微服务架构
- 在Nginx服务器中设置多个站点
- Cookie
- 23种设计模式,UML图
- 《iOS Run Loop 线下分享》的简单总结
- Android Studio JNI 的静动态注册开发以及C/C++ JNIEnv的理解
- 浅析busybox内置的ftpd服务程序如何配置
- iOS 多线程编程<二、GCD基本用法>
- [调试相关]预编译文件中宏定义打印日志
- Linux查找最近修改的文件
- MySql学习笔记-增删改查操作
- firefox插件(plugin)开发概述
- 第五周项目二 建立链栈算法库
- python 使用MethodType绑定方法到类