如何開發Android原生庫並應用到Xamarin.Android
本文將向大家介紹如何使用Android+Studio/">Android Studio開發原生庫,並將其應用到Xamarin.Android的方法步驟;
本文中我所使用的Android Studio版本和Visual Studio For Mac版本情況分別如下:

Android Studio

Visual Studio For Mac
下述內容在以上兩個版本的開發環境中是有效的。
Android Studio開發部分
首先,新建一個支援C++的Android Studio專案;

選中 include C++ support。
然後一路next,在add an Activity to Mobole處選擇加入一個Empty Activity,這樣會比較省事。

然後一路next,完成專案建立;
新增一個Java類,這裡取名NativeTest;
內容如下:
package suihan.com.nativedemo; public class NativeTest { static { System.loadLibrary("native-lib"); } public static native String Test(); }
這裡我將 static { System.loadLibrary("native-lib"); }
剪下到了這個類下,因為後面我們打包的JAR檔案中並不包含自動生成的MainActivity類,如果這段程式碼依然留在這個類中會到os檔案沒有載入。當然具體的載入時機,你可以自行修改。

利用Android Studio的智慧修復功能,就可以生成對應的native方法。我將程式碼補全成如下模樣:
#include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_suihan_com_nativedemo_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } extern "C" JNIEXPORT jstring JNICALL Java_suihan_com_nativedemo_NativeTest_Test(JNIEnv *env, jclass type) { // TODO std::string test = "Test Native"; return env->NewStringUTF(test.c_str()); }
這個時候,rebuild project就可以在app/build/intermediates/cmake/debug資料夾下看到生成的so檔案;

然後我們需要打包成Jar檔案。我們需要修改一下app的build.gradle檔案。需要修改的地方如下:
- 將apply plugin: 'com.android.application'該成apply plugin: 'com.android.library';
- 註釋掉 applicationId 項;
- 新增如下程式碼:
task makeJar(type: Copy) { //刪除存在的 delete 'build/libs/myNativeSdk.jar' //設定拷貝的檔案 from('build/intermediates/packaged-classes/release/') //打進jar包後的檔案目錄 into('build/libs/') //將classes.jar放入build/libs/目錄下 //include ,exclude引數來設定過濾 //(我們只關心classes.jar這個檔案) include('classes.jar') //重新命名 rename ('classes.jar', 'myNativeSdk.jar') } makeJar.dependsOn(build)
最後的build.gradle檔案內容是這樣的:
apply plugin: 'com.android.library' android { compileSdkVersion 28 defaultConfig { //applicationId "suihan.com.nativedemo" minSdkVersion 14 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } externalNativeBuild { cmake { path "CMakeLists.txt" } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0-rc02' 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' } task makeJar(type: Copy) { //刪除存在的 delete 'build/libs/myNativeSdk.jar' //設定拷貝的檔案 from('build/intermediates/packaged-classes/release/') //打進jar包後的檔案目錄 into('build/libs/') //將classes.jar放入build/libs/目錄下 //include ,exclude引數來設定過濾 //(我們只關心classes.jar這個檔案) include('classes.jar') //重新命名 rename ('classes.jar', 'myNativeSdk.jar') } makeJar.dependsOn(build)
注意:build/intermediates/packaged-classes/release/路徑是在Android Studio 3之後才是這樣,如果是Android studio 2的話,應該是build/intermediates/bundles/default/,更早的版本也和這個路徑不一樣,具體的請自行搜尋;
這個時候我們最好刪除掉之前編譯出來的build資料夾,在Terminal中輸入命令列:./gradlew makeJar

然後,我們在app/build路徑下就可以看到libs/myNativeSdk.jar,

好,現在原生庫需要的檔案已經準備完畢。
Xamarin.Android開發部分
1.新建一個Bindings Library專案;


在NativeBindingLib專案的Jars中加入前面我們生成的myNativeSdk.jar檔案;

新增時最好是以連結的方式新增,這樣一來,我們修改原生庫的時候就不需要重新新增檔案了,只要重新編譯一下這個專案就可以了。

編譯Binding專案後,在NativeTest專案中新增對他的引用。

下面我們新增so檔案,這裡我們在NativeTest專案新建一個lib資料夾,並在裡面新建如下這幾個資料夾,分別對應前面生成的4中架構的so檔案,並將對應的so檔案新增到其中,新增時注意同前面一樣以連結的方式新增。

我們需要將每一個so檔案的Build Action改為AndroidNativeLibrary;

然後通過reveal in Find功能開啟NativeTest專案所在的資料夾,對該專案的.csproj檔案進行編輯,開啟後找到每一個so檔案的新增配置,在配置中加入對應的<Abi>屬性;

修改MainActivity檔案的內容,以呼叫原生介面:
using Android.App; using Android.Widget; using Android.OS; using Suihan.Com.Nativedemo; namespace NativeTest { [Activity(Label = "NativeTest", MainLauncher = true, Icon = "@mipmap/icon")] public class MainActivity : Activity { int count = 1; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it Button button = FindViewById<Button>(Resource.Id.myButton); button.Text = Suihan.Com.Nativedemo.NativeTest.Test(); //button.Click += delegate { button.Text = $"{count++} clicks!"; }; } } }
完成這一系列配置後,執行專案,可見如下效果:

真機的效果,呼叫arm64-v8a架構

虛擬機器的效果,呼叫x86架構
至此我們已經完成了對原生庫的應用。
除錯原生庫時的注意事項
後面我們可能會需要對原生庫進行修改,為了節省除錯時間,我們最好是在原生環境下將程式碼除錯好。這個時候我們需要把app的build.gradle檔案修改回來。
- 將apply plugin: 'com.android.library'恢復為 apply plugin: 'com.android.application';
- 恢復 applicationId 項;
然後就可以執行程式了。
除錯好程式碼後,要生成jar時,我們還是需要將build.gradle檔案修改回去。
生成新的jar後,我們只需要重新編譯一下Xamarin中的專案即可。
參考文獻
ofollow,noindex">Android Studio生成so檔案的幾種方式
3608601/article/details/80799568" target="_blank" rel="nofollow,noindex">Android studio3.1.3 打包jar,混淆
Using Native Libraries