在 Android 模块中编写 JNI 模块来调用第三方的 .so
文件,可以使用 NDK Build (老项目)或 CMake 两种方式。以下是详细的操作步骤:
使用 NDK Build
1. 创建 JNI 目录结构
在你的 Android 模块中创建一个 jni
目录,并在其中创建 Android.mk
和 Application.mk
文件。
CppApp/
├── app/
│ ├── src/
│ ├── cpp/
│ └── jni-ndk-build/
│ ├── Android.mk
│ ├── Application.mk
│ └── native.cpp
2. 编写 Android.mk 文件
在 jni/Android.mk
文件中定义你的模块和第三方库:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := cppapp
LOCAL_SRC_FILES := native.cpp
#如果三方库需要被编译
#LOCAL_SHARED_LIBRARIES := third_party_lib # 这里是你的第三方.so库名称
#include $(CLEAR_VARS)
#LOCAL_MODULE := third_party_lib
#LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libthird_party.so # 第三方库的位置
#include $(PREBUILT_SHARED_LIBRARY)
#设置三方库的搜索路径,LOCAL_PATH:Android.mk所在位置
#THIRD_PART_LIBS_PATH := $(LOCAL_PATH)/../../jniLibs/$(TARGET_ARCH_ABI)
LOCAL_LDLIBS += -llog #(如果有三方库)-L$(THIRD_PART_LIBS_PATH) -lfmod -lfmodL
include $(BUILD_SHARED_LIBRARY)
3. 编写 Application.mk 文件
在 jni/Application.mk
文件中指定编译的目标架构和应用设置:
APP_PLATFORM := android-21
APP_STL := c++_shared
4. 编写你的 JNI 代码
在 jni/native.cpp
文件中编写你的 JNI 代码:
#include "native.h"
#include <jni.h>
#include <string>
#include <iostream>
#include <android/log.h>
#define TAG "NativeProcess"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_hfengxiang_cppapp_NativeProcess_call(JNIEnv *env, jobject thiz) {
// TODO: implement call()
jclass cls = env->GetObjectClass(thiz);
jmethodID jmtId = env->GetMethodID(cls,"toString", "()Ljava/lang/String;");
jstring jstr = static_cast<jstring>(env->CallObjectMethod(thiz, jmtId));
const char * cstr = env->GetStringUTFChars(jstr,NULL);
LOGD("caller is %s",cstr);
}
5. 在项目中使用 JNI
在你的 build.gradle
文件中配置 NDK 支持:
android {
...
externalNativeBuild {
ndkBuild {
path file("src/main/cpp/jni/Android.mk")
}
}
}
在 Java 代码中加载 JNI 库并调用本地方法:
package com.hfengxiang.cppapp;
public class NativeProcess {
static {
System.loadLibrary("cppapp");
}
public native void call();
}
package com.hfengxiang.cppapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NativeProcess process = new NativeProcess();
process.call();
}
}
使用 CMake
1. 创建 CMake 目录结构
在你的 Android 模块中创建一个 cpp
目录,并在其中创建 CMakeLists.txt
文件和你的 JNI 代码文件:
CppApp/
├── app/
│ ├── src/
│ ├── cpp/
│ └── jni-cmake/
│ ├── Android.mk
│ ├── Application.mk
│ └── native.cpp
2. 编写 CMakeLists.txt 文件
在 cpp/CMakeLists.txt
文件中定义你的模块和第三方库:
cmake_minimum_required(VERSION 3.22.1)
# 指定你的本地库名
add_library( # Sets the name of the library.
cppapp
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native.cpp)
# 引入log库
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# 引入第三方库
#add_library( third_party_lib SHARED IMPORTED )
#set_target_properties( third_party_lib PROPERTIES IMPORTED_LOCATION #${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libthird_party.so )
# 链接库
target_link_libraries( # Specifies the target library.
cppapp
# Links the target library to the log library
# included in the NDK.
${log-lib}
#third_party_lib
)
3. 编写你的 JNI 代码
在 native.cpp
文件中编写你的 JNI 代码:
#include "native.h"
#include <jni.h>
#include <string>
#include <iostream>
#include <android/log.h>
#define TAG "NativeProcess"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
extern "C"
JNIEXPORT void JNICALL
Java_com_hfengxiang_cppapp_NativeProcess_call(JNIEnv *env, jobject thiz) {
// TODO: implement call()
jclass cls = env->GetObjectClass(thiz);
jmethodID jmtId = env->GetMethodID(cls,"toString", "()Ljava/lang/String;");
jstring jstr = static_cast<jstring>(env->CallObjectMethod(thiz, jmtId));
const char * cstr = env->GetStringUTFChars(jstr,NULL);
LOGD("caller is %s",cstr);
}
4. 在项目中使用 JNI
在项目下的 build.gradle
文件中配置 CMake 支持:
android {
...
externalNativeBuild {
cmake {
path file("src/main/cpp/jni-cmake/CMakeLists.txt")
}
}
}
在 Java 代码中加载 JNI 库并调用本地方法:
package com.hfengxiang.cppapp;
public class NativeProcess {
static {
System.loadLibrary("cppapp");
}
public native void call();
}
package com.hfengxiang.cppapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NativeProcess process = new NativeProcess();
process.call();
}
}
附头文件生产方式
1. 配置JDK环境变量
2.执行命令
javac -h E:\WorkSpace\Projects\CppApp\app\src\main\java\com\hfengxiang\cppapp -encoding utf-8 E:\WorkSpace\Projects\CppApp\app\src\main\java\com\hfengxiang\cppapp\NativeProcess.java
(jdk1.8以及之前的版本用javah)
3.配置自定义命名
Program:D:\Program Files (x86)\Develop\AndroidStdio\android-studio-2023.3.1.18-windows\jbr\bin\javac.exe(javac命令所在位置)
Arguments:-h $FileDir$ -encoding utf-8 $FilePath$(命令参数)
Working directory:D:\Program Files (x86)\Develop\AndroidStdio\android-studio-2023.3.1.18-windows\jbr\bin (暂不清楚含义)
com_hfengxiang_cppapp_NativeProcess.h(可重命名)
#ifndef _Included_com_hfengxiang_cppapp_NativeProcess
#define _Included_com_hfengxiang_cppapp_NativeProcess
#ifdef __cplusplus
/*
* Class: com_hfengxiang_cppapp_NativeProcess
* Method: call
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_hfengxiang_cppapp_NativeProcess_call
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif