啥是JNI?
Jin是java 与 C/C++ 互访问的一种方案
- 从 java 中访问 C/C++
- 从 C/C++ 中访问 java
一般什么时候使用Jni
- 性能需求:利用C/C++的高性能特点,处理一些数据
- 三方库:比如openvc这类库一般都是用 C 写,当时这些库基本都给封装好了jar调用库
- 驱动:这是 android 与底层驱动互调用的重要手段
jni 的简单应用
用Android Studio创建一个Empty Activity项目
- MainActivity 代码
package org.eu.uiai.jnilearn;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
static {
//缺失 libc++_shared.so 解决问题的库,通过CMake直接编译到软件中
System.loadLibrary("help_lib_name");
//编译出的库文件为 libmylib.so
System.loadLibrary("mylib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView ss=findViewById(R.id.show_string);
TextView st=findViewById(R.id.show_text);
JniApi jApi=new JniApi();
int a=9,b=10;
ss.setText(jApi.getString(1));
st.setText(a+"+"+b+"="+jApi.getSum(a,b));
}
}
- Java 调用 C 的 API 接口
package org.eu.uiai.jnilearn;
public class JniApi {
public native String getString(int id);
public native int getSum(int a,int b);
}
- 通过命令行将JniApi的代码生成 C++ 的头文件
javac ./app/src/main/java/org/eu/uiai/jnilearn/JniApi.java -h ./app/src/main/jni
- 头文件 org_eu_uiai_jnilearn_JniApi.h 内容
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class org_eu_uiai_jnilearn_JniApi */
#ifndef _Included_org_eu_uiai_jnilearn_JniApi
#define _Included_org_eu_uiai_jnilearn_JniApi
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_eu_uiai_jnilearn_JniApi
* Method: getString
* Signature: (I)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_eu_uiai_jnilearn_JniApi_getString
(JNIEnv *, jobject, jint);
/*
* Class: org_eu_uiai_jnilearn_JniApi
* Method: getSum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_org_eu_uiai_jnilearn_JniApi_getSum
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
- 根据JNI头文件写 C++ 的实现代码
#include
#include "org_eu_uiai_jnilearn_JniApi.h"
JNIEXPORT jstring JNICALL Java_org_eu_uiai_jnilearn_JniApi_getString
(JNIEnv *env, jobject, jint id) {
int iid = (int) id;
if (iid == 0) {
return env->NewStringUTF("Hello world!");
} else if (iid == 1) {
return env->NewStringUTF("你好世界!");
}
return env->NewStringUTF("未知ID");
}
JNIEXPORT jint JNICALL Java_org_eu_uiai_jnilearn_JniApi_getSum
(JNIEnv *, jobject, jint a, jint b) {
return a + b;
}
- 编译出不同平台的 so 库 NDK的路径:“D:\DevSoft\AndroidSDK\ndk” C++编译工具的路径,版本不同有些区别:“24.0.8215888\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++” 编译的架构:架构-linux-android21
# arm64 平台的
D:\DevSoft\AndroidSDK\ndk\24.0.8215888\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++ -target aarch64-linux-android21 ./app/src/main/jni/mylib.cpp -o ./app/libs/arm64-v8a/libmylib.so -fpic -shared
# x64 平台的
D:\DevSoft\AndroidSDK\ndk\24.0.8215888\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++ -target x86_64-linux-android21 ./app/src/main/jni/mylib.cpp -o ./app/libs/x86_64/libmylib.so -fpic -shared
# x86 平台的
D:\DevSoft\AndroidSDK\ndk\24.0.8215888\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++ -target i686-linux-android21 ./app/src/main/jni/mylib.cpp -o ./app/libs/x86/libmylib.so -fpic -shared
# arm32 平台的
D:\DevSoft\AndroidSDK\ndk\24.0.8215888\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++ -target armv7a-linux-androideabi21 ./app/src/main/jni/mylib.cpp -o ./app/libs/armeabi-v7a/libmylib.so -fpic -shared
-修改build.gradle配置文件
plugins {
id 'com.android.application'
}
android {
namespace 'org.eu.uiai.jnilearn'
compileSdk 32
defaultConfig {
applicationId "org.eu.uiai.jnilearn"
minSdk 28
targetSdk 32
versionCode 1
versionName "1.0"
//添加位置1 begin
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
externalNativeBuild {
cmake {
//为了解决找不到的问题 libc++_shared.so的问题
arguments "-DANDROID_STL=c++_shared"
}
}
//添加位置2 end
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
//添加位置2 begin
//为了解决找不到 libc++_shared.so 问题
externalNativeBuild {
cmake {
path "src/main/jni/CMakeLists.txt"
}
}
//添加位置2 end
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
- 缺少库的报错 由于默认的编译方式是最小化编译,动态库。我使用的 Android 模拟器没有库,导致 libc++_shared.so 报错,需要解决。其实可以直接通过CMake脚本编译目标so库的,但是我这里是模拟导入SO库,我要另外写一个Cpp文件和Cmake文件来解决找不到so的问题
java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
- 创建src/main/jni/CMakeLists.txt文件
cmake_minimum_required(VERSION 3.6.0)
add_library(help_lib_name SHARED help_lib.cpp)
- 创建帮助导入 libc++_shared.so 的cpp文件help_lib.cpp
# 空的,不用任何内容
评论区