JNI入门学习 (AndroidStudio+CMake )

JNI开发我虽然现在开发中用得少,但是还是得有必要看下的,个人平时对这快也是比较有兴趣,再加上现在在看音视频相关,更加有必要了解下这方面的东西了。

现在在网上这方面的资料虽然多,但是都是比较老的资料了,比如:命名行集成,Elicpse集成,android.mk文件集成。一般都要配置很多东西,用起来都感觉不顺手。而现在官网新出的比较流行的是使用CMake进行NDK开发了,所以这篇文章打算结合CMake来记录下JNI开发,以及自己使用的过程。

1.想了解其它的方式关于JNI开发的,可以看这里
2.关于CMake,可以看下官方文档,里面对于它的使用方法,都有详细介绍。
3.想深入理解的,可以看这里


###1.)CMake编写

AS2.2以上只要创建项目时,勾选上对C++的支持,就会生成一个支持C++的项目,剩下的我们添加cpp文件时,只要在CMake里面添加,就能调用C++的代码。

但是我还是决定创建一个原生的项目,在原生项目上添加CMake的规则文件,这样记得会更清楚些,至少我们知道在原生的基础上如何用CMake来添加对C++的支持。

< 1 > 添加cpp文件

这里写图片描述

< 2 > CMakeLists.txt代码(纯粹为了复制)

#设置 CMake编译C/C++文件的最小版本

cmake_minimum_required(VERSION 3.4.1)

#设置C/C++资源的配置信息
#三个参数的配置信息
#jni-utils                        表示C/C++文件的名称
#SHARED                           设置库的一种模式  SHARED / STATIC
#src/main/cpp/jni-utils.cpp       C/C++文件的具体路径
add_library(
            jni-utils
            SHARED
            src/main/cpp/jni-utils.cpp
)

# CMake包含了系统库的文件,指定你需要的系统文件
find_library(
            log-lib
            log
)

# 把Cmake指定的系统库文件,链接到C/C++文件中
target_link_libraries(
            jni-utils
            ${log-lib}
)

< 3 >Gradle中添加Cmake支持

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                //fexceptions  启用对 C++ 异常处理的支持
                //-frtti 支持 RTTI
                cppFlags "-fexceptions", "-frtti"
                abiFilters "armeabi", "armeabi-v7a"
            }
        }
    }
    //JNI配置 引入cmake的配置文件
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
    buildTypes {
        release {
           
        }
    }
}

dependencies {
  
}

2.)Java调用C++

java调用native首先需要,加载add_library中定义好的c++名称

static {
    System.loadLibrary("jni-utils");
}

编写调用代码需要加native关键字

public native static String JavaCallJNI();

c++对应的实现

/**
 *  java调用jni
 */
JNIEXPORT jstring JNICALL
Java_com_narkang_jni_util_JNIUtil_JavaCallJNI(JNIEnv *env, jclass type) {
    const char* returnValue = "来自C++的问候";
    return env->NewStringUTF(returnValue);
}

c++处理int和int[]

java的调用:

public native static int JavaCallJNISum(int num1, int num2);

public native static int[] JavaCallJNIArr(int[] arr);

c++的处理:

/**
 *  java处理jni的int
 */
JNIEXPORT jint JNICALL
Java_com_narkang_jni_util_JNIUtil_JavaCallJNISum(JNIEnv *env, jclass type, jint num1, jint num2) {
    return num1 + num2;
}

/**
 * java处理jni的数组
 */
JNIEXPORT jintArray JNICALL
Java_com_narkang_jni_util_JNIUtil_JavaCallJNIArr(JNIEnv *env, jclass type, jintArray arr_) {
    //1.获取arr数组的元素
    jint *arr = env->GetIntArrayElements(arr_, NULL);
    //2.获取arr数组的长度
    jint arrsize = env -> GetArrayLength(arr_);
    //3.遍历数组
    for (int i = 0; i < arrsize; ++i) {
        *(arr + i) += 10;
    }
    //4.释放内存
    env->ReleaseIntArrayElements(arr_, arr, 0);
    //5.返回值
    return arr_;
}

3.)JNI回调Java

< 1 > Jni回调Java非静态方法

java的调用:

public native static void JNICallJavaBack();

public void JNICallJava(String str){
    Log.i(TAG, str);
}

Jni主要还是要通过反射来会掉java方法,其中设计到方法签名,可以看这里

c++的处理:

/**
 * jni回调java非静态方法
 */
JNIEXPORT void JNICALL
Java_com_narkang_jni_util_JNIUtil_JNICallJavaBack(JNIEnv *env, jclass type) {
    //1.得到类的字节码
    jclass cls = env->FindClass("com/narkang/jni/util/JNIUtil");
    //2.获取方法id
    //cls类的字节码 name java方法名 sig java方法签名
    jmethodID  mid = env->GetMethodID(cls, "JNICallJava", "(Ljava/lang/String;)V");
    //3.实例化该类
    jobject jobject = env->AllocObject(cls);
    //4.设置java层参数的值
    jstring str = env->NewStringUTF("来自JNI的回调 JNICallJava");
    //5.设置java层的方法
    env->CallVoidMethod(jobject, mid, str);
}

< 2 > Jni回调Java静态方法

Java的调用:

public native static void JNICallJavaStaticBack();

public static void JNICallJavaStatic(String str){
    Log.i(TAG, str);
}

c++的处理:

/**
 * jni回调java静态方法
 */
JNIEXPORT void JNICALL
Java_com_narkang_jni_util_JNIUtil_JNICallJavaStaticBack(JNIEnv *env, jclass type) {
    //1.得到类的字节码
    jclass cls = env->FindClass("com/narkang/jni/util/JNIUtil");
    //2.获取方法id
    //cls类的字节码 name java方法名 sig java方法签名
    jmethodID  mid = env->GetStaticMethodID(cls, "JNICallJavaStatic", "(Ljava/lang/String;)V");
    //3.设置java层参数的值
    jstring str = env->NewStringUTF("来自JNI的静态方法回调 JNICallJavaStatic");
    //4.设置java层的方法
    env->CallStaticVoidMethod(cls, mid, str);
}

注意静态方法回调,不需要实例化对象,可以直接通过反射调用。


4.)运行结果

手机运行结果

这里写图片描述

控制台运行结果:

这里写图片描述

源码


5.)参考

1.http://blog.csdn.net/column/details/17225.html
2.https://developer.android.google.cn/studio/projects/add-native-code.html
3.http://blog.csdn.net/huachao1001/article/details/53906237

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值