绑定 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 创建。所有学分属于他。谢谢你,卢卡斯。