NDK 定义:NDK编程指的是使用Android Native Development Kit(NDK)进行开发,它允许开发者使用C和C++等原生编程语言来编写Android应用的部分代码,通常是处理性能要求高或者需要直接访问设备硬件的功能
JNI函数命名规则 Java + 包名 + 类名 + 函数名(以_间隔),Eg:Java_a_b_c_ndk_MainActivity_getLength
Java_a_b_c_ndk_MainActivity_getLength (JNIEnv *env, jobject thiz, jstring param){}
数据类型
函数签名 查看函数签名的方法
输入: javap -s a.b.c.ndk01.MainActivity
读写SDCard 申请读、写、管理SDCard权限
<uses-permission android:name ="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name ="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name ="android.permission.MANAGE_EXTERNAL_STORAGE" />
MainActivity.java
package a.b.c.ndk;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.TextView;import a.b.c.ndk.databinding.ActivityMainBinding;public class MainActivity extends AppCompatActivity { private final static int MY_PERMISSION_REQUEST_WRITE_CODE = 11 ; static { System.loadLibrary("ndk" ); } public int testFun (String a,double b,long c) { return 1 ; } private ActivityMainBinding binding; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); testFun("aa" ,4.5 ,5 ); TextView tv = binding.sampleText; tv.setText(stringFromJNI()); tv.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View view) { @Override int ret = ContextCompat.checkSelfPermission(MainActivity.this ,Manifest.permission.WRITE_EXTERNAL_STORAGE); if (ret == PackageManager.PERMISSION_GRANTED) { Log.i("qqqqqqqq" ,"已经有写SDCard的权限了" ); String fp1 = Environment.getExternalStoragePublicDictory(Environment.DIRECTORY_DOWNLOADS).getAbsoultaePath(); String fc = readSDCardFile(fp1+"/b.txt" ); Log.i("qqqqqqqq" ,"文件内容:" +fc); } else { Log.i("qqqqqqqq" ,"还没有写SDcard的权限" ); ActivityCompat.requestPermissions(MainActivity.this , new String []{Manifest.permission.WRITE_EXTERNAL_STORAGE},MY_PERMISSION_REQUEST_WRITE_CODE) } } }); @Override public void onRequestPermissionResult (int requestCode,@Nonull String[] permission,@Nonull int [] grantResults) { super .onRequestPermissionResult(requestCode,permission,grantResult); swtich(requetsCode) { case MY_PERMISSION_RQQUEST_WRITE_CODE: { if (grantResult.length>0 &&grantResults[0 ]!=-1 ) { Log.i("qqqqqqqq" ,"写SDcard权限申请成功" ); } else { Log.i("qqqqqqqq" ,"写SDcard权限申请失败" ); } break ; } case 33 : { Log.i("qqqqqqqq" ,"这是申请其他权限的结果" ); break ; } } } } public native String stringFromJNI () ; public native int getLength (String param) ; public native String readSDCardFile (String filePath) ; }
native-lib.cpp
include <jni.h> #include <string> #include <android/log.h> #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"qqqqqqqq" , __VA_ARGS__); #define LOGD(...) __android_log_print(ANDROID_LOG_WARN,,"qqqqqqqq" , __VA_ARGS__); #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,"qqqqqqqq" , __VA_ARGS__); #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"qqqqqqqq" , __VA_ARGS__); extern "C" JNIEXPORT jstring JNICALL Java_a_b_c_ndk_MainActivity_stringFromJNI ( JNIEnv* env, jobject ) { std::string hello = "Hello from C++" ; return env->NewStringUTF (hello.c_str ()); } extern "C" JNIEXPORT jint JNICALL Java_a_b_c_ndk_MainActivity_getLength (JNIEnv *env, jobject thiz, jstring param) {} extern "C" JNIEXPORT jstring JNICALL Java_a_b_c_ndk_MainActivity_readSDCardFile (JNIEnv *env, jobject thiz, jstring file_path) { jstring jstring_ret = env->NewStringUTF ("null" ); char *tmp = (char *)env->GetStringUTFChars (jstring_ret,0 ); char * filePath = (char *)env->GetStringUTFChars (file_path,0 ); FILE *fp; fp = fopen (filePath,"r" ); if (fp == NULL ) { LOGE ("fp == NULL, %s" ,filePath); return jstring_ret; } char buff[1024 ]; while (fgets (buff,1024 ,fp)!=NULL ) { LOGI ("fgets :%s" ,buff); } env->ReleaseStringChars (jstring_ret, reinterpret_cast <const jchar *>(tmp)); jstring_ret = env->NewStringUTF (buff); return jstring_ret; }
Java反射 含义:在运行时检查或操作类、方法、属性等程序结构的能力。通俗地讲,反射允许程序在运行时动态地获取信息和操作对象,而不需要在编译时就知道这些信息。
1、获取类
Class.forName("类名全路径" ) 类名.class 实例.getClass
2、获取方法和属性
类.getDeclaredMethods(); 类.getDeclaredConstructors(); 类.getMethod(); 类.getDeclaredFields();
3、调用方法
用法详细解释
类.getDeclareMethods(); Class<?> clazz = MyClass.class; Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method.getName()); }
类.getDeclaredConstructors(); Class<?> clazz = MyClass.class; Constructor<?>[] constructors = clazz.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor.getName()); }
类.getMethod(); Class<?> clazz = MyClass.class; Method method = clazz.getMethod("someMethod" , String.class, int .class);
类.getDeclaredFields(); Class<?> clazz = MyClass.class; Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName()); } Eg: public class Person { private String name; private int age; public Person (String name, int age) { this .name = name; this .age = age; } public void sayHello () { System.out.println("Hello, my name is " + name + " and I am " + age + " years old." ); } private void privateMethod () { System.out.println("This is a private method." ); } } import java.lang.reflect.Field;public class ReflectionExample { public static void main (String[] args) throws NoSuchFieldException, IllegalAccessException { Class<Person> personClass = Person.class; Field[] fields = personClass.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true ); String fieldName = field.getName(); System.out.println("Field name: " + fieldName); } } } 输出: Field name: name Field name: age
MainActivity,部分代码
public void fun1 () { Class clz = null ; try { clz = Class.forName("a.b.c.ndk.Student" ); Method[] declaredMethods = clz.getDeclareMethods(); for (Method method :declareMethods) { String methodName = method.getName(); String returnType = method.getReturnType().getSimpleName(); Log.i("qqqqqqqq" ,"method:" +methodName+"," +returnType); } Constructor[] declaredConstructors = clz.getDeclaredConstructors(); for (Constructor constructor:declareConstructors) { String methodName = constructor.getName(); String returnType = constructor.toGenericString(); Log.i("qqqqqqqq" ,"Constructor:" +methodName"," +returnType); } }catch (Exception e) { e.printStackTrace(); } } public void fun2 () { Class clz = Student.class; try { Method method_study = clz.getMethod("study" ,new Class []{int .class}); Constructor constructor_Student = clz.getConstructor(new Class []{String.class,int .class}); Student student = (Student)constructor_Student.newInstance(new Object []{"lisi" ,25 }); Object obj_ret = method_study.invoke(student,new Object []{77 }); Log.i("qqqqqqqq" ,"study ret:" +(String) obj_ret); }catch (Exception e) { e.printStackTrace(); } } public void fun3 () { Class clz = one.getClass(); try { Method method_getAge0 = clz.getDeclaredMethod("getAge" ,new Class []{}); method_getAge0.setAccessible(true ); Object obj_ret = method_getAge0.invoke(one,new Object []{}); Log.i("qqqqqqqq" ,"getAge ret:" +(int ) obj_ret); }catch (Exception e) { e.printStaceTrace(); } }
Student.java
package a.b.c.ndk;import android.util.Log;public class Student { private String studentName; private int studentAge = 22 ; public Student (String studentName, int studentAge) { this .studentName = studentName; this .studentAge = studentAge; } public Student (String studentName) { this .studentName = studentName; } public String study (int flag) { Log.i("qqqqqqqq" ,"name:" + studentName +",age:" + studentAge + ",flag:" + flag); return "studyRet" ; } public static int calaLength (String param) { return param.length(); } public int getAge () { return studentAge; } }
NDK反射Java层 含义:NDK(Native Development Kit)是用于在 C/C++ 中编写代码并与 Java 层交互的工具集。在需要从 C/C++ 层访问 Java 层的情况下,可以通过 JNI(Java Native Interface)来实现。
1、获取类
jclass GetObjectClass (对象) ; jclass FindClass ("类名" ) ;
2、获取方法ID (javap -s a.b.c.javareflection.Student获取签名)
jmethodID GetMethonID (jclass clazz, const char *name, const char *sig) ; jmethodID GetStaticMethodID (jclass clazz, const char * name,const char *sig) ;
3、调用方法
void CallVoidMethod (jobject obj,jmethodID methodID,......) ;void CallStaticVoidMethod (jclass clazz, jmethodID methoID,......) ;jobject CallObjectMethod (JNIEnv*,jobject,jmethodID,.......) ;
4、获取和设置成员变量
GetFieldID; GetObjectField; SetObjectField;
MainActivity,部分代码
Log.i("qqqqqqqq" ,"callJavaFunFromJNI ret :" +callJavaFunFromJNI(one)); Log.i("qqqqqqqq" ,"callJavaFunFromJNI ret :" +callStaticJavaFunFromJNI()); public native int callJavaFunFromJNI (Student param) ; public native String callStaticJavaFunFromJNI () ;
native-lib.cpp,部分代码
extern "C" JNIEXPORT jint JNICALL MainActivity.callJavaFunFromJNI (JNIEnv *env, jobject thiz,jobject param) { jclass jclass_student = env->GetObjectClass (param); jclass jclass_student2 = env->FindClass ("a/b/c/ndk/Student" ); jmethoID jmethodID_study = env-?GetMethod (jclass_student,"study" ,"(I)Ljava/lang/String;" ); int flag = 34 ; jobject jobject_ret = env->CallObjectMethod (param,jmethodid_study,flag); char * t = (char *)env->GetStringUTFchars ((jstring)jobject_ret,0 ); LOGI ("ndk call study ret: %s" ,t); return flag; } extern "C" JNIEXPORT jstring JNICALL Java_a_b_c_ndk_MainActivity_callStaticJavaFunFromJNI (JNIEnv *env, jobject thiz) { jclass jclass_student2 = env->FindClass ("a/b/c/ndk/Student" ); jmethoID jmethodId_calcLength = env->GetStaticMethodID (jclass_student2,"calcLength" ,"(Ljava/lang/String;)I" ); jstring jstring_param = env->NewStringUTF ("hahahaha" ); jint jint_ret = env->CallStaticIntMethod (jclass_student2,jmethodId_calcLength,jstring_param); LOGI ("ndk call calcLength ret:%d" ,jint_ret); return jstring_param; }
NDK反射获取包名 查看系统源码:http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/app/ActivityThread.java
native-lib.cpp,部分代码
extern "C" JNIEXPORT jstring JNICALL Java_a_b_c_k02s10_MainActivity_getPkgName (JNIEnv *env, jobject thiz) { jclass cls_ActivityThread = env->FindClass ("android/app/ActivityThread" ); jmethodID jmethodId_currentActivityThread = env->GetStaticMethodID (cls_ActivityThread, "currentActivityThread" , "()Landroid/app/ActivityThread;" ); jobject ins_currentActivityThread = env->CallStaticObjectMethod (cls_ActivityThread, jmethodId_currentActivityThread); jmethodID jmethodId_getApplication = env->GetMethodID (cls_ActivityThread, "getApplication" , "()Landroid/app/Application;" ); jobject ins_mInitialApplication = env->CallObjectMethod (ins_currentActivityThread, jmethodId_getApplication); jclass cls_Application = env->GetObjectClass (ins_mInitialApplication); jmethodID jmethodId_getPackageName = env->GetMethodID (cls_Application, "getPackageName" , "()Ljava/lang/String;" ); jstring pkgName = (jstring)env->CallObjectMethod (ins_mInitialApplication, jmethodId_getPackageName); return pkgName; }
动态注册JNI函数 typedef struct { const char * name; const char * signature; void * fnPtr; } JNINativeMethod;
RegisterNatives
JNIEXPORT jint JNICALL RegisterNatives (JNIEnv *env, jclass cls, const JNINativeMethod *methods, jint nMethods) ;env:JNI 环境指针,通过它可以访问 JNI 提供的方法和功能。 cls:要注册本地方法的 Java 类的 jclass 对象。 methods:一个 JNINativeMethod 结构体数组,定义了要注册的本地方法。 nMethods:要注册的本地方法的数量。
GetEnv
jint result = vm->GetEnv (&env, JNI_VERSION_1_4);
MainActivity,部分代码
public native String getPkgName2222 () ;Log.i("qqqqqqqq" ,"jni22222 return:" +getPkgName2222());
native-lib.cpp
jstring getAAAA (JNIEnv *env, jobject thiz) { jclass cls_ActivityThread = env->FindClass ("android/app/ActivityThread" ); jmethodID jmethodId_currentActivityThread = env->GetStaticMethodID (cls_ActivityThread, "currentActivityThread" , "()Landroid/app/ActivityThread;" ); jobject ins_currentActivityThread = env->CallStaticObjectMethod (cls_ActivityThread, jmethodId_currentActivityThread); jmethodID jmethodId_getApplication = env->GetMethodID (cls_ActivityThread, "getApplication" , "()Landroid/app/Application;" ); jobject ins_mInitialApplication = env->CallObjectMethod (ins_currentActivityThread, jmethodId_getApplication); jclass cls_Application = env->GetObjectClass (ins_mInitialApplication); jmethodID jmethodId_getPackageName = env->GetMethodID (cls_Application, "getPackageName" , "()Ljava/lang/String;" ); jstring pkgName = (jstring)env->CallObjectMethod (ins_mInitialApplication, jmethodId_getPackageName); jstring ret = env->NewStringUTF (" from getAAAA!!!" ); return ret; } jint JNI_OnLoad (JavaVM* vm,void * reserved) { JNIEnv* env = NULL ; jint restule = -1 ; vm->GetEnv ((void **)(&env),JNI_VERSION_1_4); JNINativeMethod methods[] = {{"getPkgName2222" },"()Ljava/lang/String;" ,(void *)getAAAA}; env->Register (cls_MainActivity,methods,sizeof (methods)/sizeof (JNINativeMethod)); result = JNI_VERSION_1_4; return result; }