Android开发 -- JNI开发

1.配置JNI环境

  • 创建JNI文件夹

在项目的主目录中创建一个名为 JNI 的文件夹。这个文件夹将包含所有的本地源代码和配置文件。

  • 编写Android.mk文件

这个文件是一个 Makefile,用来指导 NDK 如何编译和构建本地代码。

#清除之前定义的变量,确保每个模块的配置从干净的状态开始。
LOCAL_PATH:=$(call my-dir)

#清除之前定义的变量,确保每个模块的配置从干净的状态开始。
include $(CLEAR_VARS)

#定义了生成的动态链接库的名称为OBOJni,在Android系统中会自动添加前缀lib和后缀.so,成为libOBOJni.so
LOCAL_MODULE := OBOJni

#指定test.cpp为此动态库的源文件。
LOCAL_SRC_FILES := test.cpp

#指定链接器链接Android系统的日志库liblog,以便库中可以使用日志功能。
LOCAL_LDLIBS := -llog

#引入构建系统用来编译和链接生成动态链接库的规则和命令。
include $(BUILD_SHARED_LIBRARY)
  • 配置build.gradle文件:

修改项目中的 app/build.gradle 文件,在 android{} 块中添加以下配置,以指定 JNI 库文件的存储路径和指向 Android.mk 的路径:

sourceSets {
        main {
            // 设置 JNI 库的路径
            jniLibs.srcDirs = ['../libs']
        }
    }
    externalNativeBuild {
        ndkBuild {
            //表示构建androidJNI的Android.mk的所在路径
            path '../jni/Android.mk'
        }
    }
  • 创建和编写test.cpp

#include <jni.h>
#include <android/log.h>

void hello_test_jni()
{
    __android_log_print(ANDROID_LOG_ERROR,"JNI","hello JNI test!!!");
}
  •  进入JNI路径,使用powershell编译
ndk-build.cmd

 能生成 .so 文件,则表示 C++ 编译环境配置正确。

2.java调用JNI模块

  • 创建JNI调用类

src 目录下,与 Activity 类同级,创建一个用于 JNI 调用的 Java 类 OBJNI.java。这个类将封装所有 JNI 相关的操作:

public class OBJNI {

    // 单例模式确保全局只有一个实例
    private static OBJNI instance = null;

    public static OBJNI getInstance() {
        if (instance == null) {
            instance = new OBJNI();
        }
        return instance;
    }

    // 声明 native 方法
    public native void hello_jni();

    // 加载 C++ 编写的库
    static {
        System.loadLibrary("testjni"); // 库名需与 Android.mk 中的 LOCAL_MODULE 相同
    }
}
  • 生成 native 方法的 C++ 声明:

使用 javah 工具从 OBOJNI 类生成对应的 C++ 头文件。打开命令行工具,导航至 Java 源文件所在的目录,并执行:

javah -classpath . -jni com.afison.ob.OBJNI

 

  •  找到com_itcast_ace_obo_170325_OBOJNI.h中的对应函数声明 拷贝到 test.cpp中去实现
    注意 一定要在extern C {} 中去实现 否则函数名会改变

  •  重新编译cpp程序 

cd C:\Users\Ace\Documents\GitHub\OBO\OBO_170325\JNI>
ndk-build.cmd 
生成新的so

  • 在java中 Activity中 调用此方法

OBOJNI.getInstance().hello_jni();

如果控制台能够输出cpp的日志 表示代用成功

3.java调用传参int类型的jni接口

  • 编写native方法

  • 将java函数生成C++接口

  •  C++接口

  •  调用

Java代码中调用

  •  重新编译

  • 运行结果

4.java调用传参bool类型的jni接口

  •  编写native方法

  • 将java函数生成C++接口

  •  C++接口

test.cpp中

JNIEXPORT jboolean JNICALL Java_com_afison_ob_OBOJNI_jni_1test2
        (JNIEnv *env, jobject obj, jboolean j_bool)
{
    bool arg_bool = (j_bool == JNI_TRUE)?true: false;
    __android_log_print(ANDROID_LOG_ERROR,"JNI","JNI:bool = %s",(arg_bool == true)?"true":"false");
    return (arg_bool == true)?JNI_TRUE:JNI_FALSE;
}
  •  调用

Java代码中调用

  •  重新编译

  • 运行结果

5.java调用传参String类型jni接口

  •  编写native方法

  • 将java函数生成C++接口

 

  •  C++接口
JNIEXPORT jstring JNICALL Java_com_afison_ob_OBOJNI_jni_1test3
        (JNIEnv *env, jobject obj, jstring j_str1, jstring j_str2) {
    if (j_str1 == NULL || j_str2 == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "JNI", "Input string is NULL");
        return NULL; // Optionally throw a Java exception
    }

    const char *c_str1 = env->GetStringUTFChars(j_str1, 0);
    const char *c_str2 = env->GetStringUTFChars(j_str2, 0);

    if (c_str1 == NULL || c_str2 == NULL) {
        __android_log_print(ANDROID_LOG_ERROR, "JNI", "Failed to convert Java string to native C string");
        return NULL; // Handle the error, maybe throw an exception
    }

    __android_log_print(ANDROID_LOG_ERROR, "JNI", "c_str1 = %s", c_str1);
    __android_log_print(ANDROID_LOG_ERROR, "JNI", "c_str2 = %s", c_str2);

    jstring ret_jString = env->NewStringUTF("JNI return string");

    env->ReleaseStringUTFChars(j_str1, c_str1);
    env->ReleaseStringUTFChars(j_str2, c_str2);

    return ret_jString;
}

  •  调用

Java代码中调用

bt_jni_4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String str1 = "Hello";
                String str2 = "World!";
                String str3 = OBOJNI.getInstance().jni_test3(str1,str2);
                Log.e("JNI", "Java:String="+str3);
            }
        });
  •  重新编译

  • 运行结果

6.Bug解决

More than one file was found with OS independent path 'lib/arm64-v8a/libOBOJni.so'

配置packagingOptions:在你的app模块的build.gradle文件中,使用packagingOptions来解决冲突。你可以通过添加如下配置来告诉Gradle在打包时如何处理重复的so文件:

javah -classpath . -jni com.afison.ob.OBJNIandroid {
    packagingOptions {
        pickFirst 'lib/arm64-v8a/libOBOJni.so'
        // 或者使用exclude排除特定的so文件,如:
        // exclude 'lib/arm64-v8a/libOBOJni.so'
    }
}

JNI调用成功 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值