NDK撩妹三部曲(一)—站住同學,我這有個C++的so庫,底層運算效率飛起,想不想要?
從何說起?
上禮拜在妹子面前秀了一波後,妹子事後頻頻要請我喝奶茶,還說我明明可以靠臉喫飯,卻偏偏要靠才華(我淦,內外兼修纔是我追求的終極奧義)。堅持了3天,終於抵擋不住妹子的熱情,當然,妥協是因爲飢渴,不對,是因爲奶茶,還不對,不是因爲奶茶,而是本着助人爲樂,共同學習,分享快樂的宗旨,獻上我寶貴的“NDK”寶典。拂去1cm厚的灰塵,翻到,328頁,對,就是這兒,“論 Android 實戰如何使用 C++ so 庫這個神祕武器?”。
寶典摘要
不管你是葵花寶典還是九陰真經,都少不了“摘要”、“目錄”這幾章吧,可千萬不要小看了這一點點內容,它可是真正武功祕籍的濃縮所在,也就是說全是精華,可謂一字值千金,百字通氣海。
如果你是一個初學者,當拿到一個 so 庫時,可能不知道怎麼辦了,因爲“聽說 Native 有點難呀”,老有人嚇你。然後當你鼓足勇氣挑戰一下,我靠,JNI 真…踏馬的麻煩。
而又當你是一個老司機時,你一定會霹靂拍啦一陣操作,生成 JNI 頭文件,再實現,再編譯 so,看起來很簡單,但是擡頭一看,幾個小時過去了,這還不包含可能出現的錯誤。當然了,有點誇張,只是舉例說明一下 JNI 方式的繁瑣。
今天我們帶妹子嘗試另一種姿勢,不對,另一種方式,使用 SUN 公司的 JNA 代替 JNI 的繁瑣過程,一會兒你就知道這讓我們調用 Native 方法有多舒服。
和妹子一起操作
一、新建 Android 項目,jnatest:
進入 libs 文件夾,然後根據你需要的 Android ABI 建立相應的文件夾,如 arm64-v8a 、armeabi-v7a。
二、從官網下載 JNA 包:
https://github.com/java-native-access/jna/releases
解壓後,進入下圖的目錄:
上圖中分別標識了不同的 Android ABI 對應的 JNA 庫,把自己需要的 jar 包複製出來並解壓,我們選擇 android-aarch64.jar ,會得到一個 libjnidispatch.so 文件,將其複製到上面我們新建的 arm64-v8a 或者 armeabi-v7a 文件夾中。
再次回到 dist 目錄,複製裏面的 jna-min.jar 和 jna-platform.jar 粘貼到上面的 libs 目錄。
三、依賴庫拷貝
3.1 如果你是個純 C++ 的 so 庫,到 ndk 目錄下拷貝 libc++_shared.so 文件到上面的 rm64-v8a 目錄。
科普:
libc++_shared 和 libgnustl_shared 均爲 C++ 標準庫,因爲不同的 NDK 版本要求了不同的 C++ 標準。
1、libc++,從 Lollipop 開始的官方安卓系統和現代 Mac 操作系統都將其作爲C++標準庫使用。從 NDK17 開始,它將成爲 NDK 中唯一可用的 C+ + 標準實現。2、gnustl,libstdc++ 的別名,這兩者在 GNU/linux 是同一個庫。這個庫的已被棄用,它在NDK 18 中被刪除;
3、STLport,由 STLport 項目編寫的 C++ 標準庫的第三方實現,自2008年以來一直處於不活躍狀態。與gnustl一樣,STLport在NDK 18 中被刪除;
3.2 如果你是個 QT 的 so 庫,往下看:
首先在任意地方新建一個文件夾,然後複製下面的內容命名爲: android-libjnatest.so-deployment-settings.json
{
"description": "This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.",
"qt": "D:/WorkSoftware/QT5.12.0_for_Android/5.12.0/android_arm64_v8a",
"sdk": "C:/Users/HiWin10/AppData/Local/Android/Sdk",
"sdkBuildToolsRevision": "26.1.1",
"ndk": "D:\\Java\\android-ndk-r16-windows-x86_64\\android-ndk-r16",
"toolchain-prefix": "aarch64-linux-android",
"tool-prefix": "aarch64-linux-android",
"toolchain-version": "4.9",
"ndk-host": "windows-x86_64",
"target-architecture": "arm64",
"stdcpp-path": "D:/Java/android-ndk-r16-windows-x86_64/android-ndk-r16/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so",
"application-binary": "E:/VPlayer_git/release/arm64-v8a/libjnatest.so"
}
其次將你編譯出的 so 庫也放到此目錄在此目錄,
最後打開 cmd 窗口,並輸入以下內容。或者將下面的內容放到 test.bat 中,雙擊此 bat 文件執行:
"D:/WorkSoftware/Qt5.12.0_for_android/5.12.0/android_arm64_v8a/bin/androiddeployqt.exe" --input E:/VPlayer_git/release/arm64-v8a/android-libjnatest.so-deployment-settings.json --output E:/VPlayer_git/release/arm64-v8a/android-build
完成後可以看到在當前目錄下創建了 android-build 目錄,依次進入 libs 目錄,再進入 arm64 目錄,可以看到這裏面即爲當前你編譯的 libjnatest.so 庫要在 android 環境下運行所要依賴的庫(此處我使用的是我們項目真正的庫文件,只是修改了名字,這樣更能貼近真實的情況。假如我用一個簡單的 so 庫測試,可能會出現和大家不一樣的情況,比如依賴庫不全等等問題)。
將上面這些庫拷貝到第二步中的 rm64-v8a 文件夾中。然後別急,再將剛纔 libs 目錄下的 QtAndroid.jar 和 QtAndroidBearer.jar 文件拷貝到第二步中的 rm64-v8a 的外層
即下圖的目錄。(是否有這兩個 jar 包取決於我們編譯的庫是否有相關依賴,如果沒有不用複製)
四、萬事俱備,只欠東風——修改 gradle 文件和添加 JNA 代碼
4.1 在 MainActivity 同級新建 Jna.java 文件,如下:
package com.qht.jnatest;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface Jna extends Library {
/*
* Step1:
* JNA加載.so庫,通過Native.loadLibrary()方法來加載,不帶前綴“lib”
*/
Jna INSTANCE = Native.loadLibrary("jnatest", Jna.class);
/*
* Step2:
* 重寫與C/C++源文件名稱相同的方法,不需要用到的方法可以不用寫
*/
int test(int a,int b);
}
4.2 MainActivity 添加一句話即可:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.tv);
int result = Jna.INSTANCE.test(20,500);
tv.setText("引用so,計算結果:" + result);
}
}
4.3 編輯 app 下的 build.gradle 文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.qht.jnatest"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
packagingOptions {
exclude 'META-INF/XXXX'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs'] //相當於將libs文件夾當做jnilibs文件夾
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation files('libs/jna-min.jar') //將這4個jar包含到項目
implementation files('libs/jna-platform.jar')
implementation files('libs/QtAndroid.jar')
implementation files('libs/QtAndroidBearer.jar')
}
完成之後 右鍵點擊 jna-min.jar 包,選擇add as library,最後點小錘子 make 一下:
如果不報錯,再將項目切到 Android 視圖,可以看到是不是多了一個 jniLibs 目錄:
最後點擊小三角,run:
我靠,剛過完 520,又來個 601,妹子這是給我什麼暗號???
csdn地址:http://blog.csdn.net/u012534831
github地址:https://github.com/qht1003077897 \
如有幫助,請多多點贊支持哦。