关于JNI、Java调C++、.so库避坑笔记

最近在我的Java同事在搞Java掉C++代码的事,而我是个写安卓的,在这一块比他稍微熟悉这块一些,就打算折腾一下。然后自己写了个测试,当然代码都很简单,主要是把其中的逻辑搞清楚。

一、配置AndroidStudio

在这里插入图片描述
要编译和调用原生代码,需要用的组件:
1.Android原生开发套间(NDK):这套工具能在Android应用中使用C/C++代码
2.CMake:一套外部编译工具
3.LLDB:AndroidStudio用于调试原生代码的调试程序
说明:在AndroidStudio的设置界面的Android SDK->SDK Tools中添加对LLDB和CMake、NDK的支持
1.在SDK Tools中选中性需要安装的NDK包、LLDB、CMake然后点击Apply即可安装
2.在模块中配置特定版本的NDK包
在build.gradl中dedaultConfig{}内添加子属性,如下
android{
ndkVersion “major.minor.build” //如 ndkVersion “21.0.6113669”
}
3.配置CMakeLists.txt

	CMakeLists说明:
	cmake_minimum_required(VERSION 3.4.1)			//构建本地库所需要的最小CMake版本
	add_library(test-lib SHARED test-lib.cpp)		//说明,这是添加新建的.cpp文件
	find_library()									//说明该命令是用于找到NDK库并将其路径存储为一个变量,也可以使用此变量在构	  	建脚本的其他部分引用 NDK 库
	target_link_libraries()							//说明为了让您的原生库能够调用 log 库中的函数,您需要使用 CMake 构建脚本中的target_link_libraries()命令来关联这些库
	
4.使用Gradle关联原生库
	要添加您的原生库项目作为 Gradle 构建依赖项,您需要向 Gradle 提供 CMake 或 ndk-build 脚本文件的路径
	手动配置Gradle:
		在android{}内添加子属性,如下
				externalNativeBuil{
					cmake{
						path "...."	//CMakeList.txt的相对路径
						version "...."	//CMakeList的版本
					}
				}

5.对于添加预构建的原生库
如果是将库添加在libs目录则需要在build.gradle中并在android{}内添加如下路径配置
sourceSets{
main{
jniLibs.srcDirs “…” //添加的路径
}
}
如果在自己新建jniLibs目录(与java目录同级)则不需要在gradle中配置原生库的路径
6.指定ABI
在defaultConfig配置ndk.abiFilters指定需要构建并打包到原生库中的部分

	defaultConfig{
			ndk{
				abiFilters "...."	//如:x86,x86_64,armeabi,....等等
			}
		}	

指定输出打的什么平台的.so 文件

二、编写C++文件,打.so包

在编写C++文件的时候,你需要先熟悉一些JNI的接口语法
这里写了一段测试代码


#include <jni.h>
#include <string>
#include <iostream>
extern "C" JNIEXPORT jstring JNICALL Java_zx_example_ndktest_MainActivity_jniTest(JNIEnv * env,jobject ){
    return env->NewStringUTF("Test Hello from C++");
}


extern "C"
JNIEXPORT jstring JNICALL
Java_zx_example_ndktest_JNI_stringFromJNI(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF("JNI Test from C++");
}

extern "C"
JNIEXPORT jstring JNICALL
Java_zx_example_ndktest_MainActivity_jniTest2(JNIEnv *env, jobject thiz) {
    // TODO: implement jniTest2()
}

然后Build一下,就可以生成.so库文件了
在这里插入图片描述
这就是我自己生成的.so 文件了。copy一下到另外的测试工程中,调用.so文件里面的方法
在这里插入图片描述

public class JNI {
    static {
        System.loadLibrary("native-lib");
        System.loadLibrary("test-lib");
    }

    public native String stringFromJNI();
}

然后写native方法供java调用就可以了
注意:
这里的stringFromJNI()方法只在路径xxxx.xxx.xxx.JNI类下面。然后你的C++代码的里面的JNI方法名的路径也要和你xxxx.xxx.xxx.JNI的路径一致,不然就调不到对应的C++方法,
即在C++文件中Java_zx_example_ndktest_JNI_stringFromJNI方法路径 Java_zx_example_ndktest_JNI_指定的是Java的native方法的调用路径。这个很重要

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java用.so库,需要使用Java Native Interface(JNI)来实现。下面是一个简单的JNI用.so库的例子: 1. 编写C代码 首先,需要编写一个C代码来实现所需的功能。例如,假设我们有一个名为"example.c"的C文件,其中包含一个名为"printHello"的函数,它将输出"Hello World!"。 ```c #include <stdio.h> #include "example.h" JNIEXPORT void JNICALL Java_com_example_MyClass_printHello(JNIEnv * env, jobject obj) { printf("Hello World!\n"); } ``` 2. 生成.h头文件 接下来,需要使用Java Native Interface工具生成一个.h头文件。这个文件包含了Java代码用C函数所需的函数原型和数据类型。可以使用以下命令生成头文件: ``` javac -h . example.java ``` 这将生成一个名为"example.h"的头文件。 3. 编写Java代码 现在,可以编写Java代码来用C函数。例如,假设我们有一个名为"MyClass"的Java类,其中包含一个名为"printHello"的本地方法,该方法将用C函数"printHello"。 ```java public class MyClass { static { System.loadLibrary("example"); } private native void printHello(); public static void main(String[] args) { MyClass obj = new MyClass(); obj.printHello(); } } ``` 在这里,"System.loadLibrary"方法用于加载.so库文件。在这个例子中,库文件名为"example",因此Java将搜索名为"libexample.so"的库文件。 4. 编译Java代码 编译Java代码并生成一个可执行的JAR文件。可以使用以下命令编译代码: ``` javac MyClass.java jar cvf MyClass.jar MyClass.class ``` 5. 运行Java代码 使用以下命令运行Java代码: ``` java -Djava.library.path=. -cp MyClass.jar MyClass ``` 这将运行Java代码并用C函数"printHello"。输出应该是"Hello World!"。 注意:在运行Java代码之前,需要确保库文件"libexample.so"位于当前目录下或在系统路径中。可以使用"-Djava.library.path"命令行选项指定.so库文件的路径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值