style.png
在使用 CMake 编译 so 之前,需要配置 NDK 环境,
Mac 用户可以参考
window 用户参考
在 Android studio 中新建项目
我的是 Android studio 3.0 版本,官方在新建项目时已经提供对c++的支持,以方便我们开发者更好的使用JNI开发项目。记得勾选 Include C++ support 选项。
新建项目.png
和普通 Android 项目的区别
项目结构.png① 会发现多了一个 CMakeLists.txt 文件和 .externalNativeBuild 文件夹。
- CMakeLists.txt 相当于 CMake 的配置文件
- .externalNativeBuild 是自动生成的构建脚本
② main 文件夹下多了一个 cpp 文件夹,里面用来放置 C/C++ 代码
image.png
③ build..gradle 文件中会有一些修改,新增了一些配置
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.muxiaolei.helei.jnitest"
minSdkVersion 14
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//新增
externalNativeBuild {
cmake {
//配置参数
cppFlags ""
//设置生成指定 ABI 版本的 so 库
abiFilters 'armeabi-v7a', 'armeabi'
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//新增
externalNativeBuild {
cmake {
//配置文件路径
path "CMakeLists.txt"
}
}
}
简单项目分析
接下来我们拿一个实现两数相加的小项目进行分析
使用 CMake 编译生成 so 文件并 JNI native 调用,我们大致需要配置
- CMakeLists.txt 文件修改
- 编写 .c/.cpp 文件
- 编写 .c/.cpp 文件对应的 java native 方法
- 修改 build.gradle 中 externalNativeBuild 闭包中配置
- System.loadLibrary 加载 so 库
- Android 端功能调用
先看看配置文件 CMakeLists.txt 内容,设置了 so 文件的输出路径,编译成功后最终会在src/main/jniLibs/ 下生成 so 文件,生成的文件个数根据 abiFilters 指定的 ABI 类型
#要求的最低版本
cmake_minimum_required(VERSION 3.4.1)
#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
#添加库
add_library( calculate
SHARED
#calculate.c的路径
src/main/cpp/calculate.c )
find_library( log-lib
log )
#链接库
target_link_libraries( calculate
${log-lib} )
calculate.c 源文件代码,
#include "calculate.h"
#include <jni.h>
#include <android/log.h>
#define TAG "myhello-jni-test" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型
JNIEXPORT jint
JNICALL Java_com_muxiaolei_helei_util_NativeHelper_calculateSum(
JNIEnv *env, jclass type, jint numberOne, jint numberTwo) {
LOGD("numberOne-----------", numberOne);
LOGD("numberTwo-----------", numberTwo);
return numberOne + numberTwo;
}
对应的 java 本地 native 方法代码
public class NativeHelper {
static {
System.loadLibrary("calculate");
}
private NativeHelper(){
//not allow create instance
}
//计算两个数之和
public static native int calculateSum(int number, int other);
}
功能调用代码
String numberOne = et_first_number.getText().toString().trim();
String numberSecond = et_second_number.getText().toString().trim();
if(TextUtils.isEmpty(numberOne)) {
Toast.makeText(this, "请输入第一个加数", Toast.LENGTH_SHORT).show();
return;
}
if(TextUtils.isEmpty(numberSecond)) {
Toast.makeText(this, "请输入第二个加数", Toast.LENGTH_SHORT).show();
return;
}
int result = NativeHelper.calculateSum(Integer.parseInt(numberOne), Integer.parseInt(numberSecond));
tv_result_sum.setText(String.valueOf(result));
如果遇上错误
Error:Execution failed for task ':app:transformNativeLibsWithMergeJniLibsForDebug'.
> More than one file was found with OS independent path 'lib/armeabi-v7a/libcompress.so'
在 build.gradle 中加入(pickFirst 的个数和 abiFilters 指定的 ABI 对应)
packagingOptions {
pickFirst 'lib/armeabi-v7a/libcalculate.so'
pickFirst 'lib/armeabi/libcalculate.so'
pickFirst 'lib/x86/libcalculate.so'
}
放上效果图,很简陋,😆
结果.png项目源码已经上传到 github,戳我查看源码
网友评论