繫結 Xamarin.iOS 中的 Swift 庫

繫結 Xamarin.iOS 中的 Swift 庫遵循與 Objective-C 相同的過程,如 https://developer.xamarin.com/guides/ios/advanced_topics/binding_objective-c/ 所示,但有一些注意事項。

  1. swift 類必須從 NSObject 繼承才能繫結。
  2. 除非在 swift 類中使用 @objc 註釋(例如 @objc(MyClass))來指定顯式目標 c 名稱,否則 Swift 編譯器會將類和協議名稱轉換為其他名稱。
  3. 在執行時,你的 APP 必須在名為 Frameworks 的資料夾中包含一些快速核心庫以及繫結框架;
  4. 當應用程式被推送到 AppStore 時,它必須在你的 Payload 資料夾旁邊包含一個 SwiftSupport 資料夾。這些都在 IPA 檔案中。

在這裡你可以找到一個簡單的樣本繫結: https//github.com/Flash3001/Xamarin.BindingSwiftLibrarySample

以及完整的繫結示例: https//github.com/Flash3001/iOSCharts.Xamarin

請找到以下步驟:

1.1 準備要匯出的 Swift 類

對於你要使用的任何 Swift 類,你必須從 NSObject 繼承並使用 objc 註釋顯式顯示 Objective-C 名稱。否則 Swift 編譯器將生成不同的名稱。下面是 Swift 類的外觀示例程式碼。請注意,只要根類繼承自 NSObject,它繼承哪個類並不重要。

//Add this to specify explicit objective c name
@objc(MyClass)
open class MyClass: NSObject {
    open func getValue() -> String
    {
        return "Value came from MyClass.swift!";
    }
}

1.2 構建框架

禁用 Bitcode。 *

StackOverflow 文件

構建適用於裝置和模擬器的版本。 * StackOverflow 文件 StackOverflow 文件

StackOverflow 文件

StackOverflow 文件

StackOverflow 文件

  • 與 Swift 繫結無關。

2.建立一個胖庫

一個框架包含幾個檔案,需要吃一點的是 NAME.framework / NAME(沒有副檔名)。

  • 將 Release-iphoneos / NAME.framework 複製到 NAME.framework
  • 使用以下命令建立 FAT 庫:
    • lipo -create Release-iphonesimulator / NAME.framework / NAME Release-iphoneos / NAME.framework / NAME -output NAME.framework / NAME
  • 將 Release-iphonesimulator / NAME.framework / Modules / NAME.swiftmodule 中的檔案複製到 NAME.framework / Modules / NAME.swiftmodule(直到現在它只包含來自 iphoneos 的檔案)

StackOverflow 文件

StackOverflow 文件

StackOverflow 文件

3.匯入庫

我假設你已經在 File - > New - > iOS - > Binding Library 中建立了 Binding 專案。

Xamarin 支援匯入 .frameworks。只需右鍵單擊 Native References,然後單擊 Add native reference。找到新建立的胖框架並新增它。

StackOverflow 文件

StackOverflow 文件

StackOverflow 文件

4.根據標頭檔案中的 LIBRARY-Swift.h 檔案建立 ApiDefinition

你可以手動完成它,但它不會很好。你可以使用 Objetive Sharpie。Xamarin 工具用於繫結自己的庫。

如何在 https://developer.xamarin.com/guides/cross-platform/macios/binding/objective-sharpie/ 上使用它

基本命令將類似於: sharpie bind -sdk iphoneos9.3 NAME-Swift.h

如果你得到了 System.Reflection.TargetInvocationException,可能是因為你安裝了不同的 SDK 版本。執行以下命令以檢查已安裝的 iPhone OS SDK:

sharpie xcode -sdks

NAME-Swift.h 檔案位於 NAME.framework / Headers / NAME-Swift.h 中

注意:swift 類必須繼承自 NSObject,否則 NAME-Swift.h 將不會匯入你的類,而 Objetive Sharpie 將不會轉換任何內容。

StackOverflow 文件

用新建立的專案替換繫結專案 ApiDefinition.cs 的內容。 StackOverflow 文件

5.更改所有[Protocol]和[BaseType]以在 Objective-C 執行時中包含類的名稱

如果原始 Swift 類或協議不包含步驟 1.1 中指定的 @objc(MyClass) 註釋,則它們的內部 Objective-C 名稱將更改,因此你需要將其對映到正確的名稱。

所有名稱都以 NAME-Swift.h 檔案的形式提供,格式如下:

SWIFT_CLASS("_TtC11SwiftSample7MyClass")
@interface MyClass : NSObject

SWIFT_PROTOCOL("_TtP6Charts17ChartDataProvider_")
@protocol ChartDataProvider

要設定名稱,請使用 BaseTypeAttribute.Name https://developer.xamarin.com/guides/cross-platform/macios/binding/binding-types-reference/#BaseType.Name 屬性以及類和 ProcotolAttribute.Name https:// developer.xamarin.com/api/property/MonoTouch.Foundation.ProtocolAttribute.Name/ 用於協議。

[BaseType(typeof(NSObject), Name = "_TtC11SwiftSample7MyClass")]
interface MyClass

手動完成並不酷。你可以使用此工具 https://github.com/Flash3001/SwiftClassify 插入所有名稱。 (它正在進行中。但它非常簡單,只需檢視程式碼就可以瞭解它的工作原理)。

6.1 包括要執行的所有 Swift 依賴項

如果你嘗試在應用程式中使用該庫並嘗試立即執行它將崩潰。錯誤是由於缺少 libswiftCore.dylib

像這樣的東西:

Dyld Error Message:
  Library not loaded: @rpath/libswiftCore.dylib
  Referenced from: /Users/USER/Library/Developer/CoreSimulator/Devices/AC440891-C819-4050-8CAB-CE15AB4B3830/data/Containers/Bundle/Application/27D2EC87-5042-4FA7-9B80-A24A8971FB48/SampleUsing.app/Frameworks/SwiftSample.framework/SwiftSample
  Reason: image not found

Xamarin.iOS 沒有為繫結 Swift 庫提供官方支援。因此,你必須在 Frameworks 和 SwiftSupport 資料夾中手動包含 swift 核心庫。Frameworks 資料夾的檔案對於 Simulator 和 Device 是不同的。它們可以在/Applications/Xcode.app/Contents/Developer//XcodeDefault.xctoolchain/usr/lib/swift.Toolchains 中找到

你可以使用此庫 https://github.com/Flash3001/Xamarin.Swift3.Support 而不是手動複製 Framework 資料夾中的檔案。它包括 Swift 3.1 所需的每個依賴項,每個依賴項都在一個 NuGet 包中。

StackOverflow 文件

如你所見,Nuget Package 包含在消費者 App 中,而不是繫結本身。如果你嘗試將其包含在繫結中,則會出現編譯錯誤。

如果你正在構建 Nuget 包,則可以指示 Nuget 將其作為依賴項包含在內。

StackOverflow 文件

6.2。找出要包含的 Swift 依賴項

一件重要的事情是弄清楚你需要包含在專案中的每個包。通常需要一個簡單的繫結:

     libswiftCore.dylib
     libswiftCoreGraphics.dylib
     libswiftCoreImage.dylib
     libswiftDarwin.dylib
     libswiftDispatch.dylib
     libswiftFoundation.dylib
     libswiftObjectiveC.dylib
     libswiftQuartzCore.dylib
     libswiftUIKit.dylib   

要列出每個依賴項,可以在 LibraryName.framework 中執行以下命令

otool -l -arch armv7 LibraryName | grep libswift

StackOverflow 文件

不要在 NuGet for Swift3 中包含所有可用的包,因為它們可能會增加你的應用程式大小。

7.包括 SwiftSupport 以將 App 推送到 AppStore

Apple 要求你的應用程式與你的 Payload 資料夾一起傳送 SwiftSupport 資料夾。兩者都在你的 IPA 包中。

你可以使用此指令碼 https://github.com/bq/ipa-packager 為你完成此項工作。

此過程是庫消費者必須手動執行的唯一過程。每次他/她試圖將 App 推送到 AppStore。

StackOverflow 文件

單擊簽名並分發並儲存到磁碟 StackOverflow 文件

解壓縮 .IPA StackOverflow 文件

使用前面提到的指令碼建立新的 IPA StackOverflow 文件

如果解壓縮檔案,它將包含 SwiftSupport 資料夾。 StackOverflow 文件

備註

在 Xcode 中構建庫時,它可以選擇包含 swift 庫。別! 它們將作為 NAME.app/Frameworks/LIBRARY.framework/Frameworks/libswift*.dylib 包含在你的最終應用中,但它們必須包含在 NAME.app/Frameworks/libswift*.dylib 中

你可以在其他地方找到此資訊,但值得一提的是:不要在庫中包含 Bitcode。截至目前,Xamarin 不包括 iOS 的 Bitcode,Apple 要求所有庫都支援相同的架構。

放棄

本指南最初由 Lucas Teixeira 建立。所有學分屬於他。謝謝你,盧卡斯。