# uts for iOS

This article aims to help iOS developers get started with UTS quickly.

Readers are required to have iOS native application development experience.

# 1 Understanding what the UTS plugin is

UTS 插件是 uni-app 新型插件形式 详情

For iOS developers, what we need to know is:

  1. When compiling: When we save the UTS source code file, the IDE will simultaneously compile it into the corresponding swift code, and generate a corresponding plug-in Framework project to compile the corresponding framework dependent library
  2. Runtime: When running on the real machine or packaging in the cloud, the framework dependent library will be added to the packaging project to generate the final ipa package

# 2 Master UTS grammar

# 2.1 For those who master the swift language

因为 UTS 语法与 swift 较类似,建议快速阅读后,在实践中掌握 UTS 语法。uts语法介绍

# 2.2 For those who only master the objective-c language

Although it is not required to master swift to develop UTS plug-ins, since UTS is currently on the iOS platform, it will be compiled into swift source code and master the swift language, which is convenient for troubleshooting and complex function implementation.

Therefore, it is recommended to learn swift syntax, and it is recommended to read

# 2.3 Data Type Differences

UTS and swift are basically consistent in terms of data types, but in some scenarios, there are still differences, which are specifically explained here

In principle:

**The data type is subject to the built-in type of UTS, and each native platform will automatically adapt to it. **

**When the API parameters of a specific platform cannot be compatible with the UTS type, the data type explicitly required by the other party is allowed to prevail. **


# Example 1: Int, Float, Double and Number

Int, Float, and Double types do not exist in UTS Developers should use the Number type to cover the scenarios where Int, Float, and Double are used on the iOS platform during the development process

However, when it is necessary to rewrite the system method or implement the protocol method (delegate method) of the third-party dependent library during development, for example, when the API explicitly requires the parameter to be Int, you need to write the native type Int

Let's take a protocol method as an example. It is necessary to implement a protocol method defined in a three-party dependency library.

// swift 
// This protocol is defined in other third-party SDKs
protocol TestProtocol {
   func addTwoInts(_ a: Int, _ b: Int) -> Int
}

When we need to implement the protocol method in the above three-party library in UTS, since the parameter and return value types are required to be of type Int, in order to adapt to this situation, UTS allows developers to use the data type Int of the native platform to meet the requirements of the native API. Data type requirements:

// implement the protocol method in UTS
class TestClass implements TestProtocol {
	addTwoInts(a: Int, b: Int): Int {
		return a + b
	}
}

Note: The implements keyword is used in UTS to indicate compliance with a protocol, which will be described in detail below

# 3 iOS native environment configuration

For iOS projects, in addition to source code, it also involves common issues such as dependencies, resources, and project configuration

This chapter will introduce how to configure these properties in the UTS plug-in development environment

Notice:

  • 1 The example codes in this chapter are taken from Hello UTS project address
  • 2 The configuration designed in this chapter will only take effect after customizing the base

# 3.1 Configure Info.plist

When the plugin needs to add configuration items in the native project Info.plist, it needs to create the Info.plist file in the plugin's app-ios directory

Take the configuration file in the uts-tencentgeolocation Tencent location plugin in hello uts as an example:

Example file location in hello uts:

~/uni_modules/uts-tencentgeolocation/utssdk/app-ios/Info.plist

This example indicates that you need to configure APIKey in Info.plist and enable background location permission

Info.plist example:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
	<key>TencentLBSAPIKey</key>
	<string>您申请的APIKey</string>
	<key>UIBackgroundModes</key>
	<array>
		<string>location</string>
	</array>
  </dict>
</plist>

The Info.plist format and configuration rules are consistent with the iOS project, and the configuration information will be merged into the native project's Info.plist when packaging in the cloud

# 3.2 Configure entitlements

HBuilder X 3.6.11+ version support

When the plugin needs to enable related services in capabilities, it needs to create a UTS.entitlements file in the plugin's app-ios directory

For example, you need to check the Access WiFi Information item in capabilities, and the corresponding configuration example of UTS.entitlements:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.developer.networking.wifi-info</key>
	<true/>
</dict>
</plist>

The UTS.entitlements format and configuration rules are consistent with those in the iOS project, and the configuration information will be merged into the entitlements configuration file of the native project when packaging in the cloud

# 3.3 Dependent resource files

If your plug-in needs to rely on resource files such as pictures, audio, etc., you can put the resource files in the path ~/utssdk/app-ios/Resources/ under the plug-in directory

All files in this directory will be added to the main bundle of the application when packaging in the cloud. It is recommended to save only the built-in resource files of the uts plugin.

# 3.4 Relying on three-party libraries

uts 插件支持依赖三方库,目前支持 framework、xcframework(仅云打包支持)、.a库

# 3.4.1 framework依赖库说明

需要将依赖的framework或者xcframework文件存放到插件目录下 ~/utssdk/app-ios/Frameworks/路径中

When packaging in the cloud, all dependent libraries in this directory will be added to the project. It is recommended to store only dependent libraries related to plug-ins

Take the uts-tencentgeolocation Tencent positioning plug-in in hello uts as an example. This plug-in needs to rely on the Tencent positioning library TencentLBS.framework, then put the dependent inventory in ~/uni_modules/uts-tencentgeolocation/utssdk/app-ios/Framework/ TencentLBS.framework location is enough

# 3.4.2 .a依赖库相关说明

# 3.4.2.1 .a库存放的目录结构
	
└─Libs                         				// .a库存放目录
	├─MyStaticLibA                 			//A静态库(该库所有文件放在此文件夹内,OC库)
	│	├─libMyStaticLib.a                  //.a文件,必须
	│	├─MyStaticLib.h                    	//A.a库对应的头文件,必须
	│	├─MyClassA.h                     	//需要暴露的头文件A,可选
	│	└─MyClassB.h              		 	//需要暴露的头文件B,可选
	└─TestSwiftLibrary                      //B静态库(该库所有文件放在此文件夹内,Swift库)
		├─libTestSwiftLibrary.a             //.a文件,必须
		└─TestSwiftLibrary.swiftmodule      //.swiftmodule文件夹,必须

注意:

  • 将.a库的所有文件存放在一个文件夹内,多个.a库就创建多个文件夹;
  • 未对某个.a库文件夹下的文件做递归查找,请不要将.a或.h文件嵌套在多层文件夹内,以免发生错误;
# 3.4.2.2 .a库的使用说明
  • OC语言创建的.a库在使用时无需import,可直接使用;
  • Swift语言创建的.a库在使用前需要在uts文件中import;
  • HBuilder X目前暂不支持.a库相关代码的语法提示;
# 3.4.2.3 .a库的使用示例
  • OC语言创建的.a库使用示例:
// uts
const aResult = ToolA.toolAMethod();
const bResult = ToolB.toolBMethod();
const libResult = TestLib.testLib();

const res = {
	aResult: aResult,
	bResult: bResult,
	libResult: libResult
};
options.success?.(res);
  • Swift语言创建的.a库使用示例:
// uts
import { Tool, Manager, TestLibraryExa } from 'TestLibraryExa';

Manager.testManager();
Tool.testTool()
let lib = TestLibraryExa();
lib.test()
console.log(lib.version);

# 3.4.3 不包含 Modules 的 framework 使用说明

有些第三方的 SDK 使用 OC 语言开发,且产物 .framework 文件里不包含 Moudules 文件夹。这就造成该 SDK 不支持 use module 模式,不能直接在 Swift 文件中导入。 这样的 SDK 不能直接被 uts 插件引用,需要做以下处理:

# 有源码的情况

如果你有 SDK 的源码,那么有以下几种方法可以生成 Modules。 以名称为 TestSDK 的 framework 为例:

  • 通过创建和 SDK 的 target 同名的头文件方式:

    • 打开 XCode, 创建一个和 SDK target 同名的 .h 文件,如 TestSDK.h
    • 将需要暴露的 public 文件 导入到 TestSDK.h 中,如 #import <TestSDK/TestA.h>;
    • target -> Build Phases -> Headers 中将刚创建的 TestSDK.h 设置为 public;
    • 重新编译 SDK, 编译后可以看到 Modules 已经生成。
  • 通过自定义 Module Map 的方式:

    • 打开 XCode, 在 TestSDK SDK 源码目录下创建 module.map.modulemap 文件;
    • 在上述文件中键入下面代码中类似的内容,下述代码是以 TestSDK 为例,实践时需要改为自己的 SDK 和文件名;
    • target -> Build Settings -> Module Map File 设置 Module Map File$(PROJECT_DIR)/TestSDK/module.map.modulemap;
    • 重新编译 SDK, 编译后可以看到 Modules 已经生成。
framework module TestSDK {
    header "TestA.h"   //需要对外暴露的头文件,需要为 plubic 的文件
	
	header "TestB.h"  //需要对外暴露的头文件,需要为 plubic 的文件

    export *
}
# 无源码的情况

如果使用的是第三方非开源的 SDK, 那么可以使用下面的方式来生成 Modules: 以 TestSDK 为例:

  • TestSDK.framework 文件夹下创建 Modules 文件夹;
  • Modules 文件夹下创建 module.modulemap 文件;
  • 在上述文件中键入下述的代码(其中的 .h 文件都要是 TestSDK.framework -> Headers 文件夹里的头文件)。
  • 至此 TestSDK 就可以直接放在 uts 插件中使用了。

注意: 实践时要将 TestSDK 改成你要操作的 SDK 名称,.h 文件也要改成你要暴露的头文件名字。

framework module TestSDK {
	// 下面的.h 文件都要是 TestSDK.framework -> Headers 文件夹下的头文件
    header "AClass.h"  
    
    header "BClass.h"
    
    header "CClass.h"
    
    header "DClass.h"
    
    export *
}

# 4 iOS platform built-in library DCloudUTSFoundation

HBuilder X 3.6.11+ version support

DCloudUTSFoundation is a built-in library for the framework, and all uts plugins will depend on this basic library

DCloudUTSFoundation will encapsulate some common methods for developers to call directly

When using it, you need to import the UTSIOS class in the uts file first, and all methods are called through the UTSIOS class

// Import UTSIOS class from DCloudUTSFoundation dependent library
import { UTSiOS } from "DCloudUTSFoundation"

# 4.1 getCurrentViewController(): UIViewController

HBuilder X 3.6.11+ version support

Get the UIViewController instance displayed by the current app

Take uts-alert in hello uts as an example:

Example file location in hello uts:

~/uni_modules/uts-alert/utssdk/app-ios/index.uts

export function showAlert(title: string|null, message: string|null, result: (index: Number) => void) {
	// The uts method will be executed in the sub-thread by default, and the UI operations involved must run in the main thread, and the code can be run in the main thread through the DispatchQueue.main.async method
	DispatchQueue.main.async(execute=():void => {
		
		// Initialize UIAlertController instance object alert
		let alert = new UIAlertController(title=title,message=message,preferredStyle=UIAlertController.Style.alert)
		
		// create UIAlertAction button
		let okAction = new UIAlertAction(title="确认", style=UIAlertAction.Style.default, handler=(action: UIAlertAction):void => {
			// callback method for clicking the button
			result(0)
		})
		
		// create UIAlertAction button
		let cancelAction = new UIAlertAction(title="取消", style=UIAlertAction.Style.cancel, handler=(action: UIAlertAction):void => {
			// callback method for clicking the button
			result(1)
		})
		
		// Add UIAlertAction to alert
		alert.addAction(okAction)
		alert.addAction(cancelAction)
		
		// Open the alert popup
		UTSiOS.getCurrentViewController().present(alert, animated= true)
	})
}

# 4.2 colorWithString(value: string): UIColor

HBuilder X 3.6.11+ version support

Convert string color value to UIColor

format support

  • Simplified hexadecimal such as: #f00
  • Hexadecimal eg: #ff0000
  • RGB such as: rgb(255, 0, 0)
  • RGBA such as: rgba(255, 0, 0, 0.5)
  • Color value keywords, such as: red

example

let bgColor = UTSiOS.colorWithString("#000000")
view.backgroundColor = bgColor

# 4.3 getResourcePath(resourceName: string): string

HBuilder X 3.6.11+ version support

Get the runtime absolute path of the specified plugin resource

For the resource path of the socket, please pass the absolute path of the resource in the project directory

example

const imagePath = UTSiOS.getResourcePath("/static/logo.png")
console.log(imagePath)
const image = new UIImage(contentsOfFile = imagePath)
/* imagePath: "/var/mobile/Containers/Data/Application/FA7080BA-3EF7-4C4E-B7C5-0332539B2964/Documents/Pandora/apps/__UNI__FB95CAB/www/static/logo.png" */

Continuously updating

# 5 Key differences between swift and UTS (continuously updated)

Read through the chapters above.

So far we think you have mastered UTS syntax, basic swift syntax, and UTS support for iOS resources.

But for a swift language user who is familiar with iOS development, there are many common habits that have changed, and we will specifically point out in this chapter, so that developers can deepen their understanding.

# 5.1 Syntax differences


# 5.1.1 Constants and variables

In swift, let is used to declare constants, and var is used to declare variables

// swift
var str = "abc" // 声明一个字符串变量
let str1 = "abc" // 声明一个字符串常量

In uts, use const to declare constants, and let to declare variables

// swift
let str = "abc" // 声明一个字符串变量
const str1 = "abc" // 声明一个字符串常量

# 5.1.2 Optional types

Optional types in swift are defined as type?

// swift
var user: String? = nil

Optional types in uts are defined as type | null

// uts
let user: string | null = null

# 5.1.3 Call the constructor

There is no need to use the new keyword when calling the constructor to create an instance object in swift

var alert = UIAlertController()

When calling the constructor in uts to instantiate an object, you need to add the new keyword before the constructor

var alert = new UIAlertController()

# 5.1.4 函数参数

在 swift 中参数名称使用 : 连接参数值,在 uts 中需要使用 = 连接

example

// swift
var alert = UIAlertController(title: "提示", message: "提示内容", preferredStyle: .alert);
// written in uts
let alert = new UIAlertController(title="提示", message="提示内容", preferredStyle=UIAlertController.Style.alert)

# 5.1.5 Enumeration value

Enumerations can ignore the enumeration type and directly abbreviate .enumeration value in swift. UTS does not support abbreviation. You need to write enumeration type.enumeration value in its entirety In the above example, the value of the last parameter preferredStyle in swift can be abbreviated as

.alert

in uts requires full write out

UIAlertController.Style.alert

枚举在 swift 中可以定义关联类型,可在关联值中传递信息,但是在 ts 中没有这种语法,所以目前 uts 还暂不支持此种用法。


// 定义带关联值的枚举
enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

// 定义枚举值
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")

// 匹配
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
    print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
    print("QR code: \(productCode).")
}

如果遇到上述类型的枚举,且在三方库中无法改动的,可以在 Swift 文件中进行调用,然后把 该 Swift 文件打包在 framework 中供 uts 插件使用; 如果上述类型的枚举定义在有源码的 swift 中时,可以将其定义成不包含关联值的枚举,然后使用合适的数据结构来表示关联值携带的信息。

# 5.1.6 Class Inheritance

When defining a subclass in swift to inherit from the parent class, you need to add the parent class name after the subclass name, separated by a colon :

// swift
class Son: Father {
    
}

The extends keyword needs to be used instead of the colon : in uts

// uts
class Son extends Father {

}

# 5.1.7 Follow protocol methods

To make a custom type conform to a certain protocol in swift, when defining the type, you need to add the protocol name after the type name, separated by a colon :. When following multiple protocols, separate each protocol with a comma ,:

class SomeClass: FirstProtocol, AnotherProtocol {

}

The implements keyword needs to be used instead of the colon : in uts

class SomeClass implements FirstProtocol, AnotherProtocol {
	
}

# 5.1.8 System version judgment

The method of judging the system version in swift

// swift
if #available(iOS 10.0, *) {
    
}

This syntax is not supported in uts and can be replaced by the following

if (UTSiOS.available("iOS 10.0, *")) {

}

# 5.1.9 Closures

Closures in swift can be shortened

// If the last parameter in swift is a closure, it is called a trailing closure, which can be abbreviated as follows, regardless of the parameter label type
let action = UIAlertAction(title: "确认", style: .default) { action in
            
}

Shorthand syntax is not supported in uts, and the closure function needs to be written completely

// The closure function corresponding to the handler in uts must be written completely
let action = new UIAlertAction(title="确认", style=UIAlertAction.Style.default, handler=(action: UIAlertAction):void => {

})

原生中有些方法的闭包参数是逃逸闭包,此时就要在闭包前面添加 @escaping 标记:

// 在闭包参数前添加@escaping
function requestLocationPromise(@escaping completion: (res: boolean)=>void) {

}

# 5.1.10 target-action method

When calling native methods involving target-action in uts, such as adding click event methods to UIButton and registering notification center event methods, precautions,

  1. The selector required by the interface is constructed by the method of Selector("method name string")
  2. The defined callback method needs to be prefixed with @objc

The following is an example of listening to screen capture events:

Example file location in hello uts:

~/uni_modules/uts-screenshot-listener/utssdk/app-ios/index.uts

// Register to monitor screen capture events and callback methods
// The target-action callback method needs to be constructed by Selector("method name")
const method = Selector("userDidTakeScreenshot")
NotificationCenter.default.addObserver(this, selector = method, name = UIApplication.userDidTakeScreenshotNotification, object = null)

// method to capture screenshot callback
// The method of target-action needs to be prefixed with @objc
@objc static userDidTakeScreenshot() {
    const obj = new UTSJSONObject()
    // callback
    this.listener?.(obj)
}

# 5.1.11 Dictionary type

Dictionary type in swift, use Map type in uts instead

// swift
var value: Dictionary<String,Any> = Dictionary()
value["name"] = "uts"
// uts
let map: Map<string,any> = new Map()
map.set("name","uts")

# 5.1.12 参数标签的兼容问题

HBuilder X 3.6.11+ version support

When overriding the system method or implementing the protocol method of the third-party SDK, some methods may have parameter labels

Taking Tencent positioning in hello uts as an example, the protocol method needs to be implemented when monitoring location changes:

tencentLBSLocationManager(_ manager: TencentLBSLocationManager, didUpdate location: TencentLBSLocation)

The second parameter of this method has didUpdate parameter label

The implementation in native swift is

// swift
func tencentLBSLocationManager(_ manager: TencentLBSLocationManager, didUpdate location: TencentLBSLocation) {
        var response = LocationResponse();
        response.name = location.name;
        response.address = location.address;
        response.latitude = NSNumber(location.location.coordinate.latitude);
        response.longitude = NSNumber(location.location.coordinate.longitude);
        self.locationOptions?.success(response);
}

In uts, the annotation syntax @argumentLabel("didUpdate") needs to be used to represent the parameter label

// uts
// The delegate method that implements location updates
tencentLBSLocationManager(manager: TencentLBSLocationManager, @argumentLabel("didUpdate") location: TencentLBSLocation) {
		let response = new LocationResponse();
		response.name = location.name;
		response.address = location.address;
		response.latitude = Number(location.location.coordinate.latitude);
		response.longitude = Number(location.location.coordinate.longitude);
		this.locationOptions?.success(response)
}

Example file location in hello uts:

~/uni_modules/uts-tencentgeolocation/utssdk/app-ios/index.uts

# 5.1.12.1 无参数标签

只写参数名称的参数,编译后会在参数前默认增加 _ 来忽略参数标签(如上面的示例,第一个参数 manager,这种方式能兼容绝大多数方法,尤其是Swift 调用 OC 方法),但是有些参数没有参数标签,默认添加 _ 的行为会和原生方法定义不一致,这种情况需要定义一个空的参数标签来解决 @argumentLabel("didUpdate")

以高德定位 SDK 的代理方法为例:第三个参数 reGeocode 只有参数名称,没有参数标签

// swift
func amapLocationManager(_ manager: AMapLocationManager!, didUpdate location: CLLocation!, reGeocode: AMapLocationReGeocode!)

uts 实现此方法时,需要给 reGeocode 参数添加一个空的参数标签

// uts
amapLocationManager(manager : AMapLocationManager, @argumentLabel("didUpdate") location : CLLocation, @argumentLabel("") reGeocode : AMapLocationReGeocode) {

}

# 5.1.13 Asynchronous methods

Swift marks a function or method as asynchronous, you can add the async keyword after the parameter list in its declaration

// swift 
@available(iOS 13.0.0, *)
func testAsync(_ opts: AsyncOptions) async -> UTSJSONObject {
    if (opts.type == "success") {
        opts.success("success");
    }
     else {
        opts.fail("fail");
    }
    opts.complete("complete");
    return UTSJSONObject([
        "name": "testAsync"
    ]);
}

The definition of an asynchronous method in uts is to add the async keyword at the beginning of the method

// uts
async function testAsync(opts: AsyncOptions) {
  if (opts.type == "success") {
    opts.success("success");
  } else {
    opts.fail("fail");
  }
  opts.complete("complete");
  return { name: "testAsync" };
}

Note: Using async to define an asynchronous method is only supported by iOS 13+ versions, and errors will be reported when calling in lower versions

# 5.1.14 try catch

swift中try有以下三种方式:

以JSON反序列化为例

  1. 使用try (注意:要和do {} catch {} 一起使用,捕获可能的异常)
// swift 
	do{
		let dict = try JSONSerialization.jsonObject(with: d, options: [])
		print(dict)
	}catch{
	   // catch 中默认提供error信息, 当序列化不成功是, 返回error
		print(error)
	}

  1. 使用try? 如果能发序列化成功,就返回成功的值,不能成功就返回nil
// swift 
// 注意:dict是个可选值
	let dict = try? JSONSerialization.jsonObject(with: data, options: [])

  1. 使用try! 强行try,如果不能反序列化成功,会造成应用闪退, 如果能序列化成功,就返回成功的值,注意该值是个可选值。
// swift 
// 注意:dict是个可选值
	let dict = try! JSONSerialization.jsonObject(with: data, options: [])

为了满足Swift上述语法,UTS使用特殊语法来支持,以上三种写法分别对应为:

  1. try
// uts
try {
	let dict = UTSiOS.try(JSONSerialization.jsonObject(with = data, options = []))
}catch (e) {
	console.log(e)
}
  1. try?
// uts
UTSiOS.try(JSONSerialization.jsonObject(with = data, options = []), "?" )

  1. try!
// uts
UTSiOS.try(JSONSerialization.jsonObject(with = data, options = []), "!" )

# 6 Frequently Asked Questions (continuously updated)

# 6.1 How to get the current UIViewController instance in UTS environment

Refer to the uts-alert plugin in the Hello UTS project

path:

~/uni_modules/uts-alert/utssdk/app-ios/index.uts

# 6.2 How to operate UI thread in UTS environment

DispatchQueue.main.async(execute=():void => {
	// The UI can be operated in the main thread
})

Refer to the uts-toast plugin in the Hello UTS project

path:

~/uni_modules/uts-toast/utssdk/app-ios/index.uts

# 7 Known open issues (continuously updated)

# 7.1 Syntax Tips

When HBuilderX currently writes iOS uts plugins, some grammatical hints will be missing and the parameter types will be inaccurate, for example:

  • The construction method of the class currently only prompts one, in fact there may be more than one;
  • Missing optional type identifier;
  • The parameter label is not marked and it is impossible to know whether to ignore the parameter label;
  • 不支持导入包含有子模块的原生模块;
  • 暂不支持.a依赖库的代码提示;

These issues will be optimized in subsequent versions

# 7.2 Syntax incompatibility issues

# 7.2.1 For loop syntax problem

  • for in loops currently have syntax compatibility issues
  • The for (int i = 0, i < array.length, i++) method currently has syntax compatibility issues

# 7.3 Type Compatibility Issues

  • 元组类型目前不支持

# 8 有关Swift语言创建的Framework和.a的Swift版本兼容性问题

  • 由于高版本XCode编译的Swift语言Framework动态库、静态库、.a库在低版本XCode上无法编译通过,因此存在Swift版本兼容性问题;
  • 目前打包机使用的XCode版本号是14.2,对应的Swift版本是5.7.2;
  • 请在编译Swift相关Framework和.a库时选择和打包机相同或者更低版本的XCode;
  • 选择比打包机更低版本XCode编译Swift库时请在Target->buildSettings设置Buid Libraries for Distribution 为Yes。
On This Page