您现在的位置是:网站首页> Android
Android中Java与C++交互及库开发与使用
- Android
- 2025-06-15
- 845人已阅读
Android中Java与C++交互及库开发与使用
库开发使用
常见问题
简单理理AndroidStudio 生成SO并调用
工程结构如下
文件结构如下:
在调用的地方定义在 MainActivity类里
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
public native String stringFromJNI();
...
}
在native-lib.cpp中实现
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_xn_helloso_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
函数名称就是Java+包地址+类+函数名
编译需要在module下的build.gradle文件里加
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
生成的so动态库在:app\build\intermediates\cmake\debug\obj
CMakeLists.txt文件内容
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
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 )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
AndroidStudio引用第三方so库的正确姿势
1、把so文件复制到 \app1\app\libs\ 文件夹下,但是要注意,so文件是放在对应的平台文件夹之下(如arm64-v8a,armeabi-v7a, x86,x86_64),这点非常重要,否则不能成功引用,每个平台文件夹下都放上该so文件,如下图:
2、AndroidStudio打开项目,并切换到 Android 栏,并打开Gradle Scripts\build.gradle(Module:app1.app) ,加入 节点
sourceSets{
main{
jniLibs.srcDirs "libs"
}
}
如下图:
3、加完之后,有一个刷新(同步)的操作 ,之后在app下就可以看到jniLibs文件夹,如下:
通过JNI定义实现调用第三方库so如上面的native-lib.cpp文件
Android引用jar和so
其实jni、jniLibs一个是C++源码提供一个是C++编译成so提供,libs、java一个是以Java编译的jar,一个是以Java代码提供
ModuleAPI.c
#include <jni.h>
#include <ModuleAPI.h>
#include <Logger.h>
#include <SerialPort.h>
#include <jni.h>
static const char *TAG = "ModuleAPI";
//#define MSG_CRC_INIT 0xFFFF
//#define MSG_CCITT_CRC_POLY 0x1021
//void CRC_calcCrc8(uint16_t *crcReg, uint16_t poly, uint16_t u8Data)
//{
// uint16_t i;
// uint16_t xorFlag;
// uint16_t bit;
// uint16_t dcdBitMask = 0x80;
// for(i=0; i<8; i++)
// {
// xorFlag = *crcReg & 0x8000;
// *crcReg <<= 1;
// bit = ((u8Data & dcdBitMask) == dcdBitMask);
// *crcReg |= bit;
// if(xorFlag)
// {
// *crcReg = *crcReg ^ poly;
// }
// dcdBitMask >>= 1;
// }
//}
//
//uint16_t CalcCRC(uint8_t *msgbuf,uint8_t msglen)
//{
// uint16_t calcCrc = MSG_CRC_INIT;
// uint8_t i;
// for (i = 1; i < msglen; ++i)
// CRC_calcCrc8(&calcCrc, MSG_CCITT_CRC_POLY, msgbuf[i]);
// return calcCrc;
//}
#define MSG_CRC_INIT 0xFFFF
#define MSG_CCITT_CRC_POLY 0x1021
#define uint16 unsigned short
#define uint8 unsigned char
void CRC_calcCrc8(uint16 *crcReg, uint16 poly, uint16 u8Data) {
uint16 i;
uint16 xorFlag;
uint16 bit;
uint16 dcdBitMask = 0x80;
for (i = 0; i < 8; i++) {
xorFlag = *crcReg & 0x8000;
*crcReg <<= 1;
bit = ((u8Data & dcdBitMask) == dcdBitMask);
*crcReg |= bit;
if (xorFlag) {
*crcReg = *crcReg ^ poly;
}
dcdBitMask >>= 1;
}
}
uint16 CalcCRC(uint8 *msgbuf, uint8 msglen) {
uint16 calcCrc = MSG_CRC_INIT;
uint8 i;
for (i = 0; i < msglen; ++i)
CRC_calcCrc8(&calcCrc, MSG_CCITT_CRC_POLY, msgbuf[i]);
return calcCrc;
}
JNIEXPORT jint JNICALL Java_com_xlzn_hcpda_ModuleAPI_SerailOpen(JNIEnv* env, jobject thiz, jstring juart,jint baudrate, jint databits,jint stopbits, jint check) {
jboolean iscopy;
LOGD(TAG, "Java_com_xlzn_hcpda_ModuleAPI_SerailOpen");
const char *path_uart = (*env)->GetStringUTFChars(env, juart, &iscopy);
int result= SerialPort_Open(path_uart, baudrate, databits, stopbits, check);
(*env)->ReleaseStringUTFChars(env, juart, path_uart);
return result;
return 0;
}
JNIEXPORT jint JNICALL Java_com_xlzn_hcpda_ModuleAPI_SerailClose(JNIEnv *env, jobject thiz,int uart_fd) {
int result= SerialPort_Close(uart_fd);
return result;
}
JNIEXPORT jint JNICALL Java_com_xlzn_hcpda_ModuleAPI_SerailSendData(JNIEnv *env, jobject thiz, int uart_fd,jbyteArray send_data,int sendLen) {
unsigned char uData[sendLen];
jbyte *jpszData = (*env)->GetByteArrayElements(env, send_data, 0);
for (int i = 0; i < sendLen; i++) {
uData[i] = jpszData[i];
}
int reuslt= SerialPort_Send(uData,sendLen,uart_fd);
(*env)->ReleaseByteArrayElements(env, send_data , jpszData, 0);
return reuslt;
}
JNIEXPORT jint JNICALL Java_com_xlzn_hcpda_ModuleAPI_SerailReceive(JNIEnv *env, jobject thiz, jint uart_fd,jbyteArray receive_data,int receive_dataLen) {
unsigned char uData[receive_dataLen];
int reuslt= SerialPort_Receive(uData,receive_dataLen,uart_fd);
if(reuslt>0){
jbyte *jpszData = (*env)->GetByteArrayElements(env, receive_data, 0);
for (int i = 0; i < reuslt; i++) {
jpszData[i] = uData[i];
}
(*env)->ReleaseByteArrayElements(env, receive_data , jpszData, 0);
}
return reuslt;
}
JNIEXPORT jint JNICALL Java_com_xlzn_hcpda_ModuleAPI_CalcCRC(JNIEnv *env, jobject thiz, jbyteArray jdata, jint data_len,jbyteArray jout_crc){
jbyte *jpszData = (*env)->GetByteArrayElements(env, jdata, 0);
jbyte *outData = (*env)->GetByteArrayElements(env, jout_crc, 0);
uint16_t result=CalcCRC(jpszData,data_len);
outData[0]=result>>8;
outData[1]=result&0xFF;
(*env)->ReleaseByteArrayElements(env, jdata , jpszData, 0);
(*env)->ReleaseByteArrayElements(env, jout_crc , outData, 0);
return 0;
}
ModuleAPI.java
package com.xlzn.hcpda;
public class ModuleAPI {
private static ModuleAPI moduleAPI=new ModuleAPI();
private ModuleAPI(){}
public static ModuleAPI getInstance(){
return moduleAPI;
}
static {
System.loadLibrary("ModuleAPI");
}
public native int SerailOpen(String uart, int baudrate, int databits, int stopbits, int parity);
public native int SerailClose(int uart_fd);
public native int SerailSendData(int uart_fd,byte[] sendData,int sendLen);
public native int SerailReceive(int uart_fd,byte[] receiveData,int receiveDataLen);
public native int CalcCRC(byte[] data,int dataLen,byte[] outCrc);
public static int getVersionCode = BuildConfig.API_VERSION;
}
build.gradle设置相关内容:
plugins {
id 'com.android.library'
}
android {
compileSdkVersion 31
buildToolsVersion "30.0.3"
defaultConfig {
minSdkVersion 21
targetSdkVersion 31
versionCode 16
versionName "2.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
externalNativeBuild {
cmake {
abiFilters "armeabi-v7a" //abi体系结构下的so库
}
}
}
signingConfigs {
debug {
File strFile = new File("/android.keystore")
storeFile file(strFile)
storePassword "123456"
keyPassword "123456"
keyAlias "keyAlias"
}
release {
File strFile = new File("/release.jks")
storeFile file(strFile)
storePassword "123456"
keyPassword "123456"
keyAlias "keyAlias"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
android.libraryVariants.all { variant ->
variant.outputs.all {
outputFileName = "HCUHF_${versionCodeA()}_${releaseTime()}.aar"
}
}
buildConfigField("int", "API_VERSION", "${releaseTime()}")
}
debug {
signingConfig signingConfigs.debug
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("int", "API_VERSION", "${releaseTime()}")
}
}
sourceSets {
main {
jni.srcDirs = ['src/main/jni']
jniLibs.srcDirs = ['src/main/jni/libs']
java.srcDirs = ['src/main/java']
}
}
externalNativeBuild {
cmake {
path file('src/main/jni/CMakeLists.txt')
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation files('libs\\classes.jar')
implementation files('libs\\jxl.jar')
implementation files('libs\\xUtils-2.5.5.jar')
implementation files('libs\\classes.jar')
}
static def releaseTime() {
new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08:00"))
}
static def versionName() {
"\"v1.0.7\""
}
static def versionCodeA() {
"v1.0.7"
}
CMakeLists.txt内容
cmake_minimum_required (VERSION 3.4.1)
project(ModuleAPI)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/inc")
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
)
add_library(
ModuleAPI
SHARED
${SRC_LIST}
)
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 )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
ModuleAPI
# Links the target library to the log library
# included in the NDK.
${log-lib} )
Android打aar没有包含so的解决办法
引言
在Android开发中,我们常常会将一些功能封装成库文件(aar)进行使用。然而有时候在打aar包时,可能会遇到一种情况:aar文件中没有包含.so文件。这时候我们需要告诉刚入行的小白如何解决这个问题。
解决方案概述
解决这个问题的基本思路是,在打aar包时将.so文件也打包进去。下面是整个解决方案的流程图:
开始
创建Android Library工程
在工程的main目录下创建jniLibs目录
将.so文件复制到jniLibs目录下
在工程的build.gradle文件中添加ndk配置
编译并打包aar
结束
下面我们将逐步解释每一步需要做什么。
步骤详解
1. 创建Android Library工程
首先,在Android Studio中创建一个新的Android Library工程。
2. 创建jniLibs目录
在工程的main目录下创建一个名为jniLibs的目录。这个目录将用于存放.so文件。
3. 复制.so文件
将需要打包的.so文件复制到jniLibs目录下。注意,如果有多个.so文件,都需要复制到该目录下。
4. 添加ndk配置
在工程的build.gradle文件中添加ndk的配置。具体的代码如下所示:
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
...
}
这段代码的作用是告诉Android Studio,要将jniLibs目录作为so库的来源。
5. 编译并打包aar
最后,编译并打包aar。可以通过在终端执行以下命令来实现:
./gradlew assembleRelease
这将在工程的build/outputs/aar目录下生成一个aar文件。
至此,我们完成了解决方案的所有步骤。
总结
本文介绍了解决Android打aar没有包含.so文件的问题的详细步骤。通过创建jniLibs目录,将.so文件复制到该目录下,并在build.gradle文件中添加ndk配置,最终成功编译并打包出包含.so文件的aar。希望本文对刚入行的小白有所帮助。
(以上为所需代码,请用“行内代码”的markdown语法标识出来)
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
...
}
./gradlew assembleRelease
上一篇:Android快速回顾
下一篇:Android同行者