惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
腾讯CDC
D
Docker
G
Google Developers Blog
D
DataBreaches.Net
雷峰网
雷峰网
Blog — PlanetScale
Blog — PlanetScale
S
SegmentFault 最新的问题
The Cloudflare Blog
有赞技术团队
有赞技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Stack Overflow Blog
Stack Overflow Blog
大猫的无限游戏
大猫的无限游戏
量子位
美团技术团队
aimingoo的专栏
aimingoo的专栏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Engineering at Meta
Engineering at Meta
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 星辰之力

网站工具 Vue项目用于Ios和Android端开发 Android assets文件夹之位置放置和作用 轻松搭建Xposed Hook cordov vue项目中调用手机原生api Android 直接修改dex破解 Android 逆向实战篇(加密数据包破解) Android JNI中C调用Java方法 Android Studio NDK JNI动态注册本地方法 JNI C反射调用java方法 Jni 线程JNIEnv,JavaVM,JNI_OnLoad(GetEnv返回NULL?FindClass返回NULL?) Jni OnLoad()和OnUnload() Android JNI之C/C++层调用JAVA Android NDK编译之undefined reference to 'JNI_CreateJavaVM' Android 开创java世界(JNI Invocation API) Android JNI c/c++调用java 无需新建虚拟机 cmake:善用find_package()提高效率暨查找JNI支持 如何解决用CMake未定义引用`JNI_CreateJavaVM'? [Linker error] undefined reference to `_imp__JNI_CreateJavaVM@12'
JNI NDK (AndroidStudio+CMake )实现C C++调用Java代码流程
星辰之力 · 2019-03-27 · via 博客园 - 星辰之力

JNI/NDK Java调用C/C++前言
  通过第三篇文章讲解在实际的开发过程中Java层调用C/C++层的处理流程。其实我们在很大的业务里也需要C/C+ +层去调用Java层,这两层之间的相互调用显得如此的重要,正式两层之间的相互调用使得程序更具有高效性、安全性可言。下面主要讲解一下C/C+ +层调用Java层的处理流程。

JNI/NDK Java调用C/C++ 编写java文件
  同样我们也需要先写java文件,用来让C/C++调用java层的方法,实现具体的业务逻辑。

public class NativeUtils {
    //1、引用JIN/NDk库文件(库名称与创建的C/C++文件名保持一致)
    static {
        System.loadLibrary("jni-utils");
    }
    //2、定义native 原生方法 (代表该方法会调用C/C++来实现功能)

    //有返回值、无参数  处理字符串
    public native String JavaCallJNI();

    //有参数、有返回值  处理int类型
    public native int JavaCallJNISum(int num1, int num2);

    //有参数、有返回值  处理int[] 数组类型
    public native int[] JavaCallJNIArr(int[] arr);

    //C/C++层调用该方法的回调
    public native void JNICallJavaBack();

    //java层方法的具体实现
    public void JNICallJava(String msg) {
        Log.e("TAG", "JNICallJava--->" + msg);
    }

    //C/C++层调用该方法的回调
    public native void JNICallJavaSumBack();

    //java层方法的具体实现
    public void JNICallJavaSum(int num1, int num2) {
        Log.e("TAG", String.format("JNICallJavaSum--->%d+%d=%d", num1, num2, num1 + num2));
    }

    //C/C++层调用该方法的回调
    public native void JNICallJavaStaticMethodBack();

    //java层方法的具体实现
    public static void JNICallJavaStaticMethod() {
        Log.e("TAG", "JNICallJavaStaticMethod--->");
    }
}

JNI/NDK Java调用C/C++ 编写C/C++文件

通过上一步我们编写了java层的代码,其次我们需要在C/C++文件中进行调用java层的方法。这是一个比较抽象的处理。总体思想就是采用反射机制拿到方法的信息。

//1.引入Jni头文件
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <android/log.h>

//处理日志打印
//------------------------------------日志处理-----------------------------------
#define LOG_TAG "JNILogTag"
//不带格式log
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,"%s",__VA_ARGS__)
//带格式
#define LOG_I(format, ...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,format,__VA_ARGS__)

//2.编写NativeUtils对应的JNI的C/C++函数
//------------------------------C/C++函数解释--------------------------------------
//JNIEXPORT JNI导出   jstring 函数返回值  JNICALL  JNI进行调用
//Java_全类名_NativeUtils方法名(JNIEnv *env,jobject jobject)
// JNIEnv *env  C/C++中的函数指针    jobject jobject 调用Native方法的类对象

//------------------------------------sig签名处理-----------------------------------
//方式一:命令
//生成方法签名的方式:进行生成.class文件的目录下 执行: javap -s  xxx.class
//方式二:规律  public String JNICallJava(String msg) java层的方法
//首先是参数(String msg) ---> (Ljava/lang/String;)
//其次返回值 String       ----> Ljava/lang/String;
//最终签名   (Ljava/lang/String;)Ljava/lang/String;
//------------------------常见的转换表------------------------
//     String              Ljava/lang/String;
//      int                 I
//      int[]               [I
//      void                V
//------------------------------------C/C++调用Java-----------------------------------
extern "C"
JNIEXPORT void JNICALL
Java_com_aynu_androidjni_NativeUtils_JNICallJavaBack(JNIEnv *env, jobject instance) {
    //1.得到类的字节码 (调用java方法所在的类  包名+类名)
    jclass cls = env->FindClass("com/aynu/androidjni/NativeUtils");
    //2.获取方法id
    //clazz 类的字节码  name java方法名称  sig java方法签名
    jmethodID mid = env->GetMethodID(cls, "JNICallJava", "(Ljava/lang/String;)V");
    //3.实例化该类
    jobject jobject = env->AllocObject(cls);
    //5.设置java层参数的值
    jstring str = env->NewStringUTF("C/C++ input  value");
    //4.调用java层方法
    env->CallVoidMethod(jobject, mid, str);
}
extern "C" JNIEXPORT void JNICALL
Java_com_aynu_androidjni_NativeUtils_JNICallJavaSumBack(JNIEnv *env, jobject instance) {
    //1.得到类的字节码 (调用java方法所在的类  包名+类名)
    jclass cls = env->FindClass("com/aynu/androidjni/NativeUtils");
    //2.获取方法id
    //参数解析 jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
    //clazz 类的字节码  name java方法名称  sig java方法签名
    jmethodID mid = env->GetMethodID(cls, "JNICallJavaSum", "(II)V");
    //3.实例化该类
    jobject jobject = env->AllocObject(cls);
    //5.设置java层参数的值
    jint num1 = 10;
    jint num2 = 5;
    //4.调用java层方法
    env->CallVoidMethod(jobject, mid, num1, num2);
}
extern "C" JNIEXPORT void JNICALL
Java_com_aynu_androidjni_NativeUtils_JNICallJavaStaticMethodBack(JNIEnv *env, jobject instance) {
    //1.得到类的字节码 (调用java方法所在的类  包名+类名)
    jclass cls = env->FindClass("com/aynu/androidjni/NativeUtils");
    //2.获取方法id
    //参数解析 jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
    //clazz 类的字节码  name java方法名称  sig java方法签名
    jmethodID mid = env->GetStaticMethodID(cls, "JNICallJavaStaticMethod", "()V");
    //3.实例化该类 该方法为static静态方法 故不需要实例化
    //jobject jobject = env->AllocObject(cls);
    //4.调用java层方法
    env->CallStaticVoidMethod(cls, mid);
}

//------------------------------------Java调用C/C++-----------------------------------
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_aynu_androidjni_NativeUtils_JavaCallJNIArr(JNIEnv *env, jobject jobject,
                                                    jintArray arr_) {
    //1.获取arr数组的元素
    jint *arr = env->GetIntArrayElements(arr_, NULL);
    //2.获取arr数组的长度
    jsize arrSize = env->GetArrayLength(arr_);
    //3.遍历数组
    for (int i = 0; i < arrSize; ++i) {
        *(arr + i) += 10;
    }
    //4.释放内存
    env->ReleaseIntArrayElements(arr_, arr, 0);
    //5.返回数组
    return arr_;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_aynu_androidjni_NativeUtils_JavaCallJNISum(JNIEnv *env, jobject jobject,
                                                    jint num1, jint num2) {
    //1.相应的逻辑运算

    return num1 + num2;

}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_aynu_androidjni_NativeUtils_JavaCallJNI(JNIEnv *env, jobject jobject) {

    //3.编写具体的业务逻辑

    return env->NewStringUTF("C/C++ Say");
}

JNI/NDK 进行调用

我们编写好java层和C/C++层之后,就需要我们进行去调用。 

public class MainActivity extends AppCompatActivity {

    private TextView mMsgTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mMsgTxt = (TextView) findViewById(R.id.msg_txt);

        NativeUtils nativeUtils = new NativeUtils();
        //Java调用JNI
        String msg = nativeUtils.JavaCallJNI();
        //mMsgTxt.setText(msg);

        //Java调用JNI实现两个数之和
        int sum = nativeUtils.JavaCallJNISum(10, 5);
        //mMsgTxt.setText(String.format("10+5=%d", sum));

        //Java调用JNI实现数组中的每个元素加10
        int[] arr = new int[]{1, 2, 3, 4, 5};
        int[] jniArr = nativeUtils.JavaCallJNIArr(arr);
        StringBuilder buffer = new StringBuilder();
        for (int aJniArr : jniArr) {
            buffer.append(aJniArr).append(",");
        }
        //mMsgTxt.setText(buffer.toString());

        //JNICallJavaBack执行
        nativeUtils.JNICallJavaBack();
        //JNICallJavaSumBack执行
        nativeUtils.JNICallJavaSumBack();
        //JNICallJavaStaticMethodBack执行
        nativeUtils.JNICallJavaStaticMethodBack();
    }
}

JNI/NDK 结果

调用之后我们会生成对应的so库文件,同时也会展示我们的最后结果。

JNI/NDK 结束语

以上便是采用Androidstudio+CMake进行搭建JNI/NDK开发中C/ C++调用Java代码流程的项目。如若有理解错误的地方,请多多留言指教。