最近在做Unity中使用C++的方案,剛開始是用直接打包到Android發現會找不到C++DLL,通過查資料發現Android中不能用C++DLL,需要自己手動打包成android對用的.so文件。
先將下要用的工具,NDK,Android SDK,AndroidStudio。我的AndroidSutdio用的是2.3.3版本的,下Android SDK相關的最好能能翻牆,不然有可能下載失敗。
安裝完之後打開AndroidStudio,新建C++項目,注意一定要勾選Include C++選項,然後就一直下一步就可以了,完成之後打開項目配置file->project structure設置下SDK,NDK路徑
,新創建的項目會有一個默認的c++文件,先編譯一下make project,確保默認的文件能編譯通過,這樣說明你的環境沒有問題。編譯默認項目的時候也有可能會遇到報錯,我遇到了SDK的版本和build tool的版本匹配不上,這裏講下解決方法,打開app目錄下的build.gradle文件,修改相應的版本對應自己SDK的版本就行,如果沒有對應的版本需要去下。這裏貼一下我的配置,注意紅框裏面的版本要移植,不然就會編譯報錯。
確保默認項目沒問題之後開始我們接下來的工作,如果你的工程有多個項目,並且有依賴關係,比如工程裏面有a,b,c三個項目,a是主工程,b,c是提供相關功能的模塊。我們就需要先把b和c在androidstudio裏面編譯成靜態庫的.a文件,然後在編譯主工程編譯依賴着兩個.a文件編譯成.so文件。
選擇file->new->new module,選android library,,新建完之後在這個目錄下新建一個CMakeLists.txt文件。,cmake的寫法我就不講了,需要的自己百度,我這裏寫了一個例子,可以參考我這個來寫,具體的內容要根據自己的項目來填充。
# 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)
#宏定義 格式 -D_你的宏定義
add_definitions(-D_VISION_MOBILE)
add_definitions(-D_VISION_ANDROID)
#編譯需要引用的頭文件
set(INCLUDE_DIR
../../Program/Client/a
../../Program/Client/b
)
#引用頭文件
include_directories(${INCLUDE_DIR})
#編譯需要的CPP文件
file(GLOB_RECURSE SRC_FILE
"../../Program/Client/a/*.cpp"
"../../Program/Client/b/*.cpp"
)
#編譯.a文件 STATIC 是生成.a文件 SHARED是生成.so文件
add_library( # Sets the name of the library.
Client
# Sets the library as a shared library.
STATIC
# Provides a relative path to your source file(s).
${SRC_FILE} )
build.gradle裏面需要加一些配置
apply plugin: 'com.android.library'
apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
def stlArg = getSTLArg()
def toolChain = getToolChain()
def abis = getAbiFilters()
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
minSdkVersion 22
targetSdkVersion 25
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
//abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'
for(abi in abis){
abiFilters abi
}
//https://developer.android.com/ndk/guides/cmake.html#variables
arguments toolChain,stlArg,'-DANDROID_ARM_MODE=arm','-DANDROID_ARM_NEON=TRUE'
cFlags '-std=c11'
cppFlags '-std=c++11', '-fpic', '-fstack-protector', '-frtti', '-fexceptions'
targets "BaseRace"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
}
這些都配置完之後就make project,這個時間是最痛苦的時間會有很多報錯,需要耐心慢慢改,我們項目的代碼比較多,我改了兩天多才改完。例如不能引用windows的相關頭文件,調用函數不能用int賦值給uint等等。
如果你的.a文件存在依賴的關係,只需要把另外依賴的項目相關的頭文件加進去就可以,到最後編譯.so文件的時候在鏈接,不需要再編譯.a文件的時候添加庫依賴。
好,就這樣編譯完所有的.a文件之後,開始編譯.so文件,.so文件的配置和.a文件有點不一樣。首先是add library裏面要改成SHARED,然後後面要加上相關的依賴。
# 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)
#宏定義
add_definitions(-D_VISION_MOBILE)
add_definitions(-D_VISION_ANDROID)
#編譯需要引用的頭文件
set(INCLUDE_DIR
../../Program/c/a
../../Program/c/b
E:/SDK1/Sdk/ndk-bundle/sources
)
#引用頭文件
include_directories(${INCLUDE_DIR})
#編譯需要的CPP文件
file(GLOB_RECURSE SRC_FILE
"../../Program/c/a/*.cpp"
"../../Program/c/b/*.cpp"
)
#編譯.so文件
add_library( # Sets the name of the library.
Client
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
${SRC_FILE} )
#查找NDK相關的庫文件
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 )
find_library(
stdc++-lib
stdc++ )
find_library(
c-lib
c )
find_library(
dl-lib
dl )
find_library(
m-lib
m )
find_library(
GLESv1_CM-lib
GLESv1_CM
)
find_library(
GLESv2-lib
GLESv2 )
find_library(
EGL-lib
EGL
)
find_library(
android-lib
android )
find_library(
android_support-lib
android_support )
find_library(
c++_static-lib
c++_static )
#添加link依賴項
target_link_libraries( # Specifies the target library.
Client
"-Wl,--start-group"
liba.a
libb.a
${android-lib}
"-Wl,--end-group"
${GLESv1_CM-lib}
${GLESv2-lib}
${EGL-lib}
${c-lib}
${log-lib}
${dl-lib}
${m-lib}
)
需要把liba.a拷貝到cmakelist同級目錄或者制定下相對路徑也行。改好makelist之後編譯,有可能會有鏈接問題,一般都是相關的CPP文件沒有加到.a文件的編譯裏面,回到之前的.a工程在加進去就行了。
最後編譯出來.so文件放到unity的Assets\Plugins\Android\libs\armeabi-v7a目錄下面,沒有的話創建一個,注意unity,dllimport裏面的名字只需要填去掉lib前綴和.so後綴的。比如你的so叫libClient.so,
[DllImport("Client")]
public static extern bool a();
這樣寫就可以了。注意unity build的時候選,不要用默認的FAT,不然會找不到DLL。