Android JNI反射调用Java构造方法、成员方法和静态方法
2017-07-18 14:12
671 查看
Android开发中一般讲Java接口调用放在APP层,但是如果想对外隐藏Java接口调用,应该怎么办呢?我们可以将接口调用放在JNI层,通过反射调用所需接口,之后打包成.so库,这样既可对外隐藏所有调用细节。下面开始讲解JNI怎么调用Java方法。
这个类包一个构造方法、一个成员方法,一个静态方法,一个内部类,大多数的类都是由这三种方法组成的。下面要做的就是怎么在JNI调用这些方法。
进入到classpath目录下:
命令: cd app/build/intermediates/classes/debug
查看外部类的签名
javap -s -p com.lb6905.jnidemo.TestClass
查看内部类的签名
javap -s -p com.lb6905.jnidemo.TestClass$InnerClass
结果如下:
结果如下,达到预期效果
这种方法也可以调用Android的自带的接口,可以很大程度提高安全性,因为.so文件比较难破解。
关于env,在C和C++语言中调用方式是不同的,如下,本例使用的C语言
代码地址(顺手给个Star啊):点击查看源码
作者:lb377463323
出处:http://blog.csdn.net/lb377463323
原文链接:http://blog.csdn.net/lb377463323/article/details/75303125
转载请注明出处!
首先模拟实现一个类,代表想隐藏的接口
代码如下:package com.lb6905.jnidemo; import android.util.Log; public class TestClass { private final static String TAG = "TestClass"; public TestClass(){ Log.i(TAG, "TestClass"); } public void test(int index) { Log.i(TAG, "test : " + index); } public static void testStatic(String str) { Log.i(TAG, "testStatic : " + str); } public static class InnerClass { private int num; public InnerClass() { Log.i(TAG, "InnerClass"); } public void setInt(int n) { num = n; Log.i(TAG, "setInt: num = " + num); } } }
这个类包一个构造方法、一个成员方法,一个静态方法,一个内部类,大多数的类都是由这三种方法组成的。下面要做的就是怎么在JNI调用这些方法。
查看方法签名
这里首先Make Project,否则不会生成Java文件对应的class文件进入到classpath目录下:
命令: cd app/build/intermediates/classes/debug
查看外部类的签名
javap -s -p com.lb6905.jnidemo.TestClass
查看内部类的签名
javap -s -p com.lb6905.jnidemo.TestClass$InnerClass
结果如下:
F:\Apps\jniDemo\JNIDemo\app\build\intermediates\classes\debug>javap -s -p com.lb6905.jnidemo.TestClass Compiled from "TestClass.java" public class com.lb6905.jnidemo.TestClass { private static final java.lang.String TAG; descriptor: Ljava/lang/String; public com.lb6905.jnidemo.TestClass(); descriptor: ()V public void test(int); descriptor: (I)V public static void testStatic(java.lang.String); descriptor: (Ljava/lang/String;)V } F:\Apps\jniDemo\JNIDemo\app\build\intermediates\classes\debug>javap -s -p com.lb6905.jnidemo.TestClass$InnerClass Compiled from "TestClass.java" public class com.lb6905.jnidemo.TestClass$InnerClass { private int num; descriptor: I public com.lb6905.jnidemo.TestClass$InnerClass(); descriptor: ()V public void setInt(int); descriptor: (I)V }
在JNI中反射调用上述方法
JNIEXPORT void JNICALL Java_com_lb6905_jnidemo_MainActivity_JNIReflect (JNIEnv *env, jobject thiz) { //实例化Test类 jclass testclass = (*env)->FindClass(env, "com/lb6905/jnidemo/TestClass"); //构造函数的方法名为<init> jmethodID testcontruct = (*env)->GetMethodID(env, testclass, "<init>", "()V"); //根据构造函数实例化对象 jobject testobject = (*env)->NewObject(env, testclass, testcontruct); //调用成员方法,需使用jobject对象 jmethodID test = (*env)->GetMethodID(env, testclass, "test", "(I)V"); (*env)->CallVoidMethod(env, testobject, test, 1); //调用静态方法 jmethodID testStatic = (*env)->GetStaticMethodID(env, testclass, "testStatic", "(Ljava/lang/String;)V"); //创建字符串,不能在CallStaticVoidMethod中直接使用"hello world!",会报错的 jstring str = (*env)->NewStringUTF(env, "hello world!"); //调用静态方法使用的是jclass,而不是jobject (*env)->CallStaticVoidMethod(env, testclass, testStatic, str); //实例化InnerClass子类 jclass innerclass = (*env)->FindClass(env, "com/lb6905/jnidemo/TestClass$InnerClass"); jmethodID innercontruct = (*env)->GetMethodID(env, innerclass, "<init>", "()V"); jobject innerobject = (*env)->NewObject(env, innerclass, innercontruct); //调用子类的成员方法 jmethodID setInt = (*env)->GetMethodID(env, innerclass, "setInt", "(I)V"); (*env)->CallVoidMethod(env, innerobject, setInt, 2); }
生成.so文件
ndk-build打包成.so库,之后只需要在Android中使用就可以了static { System.loadLibrary("hello-jni"); } @Override protected void onCreate(Bundle savedInstanceState) { ...... JNIReflect(); }
结果如下,达到预期效果
10-17 11:00:29.685 26729-26729/com.lb6905.jnidemo I/TestClass: TestClass 10-17 11:00:29.685 26729-26729/com.lb6905.jnidemo I/TestClass: test : 1 10-17 11:00:29.685 26729-26729/com.lb6905.jnidemo I/TestClass: testStatic : hello world! 10-17 11:00:29.686 26729-26729/com.lb6905.jnidemo I/TestClass: InnerClass 10-17 11:00:29.686 26729-26729/com.lb6905.jnidemo I/TestClass: setInt: num = 2
这种方法也可以调用Android的自带的接口,可以很大程度提高安全性,因为.so文件比较难破解。
关于env,在C和C++语言中调用方式是不同的,如下,本例使用的C语言
在C中: (*env)->方法名(env,参数列表) 在C++中: env->方法名(参数列表)
代码地址(顺手给个Star啊):点击查看源码
作者:lb377463323
出处:http://blog.csdn.net/lb377463323
原文链接:http://blog.csdn.net/lb377463323/article/details/75303125
转载请注明出处!
相关文章推荐
- JAVA反射调用无参构造、有参构造、普通方法、成员操作
- Java反射高级应用--利用反射调用类的私有方法修改私有方法值,以及替换Java的类成员数据
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- java利用反射来调用一个类的私有方法和成员变量
- 利用java反射解决 Android系统方法不能调用的情况
- Java反射高级应用--利用反射调用类的私有方法修改私有方法值,以及替换Java的类成员数据
- free pascal(lazarus)版的android JNI进阶篇:反向调用java的方法并传递复杂参数
- 入门: 使用JNI 从C++代码中调用Java的静态方法
- 黑马程序员--Java基础加强--16.利用反射操作泛型V【通过Constructor反射解析泛型构造方法】【通过Field反射解析泛型成员变量】【个人总结】
- 关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序的探讨
- Java基础---基础加强---增强for循环、自动拆装箱及享元、枚举的作用、实现带有构造方法、透彻分析反射的基础_Class类、成员变量的反射、数组参数的成员方法进行反射、数组的反射应用
- Java反射高级应用--利用反射调用类的私有方法修改私有方法值,以及替换Java的类成员数据
- Java基础---基础加强---增强for循环、自动拆装箱及享元、枚举的作用、实现带有构造方法、透彻分析反射的基础_Class类、成员变量的反射、数组参数的成员方法进行反射、数组的反射应用
- java 程序加载过程---3--类中申明同时申明类的静态对象 创建类的实例 访问类的静态变量 调用类的静态方法 使用反射方法 初始化类的子类对象 直接使用java.exe 调用某个类
- Android 在JNI中执行Java方法--C/C++调用Java
- 【学习Android NDK开发】Java通过JNI调用native方法
- Android JNI开发高级篇有关Android JNI开发中比较强大和有用的功能就是从JNI层创建、构造Java的类或执行Java层的方法获取属性等操作。 一、类的相关操作 1. jclass FindClass(JNIEnv *env, const char *name);
- 模仿android_debug_JNITest实现apk 调用framework java JNI中方法
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java