Android 如何編譯和使用外部so文件

[TOC]

故事場景

android通常使用別人的輪子是直接依賴別人的aar,但是如果別人扔給你一個so和一個.h文件,我們需要如何使用,本工程將演示直接在ndk文件中鏈接so并在工程中使用。

編譯庫文件

工程結(jié)構(gòu)

image

hello.h

提供 libhello.so和對應(yīng)的.h文件 hello.h 如下

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

其中 HelloAdd方法實現(xiàn)了a+b的操作,接下來將調(diào)用此函數(shù)實現(xiàn)功能。

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)

此示例是演示了動態(tài)和靜態(tài)庫兩種編譯方式

編譯

模塊下有一個腳本cmake_build_all.sh,直接在終端執(zhí)行
cmake_build_all.sh libhello.so
則可輸出以下文件:

image

注意:cmake_build_all.sh腳本信賴于環(huán)境變量ANDROID_SDK_PATH的配置,比如:
export ANDROID_SDK_PATH=/Users/Shared/ShareLib/Android/sdk

使用庫文件

創(chuàng)建ndk工程

配置工程為cmake編譯

在應(yīng)用的build.gradle中配置

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

當前目錄創(chuàng)建CmakeLists.txt文件

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

在對應(yīng)的“src/main/cpp/jni”文件下再創(chuàng)建以下文件

image

其中CmakeLists.txt文件的內(nèi)容為

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

創(chuàng)建有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

創(chuàng)建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)

以上庫的連接文件是動態(tài)連接,意味著當前工程就包連接hello庫,也需要將hello庫打包在工程中,因此需要將庫文件拷貝到"src/main/jniLibs"目錄下,至此整個依賴關(guān)系可完成。

示例代碼

示例代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容