文章目录
- 1、简介
- 2、先编译出一个第三方非标准so库
- 1)android studio 新创建一个项目
- 2) main 新创建 jni 文件夹
- 3) 新建 .cpp 文件和 .h 实现 求和功能
- 4)、编写 CMakeLists.txt 用来编译 cpp 文件到so
- 5)配置编译环境
- 6)、编译第三方 非标准 库
- 3、新项目 引用第三方 so 库
- 1)新建 android studio 项目
- 2)新建 java 类,封装想要调用的接口函数
- 3)Main 文件夹新建 jniLibs 文件夹
- 4)创建 对应的 jni java 类 文件的 头文件
- 5) main 文件夹 下新建 jni文件夹,实现底层逻辑
- 6) 配置环境
- 7) 编写 自己 so 库的 CMakeLists.txt 文件
- 8 ) 编译自己的标so 库
- 9) 主函数调用测试
1、简介
当我们调用别人的非标准的 jni so 库,无法使用 jni 标准接口的时候。我们需要采用间接的方式调用。
(1)比如现在我们有第三方给的 libnative.so 库,无法自己直接 jni 调用
(2)我们自己用 c/c++ 创建一个标准的so 库,比如 mynative.so
(3) 然后用我们自己的mynative.so 库中去调用第三方的libnative.so库
(4) 然后 我们在上层 调用我们自己的mynativeso 库 ,就实现了对第三方 libnativeso 库 方法的调用。
这种方式 我们要先有第三方 的 so 库 和编译库 对应的头文件
2、先编译出一个第三方非标准so库
1)android studio 新创建一个项目
我们先制作一个非标准 jni 库,只要功能实现两个 数相加 ,并返回
2) main 新创建 jni 文件夹
3) 新建 .cpp 文件和 .h 实现 求和功能
test.cpp
//
// Created by lum on 20-8-8.
//
#include "test.h"
Add::Add(){}
Add::~Add(){}
int Add::add(int x, int y){
return x + y;
}
test.h
#ifndef _TEST_JNI_ADD_H_
#define _TEST_JNI_ADD_H_
class Add{
public :
Add();
~Add();
int add(int x, int y);
};
#endif
4)、编写 CMakeLists.txt 用来编译 cpp 文件到so
在 app 文件下 新建 CMakeLists.txt 文件
#指定cmake最小版本
cmake_minimum_required(VERSION 3.4.1)
#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
#生成so
add_library( # 设置生成库的名字
nativeso
# 生成动态库
SHARED
# 指定源码文件,这里指定test.cpp文件
src/main/jni/test.cpp )
#依赖的头文件
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src/main/jni)
find_library( # log库的别名
log-lib
#log库
log )
#链接代码到指定的库
target_link_libraries( # Specifies the target library.
nativeso
# Links the target library to the log library
# included in the NDK.
${log-lib} )
5)配置编译环境
(1)配置 sdk tool 里 CMake NDK
(2)配置 build.gradle(:app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.1"
defaultConfig {
applicationId "com.example.myjni"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// 添加
externalNativeBuild {
cmake {
cppFlags ""
}
}
//添加
ndk {
abiFilters 'arm64-v8a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
//添加
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
//添加
packagingOptions {//加上这些代码
pickFirst 'lib/armeabi-v7a/libnativeso.so'
pickFirst 'lib/armeabi-v8a/libnativeso.so'
pickFirst 'lib/arm64-v8a/libnativeso.so'
pickFirst 'lib/x86/libnativeso.so'
pickFirst 'lib/x86_64/libnativeso.so'
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
(3)配置 gradle.properties
添加
android.useDeprecatedNdk=true
(4)配置好 ndk 路径
6)、编译第三方 非标准 库
点击 途中 绿色小锤子 按钮
然后就会编译出我们要的so 库
3、新项目 引用第三方 so 库
1)新建 android studio 项目
2)新建 java 类,封装想要调用的接口函数
package com.example.myjninative;
public class JniCallNative {
static {
System.loadLibrary("mynativeso");
}
public static native int getAddFromNative(int a,int b);
}
3)Main 文件夹新建 jniLibs 文件夹
(1) main 文件夹 新建 jniLibs 文件夹
(2)jniLibs 文件夹 新建so库 对应架构文件夹
(3)拷贝 第三方 so 库 到对应架构文件夹下
4)创建 对应的 jni java 类 文件的 头文件
android studio 命令行切换到 java 目录
执行javah -jni + 类文件包名 + 类名
生成 .h 文件
javah -jni com.example.myjninative.JniCallNative
我们可以在 java 目录生成 对应 .h 文件
com_example_myjninative_JniCallNative.h 文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_myjninative_JniCallNative */
#ifndef _Included_com_example_myjninative_JniCallNative
#define _Included_com_example_myjninative_JniCallNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_myjninative_JniCallNative
* Method: getAddFromNative
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_myjninative_JniCallNative_getAddFromNative
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
5) main 文件夹 下新建 jni文件夹,实现底层逻辑
(1)将上一步 生成 .h 文件 拷贝进来
(2)根据.h 文件 编写 对应的 .cpp 文件 ,在cpp 文件里实现对 第三方 so 库 的引用
(3)将第三方 so 库里用到的 头文件 拷贝进来
jninative.cpp 文件
里面实现对第三方 so 库 方法的引用
//
// Created by lum on 20-8-8.
//
#include <jni.h>
#include <string>
#include <test.h>//导入需要的.h文件,这个是必须的,如果依赖的第三方库没有.h,需要自己编写
extern "C"
JNIEXPORT jint JNICALL Java_com_example_myjninative_JniCallNative_getAddFromNative
(JNIEnv *, jclass, jint a, jint b){
//生成add对象并调用方法
Add addObj;
int result = addObj.add(a,b);
return result;
}
test.h
第三方 库 里的 使用的头文件
#ifndef _TEST_JNI_ADD_H_
#define _TEST_JNI_ADD_H_
class Add{
public :
Add();
~Add();
int add(int x, int y);
};
#endif
6) 配置环境
同上
build.gradle(app )多添加 一段
7) 编写 自己 so 库的 CMakeLists.txt 文件
app 文件下新建 CMakeLists.txt
#指定cmake最小版本
cmake_minimum_required(VERSION 3.4.1)
#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
#生成so
add_library( # 设置生成库的名字
mynativeso
# 生成动态库
SHARED
# 指定源码文件,这里指定test.cpp文件
src/main/jni/jninative.cpp )
#依赖的头文件
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src/main/jni)
#依赖的add库
add_library(nativeso SHARED IMPORTED)
set_target_properties(nativeso
PROPERTIES IMPORTED_LOCATION
${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libnativeso.so)
find_library( # log库的别名
log-lib
#log库
log )
#链接代码到指定的库
target_link_libraries( # Specifies the target library.
mynativeso
#add库需要链接
nativeso
# Links the target library to the log library
# included in the NDK.
${log-lib} )
8 ) 编译自己的标so 库
点击 绿色小锤子
看到 jniLibs 下多了自己的 so 库
9) 主函数调用测试
主函数添加 调用 jni 上层 java 接口的函数
编译 apk 测试运行
发现自己的 java 上层 可以调用到第三方 的 so 库 里加法函数