NDK交叉編譯及so庫導(dǎo)入Android項(xiàng)目

個(gè)人博客

http://www.milovetingting.cn

前言

記錄NDK交叉編譯及so庫導(dǎo)入Android項(xiàng)目的簡單步驟,以備后續(xù)用到時(shí)查看。

環(huán)境

在Linux和Mac環(huán)境下,分別編譯輸出so庫。

Red Hat Enterprise Linux 8 64 位 使用GCC編譯(也可以用CLANG,這里演示用GCC)

macOS Big Sur 11.3.1 使用CLANG編譯(也可以用GCC,這里演示用CLANG)

下載NDK

這里只演示下載NDK17,項(xiàng)目中Mac用到的NDK版本為NDK21

下載NDK

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

NDK18及之后的NDK版本,建議使用CLANG編譯。

解壓NDK

unzip android-ndk-r17c-linux-x86_64.zip

解壓后得到android-ndk-r17c文件夾

編寫頭文件及c文件

GCC編譯

#include "get.h"

int get(){
  return 666;
}
#include "get.h"

int get(){
  return 666;
}

CLANG編譯

#include <stdio.h>

int hi();

#include "hi.h"

int hi(){
  return 888;
}

配置NDK

Linux(使用GCC編譯)

編輯Home/用戶 目錄下的.bashrc

vim /home/wangyz/.bashrc

添加以下內(nèi)容

# 配置NDK的目錄
export NDK_HOME=/home/wangyz/NDK/android-ndk-r17c
# 將NDK目錄加入PATH中
export PATH=$PATH:$NDK_HOME

# x86 CPU架構(gòu)的gcc
export NDK_GCC_x86=$NDK_HOME/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-gcc

# x86_64 CPU架構(gòu)的gcc
export NDK_GCC_x64=$NDK_HOME/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc

# ARM CPU架構(gòu)的gcc
export NDK_GCC_ARM=$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc

# ARM64 CPU架構(gòu)的gcc
export NDK_GCC_ARM_64=$NDK_HOME/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc

# x86 CPU架構(gòu) 配置sysroot,isystem,否則會(huì)找不到頭文件
export NDK_GCC_CONFIG_x86="--sysroot=$NDK_HOME/platforms/android-21/arch-x86 -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/i686-linux-android"

# x86_64 CPU架構(gòu) 配置sysroot,isystem,否則會(huì)找不到頭文件
export NDK_GCC_CONFIG_x64="--sysroot=$NDK_HOME/platforms/android-21/arch-x86_64 -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/x86_64-linux-android"

# ARM CPU架構(gòu) 配置sysroot,isystem,否則會(huì)找不到頭文件
export NDK_GCC_CONFIG_ARM="--sysroot=$NDK_HOME/platforms/android-21/arch-arm -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/arm-linux-androideabi"

# ARM64 CPU架構(gòu) 配置sysroot,isystem,否則會(huì)找不到頭文件
export NDK_GCC_CONFIG_ARM_64="--sysroot=$NDK_HOME/platforms/android-21/arch-arm64 -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/aarch64-linux-android"

Mac(使用CLANG編譯)

修改~/.bash_profile

vim ~/.bash_profile

添加以下內(nèi)容

# NDK目錄
export NDK_HOME=/Users/ringle/Library/Android/sdk/ndk/21.1.6352462

# CLANG目錄
export CLANG=${NDK_HOME}/toolchains/llvm/prebuilt/darwin-x86_64/bin

# 添加到PATH中
export PATH=${PATH}:${NDK_HOME}:${CLANG}

編譯

這里編譯ARM64構(gòu)架的so

GCC

$NDK_GCC_ARM_64 $NDK_GCC_CONFIG_ARM_64 -fPIC -shared get.c -o libndk-linux.so

CLANG

aarch64-linux-android21-clang -fPIC -shared hi.c -o libndk-mac.so

導(dǎo)入Android Studio

復(fù)制so到項(xiàng)目中

在app/src/main 目錄下新建jniLibs目錄,再新建arm64-v8a目錄,將編譯生成的libndk-linux.so及l(fā)ibndk-mac.so復(fù)制到目錄下

配置cmake

在app/src/main 目錄下新建cpp目錄,新建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.10.2)

# Declares and names the project.

project("ndk")

# 包含所有CPP文件
file(GLOB allCPP *.cpp)

# 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).
        ${allCPP})

# 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)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")

# 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}
        # 鏈接libndk-mac
        ndk-mac
        # 鏈接libndk-linux
        ndk-linux
        )

配置gradle

配置app模塊下的build.gralde文件


android {

    defaultConfig {
        //...
        
        externalNativeBuild {
            cmake {
                abiFilters "arm64-v8a"
            }
        }
        ndk {
            abiFilters "arm64-v8a"
        }
    }

    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}

引用so中的方法

在cpp目錄下,新建native-lib.cpp

#include <jni.h>
#include <string>
#include <android/log.h>

#define TAG "Wangyz"

#define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, TAG,  __VA_ARGS__);

extern "C" int get();

extern "C" int hi();

extern "C" JNIEXPORT jstring JNICALL
Java_com_wangyz_ndk_MainActivity_stringFromJNI(
        JNIEnv *env,jobject /* this */) {
    int a = get();
    LOG_I("hello:%d", a);

    int b = hi();
    LOG_I("hi:%d", b);

    return env->NewStringUTF("hello");
}

Activity中調(diào)用


public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("ndk-mac");
        System.loadLibrary("ndk-linux");
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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