在 Xamarin.iOS 中參考原生連結庫
Xamarin.iOS 支援使用原生 C 連結庫和 Objective-C 連結庫進行連結。 本文件討論如何將原生 C 連結庫與 Xamarin.iOS 項目連結。 如需針對 Objective-C 連結庫執行相同動作的詳細資訊,請參閱我們的 系結 Objective-C 類型 檔。
建置通用原生連結庫 (i386、ARMv7 和 ARM64)
通常建議針對 iOS 開發的每個支援平臺建置原生連結庫(適用於模擬器的 i386,以及裝置本身的 ARMv7/ARM64)。 如果您已經有連結庫的 Xcode 專案,這確實很簡單。
若要建置原生連結庫的 i386 版本,請從終端機執行下列命令:
/Developer/usr/bin/xcodebuild -project MyProject.xcodeproj -target MyLibrary -sdk iphonesimulator -arch i386 -configuration Release clean build
這會導致 下的 MyProject.xcodeproj/build/Release-iphonesimulator/
原生靜態庫。 複製 (或移動) 連結庫封存盤案 (libMyLibrary.a) 到某個位置安全以供日後使用,為它提供唯一的名稱(例如 libMyLibrary-i386.a),使其不會與接下來要建置之相同連結庫的 arm64 和 armv7 版本發生衝突。
若要建置原生連結庫的 ARM64 版本,請執行下列命令:
/Developer/usr/bin/xcodebuild -project MyProject.xcodeproj -target MyLibrary -sdk iphoneos -arch arm64 -configuration Release clean build
這次建置的原生連結庫將會位於 MyProject.xcodeproj/build/Release-iphoneos/
。 再次將這個檔案複製到安全的位置,將它重新命名為 libMyLibrary-arm64.a 之類的專案,使其不會發生衝突。
現在建置連結庫的 ARMv7 版本:
/Developer/usr/bin/xcodebuild -project MyProject.xcodeproj -target MyLibrary -sdk iphoneos -arch armv7 -configuration Release clean build
將產生的連結庫檔案複製到您移動其他 2 個連結庫版本的相同位置,將其重新命名為 libMyLibrary-armv7.a 之類的專案。
若要建立通用二進位檔,您可以使用 lipo
工具,如下所示:
lipo -create -output libMyLibrary.a libMyLibrary-i386.a libMyLibrary-arm64.a libMyLibrary-armv7.a
這會建立 libMyLibrary.a
一個通用 (fat) 連結庫,適合用於所有 iOS 開發目標。
遺漏必要的架構 i386
如果您在嘗試在 iOS 模擬器中取用連結庫時,在運行時間輸出中收到 does not implement methodSignatureForSelector
或 does not implement doesNotRecognizeSelector
訊息,您的連結庫可能未針對 i386 架構進行編譯(請參閱上面的建置通用原生連結庫一節)。Objective-C
若要檢查指定連結庫支援的架構,請在終端機中使用下列命令:
lipo -info /full/path/to/libraryname.a
其中 /full/path/to/
是所取用連結庫的完整路徑,而 libraryname.a
是有問題的連結庫名稱。
如果您有連結庫的來源,如果您想要在iOS模擬器上測試您的應用程式,則必須編譯並配套i386架構。
連結您的連結庫
您取用的任何第三方連結庫都必須以靜態方式連結您的應用程式。
如果您想要以靜態方式連結連結連結庫 “libMyLibrary.a”,您可以從因特網或使用 Xcode 建置,您需要執行一些動作:
- 將連結庫帶入您的專案
- 設定 Xamarin.iOS 連結連結庫
- 從鏈接庫存取方法。
若要 將連結庫帶入您的專案,請從方案總管選取專案,然後按 Command+Option+a。 流覽至 libMyLibrary.a,並將它新增至專案。 出現提示時,請告訴 Visual Studio for Mac 或 Visual Studio 將它複製到專案中。 新增它之後,請在項目中尋找 libFoo.a,以滑鼠右鍵按兩下它,然後將 [建置動作] 設定為 [無]。
若要設定 Xamarin.iOS 以連結庫,請在最終可執行檔的項目選項上(不是連結庫本身,而是最終程式),您需要在 iOS 組建的額外自變數中新增 [-gcc_flags] 選項,後面接著包含程式所需的所有額外連結庫的引號字串, 例如:
-gcc_flags "-L$(MSBuildProjectDirectory) -lMylibrary -force_load $(MSBuildProjectDirectory)/libMyLibrary.a"
上述範例會連結 libMyLibrary.a
您可以使用 -gcc_flags
來指定任何命令行自變數集,以傳遞至用來執行可執行檔最終連結的 GCC 編譯程式。 例如,這個命令行也會參考 CFNetwork 架構:
-gcc_flags "-L$(MSBuildProjectDirectory) -lMylibrary -lSystemLibrary -framework CFNetwork -force_load $(MSBuildProjectDirectory)/libMyLibrary.a"
如果您的原生連結庫包含 C++ 程式代碼,您也必須在 「Extra Arguments」 中傳遞 -cxx 旗標,讓 Xamarin.iOS 知道使用正確的編譯程式。 針對 C++,先前的選項看起來會像這樣:
-cxx -gcc_flags "-L$(MSBuildProjectDirectory) -lMylibrary -lSystemLibrary -framework CFNetwork -force_load $(MSBuildProjectDirectory)/libMyLibrary.a"
從 C 存取 C 方法#
iOS 上提供兩種原生連結庫:
屬於操作系統一部分的共享連結庫。
您隨附於應用程式的靜態連結庫。
若要存取上述任一項中定義的方法,您可以使用 Mono的 P/Invoke 功能 ,其與您在 .NET 中使用的技術相同,大致如下:
- 判斷您要叫用的 C 函式
- 判斷其簽章
- 判斷它所在的連結庫
- 撰寫適當的 P/Invoke 宣告
當您使用 P/Invoke 時,必須指定您要連結的連結庫路徑。 使用 iOS 共用連結庫時,您可以硬式編碼路徑,也可以使用我們在 中 Constants
定義的便利常數,這些常數應該涵蓋 iOS 共用連結庫。
例如,如果您想要從 Apple 的 UIKit 連結庫叫用 UIRectFrameUsingBlendMode 方法,並在 C 中具有此簽章:
void UIRectFrameUsingBlendMode (CGRect rect, CGBlendMode mode);
您的 P/Invoke 宣告看起來會像這樣:
[DllImport (Constants.UIKitLibrary,EntryPoint="UIRectFrameUsingBlendMode")]
public extern static void RectFrameUsingBlendMode (RectangleF rect, CGBlendMode blendMode);
Constants.UIKitLibrary 只是定義為 “/System/Library/Frameworks/UIKit.framework/UIKit”的常數,EntryPoint 可讓我們選擇性地指定外部名稱 (UIRectFramUsingBlendMode),同時在 C# 中公開不同名稱,也就是較短的 RectFrameUsingBlendMode。
存取 C Dylibs
如果您需要在 Xamarin.iOS 應用程式中取用 C Dylib,在呼叫 DllImport
屬性之前需要一些額外的設定。
例如,如果我們有 Animal.dylib
的方法 Animal_Version
,我們將在應用程式中呼叫,則必須先通知 Xamarin.iOS 連結庫的位置,然後再嘗試取用它。
若要這樣做,請編輯 Main.CS
檔案,使其看起來如下:
static void Main (string[] args)
{
// Load Dylib
MonoTouch.ObjCRuntime.Dlfcn.dlopen ("/full/path/to/Animal.dylib", 0);
// Start application
UIApplication.Main (args, null, "AppDelegate");
}
其中 /full/path/to/
是取用 Dylib 的完整路徑。 有了此程式代碼,我們就可以連結至 Animal_Version
方法,如下所示:
[DllImport("Animal.dylib", EntryPoint="Animal_Version")]
public static extern double AnimalLibraryVersion();
靜態庫
由於您只能在 iOS 上使用靜態庫,因此沒有外部共用連結庫可連結,因此 DllImport 屬性中的 path 參數需要使用特殊名稱 __Internal
(請注意名稱開頭的雙底線字元),而不是路徑名稱。
這會強制 DllImport 查閱您在目前程序中參考的方法符號,而不是嘗試從共用連結庫載入它。