JNI-NDK(Linux平台使用NDK打包so库)

1、源文件

将以下简单的一个C程序打包成动态SO库提供给安卓使用。

  • 头文件
//
// Created by DELL on 2022/9/1.
//
#include 

#ifndef UNTITLED_DEMO_H
#define UNTITLED_DEMO_H

#endif //UNTITLED_DEMO_H

int testDemo();

  • 实现文件
//
// Created by DELL on 2022/9/1.
//
#include "demo.h"
int testDemo() {
    printf("Hello, Get World!\n");
    return 889;
}
int main(){
    testDemo();
}
#include 

int testStatic() {
    printf("Hello, Get World!\n");
    return 3333;
}

#include 

int get() {
    printf("Hello, Get World!\n");
    return 199;
}

2、Linux平台打SO动态库

(1)Linux平台下载安装NDK

wget https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip? hl=zh_cn

(2)重命名解压

修改成.zip mv android-ndk-r17c-linux-x86_64.zip?hl=zh_cn android-ndk-r17c-linux- x86_64.zip
解压unzip android-ndk-r17c-linux-x86_64.zip

(3)配置全局环境变量

vim /etc/profile

#配置NDK路径
export NDK="/root/NDK/tool/android-ndk-r17c"
#配置GCC
export NDK_GCC_x86="/root/NDK/tool/android-ndk-r17c/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-gcc"
export NDK_GCC_x64="/root/NDK/tool/android-ndk-r17c/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc"
export NDK_GCC_arm="/root/NDK/tool/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc"
export NDK_GCC_arm64="/root/NDK/tool/android-ndk-r17c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc"

#配置寻找库文件、头文件、asm
#arch-arm  arch-arm64  arch-mips64  arch-x86  arch-x86_64 

export NDK_CFIG_x86="--sysroot=/root/NDK/tool/android-ndk-r17c/platforms/android-21/arch-x86 -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include  -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include/i686-linux-android"
export NDK_CFIG_x64="--sysroot=/root/NDK/tool/android-ndk-r17c/platforms/android-21/arch-x86_64 -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include  -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include/x86_64-linux-android"
export NDK_CFIG_arm="--sysroot=/root/NDK/tool/android-ndk-r17c/platforms/android-21/arch-arm -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include  -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi"
export NDK_CFIG_arm64="--sysroot=/root/NDK/tool/android-ndk-r17c/platforms/android-21/arch-arm64 -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include  -isystem /root/NDK/tool/android-ndk-r17c/sysroot/usr/include/aarch64-linux-android"

#配置AR 用于打包静态库
export NDK_AR_x86="/root/NDK/tool/android-ndk-r17c/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-ar"
export NDK_AR_x64="/root/NDK/tool/android-ndk-r17c/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-ar"
export NDK_AR_arm="/root/NDK/tool/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar"
export NDK_AR_arm64="/root/NDK/tool/android-ndk-r17c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar"

image.png

(4)打动态so库

以上配置了四个平台、x86、x86_64、arm,arm64。使用相应的环境变量打包生成相应平台的so库。例如打x86平台的so执行如下:

$NDK_GCC_x86 $NDK_CFIG_x86 -fPIC -shared demo.c -o libdemo.so

因此四个平台打包的命令分别如下:

$NDK_GCC_x86 $NDK_CFIG_x86 -fPIC -shared demo.c -o libdemo.so
$NDK_GCC_x64 $NDK_CFIG_x64 -fPIC -shared test.c -o libtest.so
$NDK_GCC_arm $NDK_CFIG_arm -fPIC -shared test.c -o libtest.so
$NDK_GCC_arm64 $NDK_CFIG_arm64 -fPIC -shared test.c -o libtest.so

这样我们就生成了对于平台的so库。


image.png

(4)打静态a库

#打包静态库
$NDK_GCC_x86 $NDK_CFIG_x86 -fPIC -c static.c -o libstatic.o
$NDK_AR_x86 rcs -o  libstatic.a  libstatic.o
image.png

3、动态so库、静态a库集成到Android环境

(1)将so库集成到jnilibs中

image.png

(2)将静态a库集成as中

image.png

(3)配置Cmake

#cmake_minimum_required(VERSION 3.4.1) # 最低支持Cmake版本

cmake_minimum_required(VERSION 3.10.2)# 最低支持Cmake版本
# Declares and names the project.
project("jni_02")

#NDK集成C库流程
#1、导入C库头文件 inc
include_directories("inc")

#2、配置总库,也就是最终打包到APK里的库
file(GLOB allCPP *.c *.h *.cpp)
add_library(
        native-lib # Sets the name of the library 给最终打包到APK的C库起名称 native-lib
        SHARED # Sets the library as a shared library.//设置库为动态共享库
        ${allCPP} # Provides a relative path to your source file(s).//导入所有源文件
)
#导入静态库【第二方式】 可读性更强,代码多
add_library(static STATIC IMPORTED)
set_target_properties(static PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libstatic.a)

# 导入动态库 【第二方式】 可读性更强,代码多
#add_library(getndk SHARED IMPORTED)
#set_target_properties(getndk PROPERTIES
        #IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libgetndk.so)

#导入动态库 【第一种方式】简单,不易理解 ,CMAKE_ANDROID_ARCH_ABI会自动匹配当前的CPU架构,
    ##设置so文件夹
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")



#这种方式是一个个添加
#add_library( # Sets the name of the library.
#        jni_01
#        # Sets the library as a shared library.
#        SHARED
#        # Provides a relative path to your source file(s).
#        native-lib.cpp extern-lib.cpp)

#4、链接具体的库,到我们的 libnative-lib.so总库
target_link_libraries(
        native-lib
        #${log-varAAAA}
        log # 自动寻找  # 具体的库 链接到 libnative-lib.so里面去
        fmod # 具体的库 链接到 libnative-lib.so里面去
        fmodL # 具体的库 链接到 libnative-lib.so里面去
        test # 具体的库 链接到 libnative-lib.so里面去
        demo # 具体的库 链接到 libnative-lib.so里面去
        static # 具体的库 链接到 libnative-lib.so里面去
)



(3)配置Gadle

image.png

(4)测试

  • 初始化加载lib
  static {
        System.loadLibrary("native-lib");
        System.loadLibrary("test");
        System.loadLibrary("demo");
    }
  • JNI测试
 binding.btnMySo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testMySo();
            }
        });
    native void testMySo();
// 我先声明 int get(),运行后,你自己去找 实现(libtest.so 库里面的实现),如果找不到报错
extern "C" { // 由于库 是C编写的,必须采用C的编译方式
extern int get();
}
extern "C" { // 由于库 是C编写的,必须采用C的编译方式
extern int testDemo();
}
extern "C" { // 由于库 是C编写的,必须采用C的编译方式
extern int testStatic();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_it_jni_102_MainActivity_testMySo(JNIEnv *env, jobject thiz) {
    LOGD("test my so")
    jint  result = testDemo();
    jint  result2 = get();
    jint  result3 = testStatic();
    LOGD("testDemo value is %d",result);
    LOGD("get value is %d",result2);
    LOGD("testStatic value is %d",result3);

}
2022-09-01 14:34:09.596 4375-4375/com.it.jni_02 D/Native: test my so
2022-09-01 14:34:09.596 4375-4375/com.it.jni_02 D/Native: testDemo value is 889
2022-09-01 14:34:09.596 4375-4375/com.it.jni_02 D/Native: get value is 199
2022-09-01 14:34:09.596 4375-4375/com.it.jni_02 D/Native: testStatic value is 3333

你可能感兴趣的:(JNI-NDK(Linux平台使用NDK打包so库))