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,戳我查看源碼