美文网首页
Android 如何编译和使用外部so文件

Android 如何编译和使用外部so文件

作者: 茶不思基 | 来源:发表于2020-02-16 22:54 被阅读0次

    [TOC]

    故事场景

    android通常使用别人的轮子是直接依赖别人的aar,但是如果别人扔给你一个so和一个.h文件,我们需要如何使用,本工程将演示直接在ndk文件中链接so并在工程中使用。

    编译库文件

    工程结构

    image

    hello.h

    提供 libhello.so和对应的.h文件 hello.h 如下

    #ifndef HELLO_H 
    #define HELLO_H 
    #include <stdio.h> 
    int HelloAdd(int a,int b);
    #endif
    

    其中 HelloAdd方法实现了a+b的操作,接下来将调用此函数实现功能。

    hello.cpp

    #include "hello.h"
    int HelloAdd(int a,int b)
    {
         int result=a+b;
         printf("HelloAdd:result=%d \n",result);
         return result;
    }
    

    CmakeLists.txt

    SET(LIBHELLO_SRC hello.cpp)
    
    ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
    SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
    
    ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
    SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
    SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    
    INSTALL(TARGETS hello hello_static
            LIBRARY DESTINATION lib
            ARCHIVE DESTINATION lib)
    INSTALL(FILES hello.h DESTINATION include/hello)
    

    此示例是演示了动态和静态库两种编译方式

    编译

    模块下有一个脚本cmake_build_all.sh,直接在终端执行
    cmake_build_all.sh libhello.so
    则可输出以下文件:

    image

    注意:cmake_build_all.sh脚本信赖于环境变量ANDROID_SDK_PATH的配置,比如:
    export ANDROID_SDK_PATH=/Users/Shared/ShareLib/Android/sdk

    使用库文件

    创建ndk工程

    配置工程为cmake编译

    在应用的build.gradle中配置

    externalNativeBuild {
            cmake {
                path 'CMakeLists.txt'
            }
        }
    

    当前目录创建CmakeLists.txt文件

    cmake_minimum_required(VERSION 3.4.1)
    add_subdirectory(src/main/cpp/jni)
    

    在对应的“src/main/cpp/jni”文件下再创建以下文件

    image

    其中CmakeLists.txt文件的内容为

    cmake_minimum_required(VERSION 3.4.1)
    add_library(math_test SHARED math_test.cc)
    

    创建有native方法的java类MathTest

    package com.sen.ndk.buildexternso;
    public class MathTest {
    
        public static native int add(int a, int b);
    
        static {
            System.loadLibrary("math_test");
        }
    }
    

    因此需要定义Java_com_sen_ndk_buildexternso_MathTest_add方法

    定义math_test.h文件

    #ifndef BUILDEXTERNSO_MATH_TEST_H
    #define BUILDEXTERNSO_MATH_TEST_H
    #include <jni.h>
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    JNIEXPORT jint JNICALL Java_com_sen_ndk_buildexternso_MathTest_add
        (JNIEnv *, jobject, jint, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif //BUILDEXTERNSO_MATH_TEST_H
    
    

    创建math_test.cc文件,目前还未使用so,直接返回相加值可测试工程运行

    
    #include "math_test.h"
    
    JNIEXPORT jint JNICALL Java_com_sen_ndk_buildexternso_MathTest_add
        (JNIEnv * env, jobject jo, jint a, jint b){
    
      return a+b;
    }
    
    
    

    使用hello.so文件

    拷贝hello.h文件

    #ifndef HELLO_H 
    #define HELLO_H 
    #include <stdio.h> 
    extern int HelloAdd(int a,int b); 
    #endif
    

    更新main.cpp

    #include "hello.h"
    int HelloAdd(int a,int b)
    {
         int result=a+b;
         printf("HelloAdd:result=%d \n",result);
         return result;
    }
    

    更新cmake文件

    cmake_minimum_required(VERSION 3.4.1)
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
    
    
    add_library(hello SHARED IMPORTED)
    set_target_properties(hello PROPERTIES IMPORTED_LOCATION
            ${PROJECT_LIBS_DIR}/${ANDROID_ABI}/libhello.so)
    
    add_library(math_test SHARED math_test.cc)
    target_include_directories(math_test PUBLIC ${hello_INCLUDE})
    TARGET_LINK_LIBRARIES(math_test hello)
    

    以上库的连接文件是动态连接,意味着当前工程就包连接hello库,也需要将hello库打包在工程中,因此需要将库文件拷贝到"src/main/jniLibs"目录下,至此整个依赖关系可完成。

    示例代码

    示例代码

    相关文章

      网友评论

          本文标题:Android 如何编译和使用外部so文件

          本文链接:https://www.haomeiwen.com/subject/yekvfhtx.html