Coding01

Coding 点滴

0%

学习 iOS Widgets 开发之 exchange 动态获取选项

在之前的写货币兑换的小组件文章中,我们采用 Enum 静态的方式写入我们的货币选择,今天我们改用动态的,一方面是学习如何通过代码的形式动态修改选项,另一方面是为了之后扩展需要,将选项放到接口中实时动态调整。

Enum && Type

Enum

简单的理解就是 Enums 是写死在 .intentdefinition 文件中的静态配置,只有发版才可以更新。

Type
Types 就灵活多了,可以在运行时动态的生成,一般而言我们使用 Types 来做自定义选项。

IntentHandling

我们在 Intent 中将我们的 From 和 To 类型改为 Type,并增加一个 Type 类型:

重点是选择:Options are provided dynamically

这样,系统会为我们自动生成一个数据操作协议 ExchangeIntentHandling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public protocol ExchangeIntentHandling: NSObjectProtocol {

/*!
@abstract Dynamic options methods - provide options for the parameter at runtime
@discussion Called to query dynamic options for the parameter and this intent in its current form.

@param intent The input intent
@param completion The response block contains options for the parameter
*/
@available(iOS 14.0, macOS 10.16, watchOS 7.0, *)
@objc(provideFromOptionsCollectionForExchange:withCompletion:)
func provideFromOptionsCollection(for intent: ExchangeIntent, with completion: @escaping (INObjectCollection<Exchange>?, Error?) -> Swift.Void)

@available(iOS 14.0, macOS 10.16, watchOS 7.0, *)
@objc(provideToOptionsCollectionForExchange:withCompletion:)
func provideToOptionsCollection(for intent: ExchangeIntent, with completion: @escaping (INObjectCollection<Exchange>?, Error?) -> Swift.Void)

/*!
@abstract Confirmation method - Validate that this intent is ready for the next step (i.e. handling)
@discussion Called prior to asking the app to handle the intent. The app should return a response object that contains additional information about the intent, which may be relevant for the system to show the user prior to handling. If unimplemented, the system will assume the intent is valid, and will assume there is no additional information relevant to this intent.

@param intent The input intent
@param completion The response block contains a ExchangeIntentResponse containing additional details about the intent that may be relevant for the system to show the user prior to handling.

@see ExchangeIntentResponse
*/
@objc(confirmExchange:completion:)
optional func confirm(intent: ExchangeIntent, completion: @escaping (ExchangeIntentResponse) -> Swift.Void)

/*!
@abstract Handling method - Execute the task represented by the ExchangeIntent that's passed in
@discussion Called to actually execute the intent. The app must return a response for this intent.

@param intent The input intent
@param completion The response handling block takes a ExchangeIntentResponse containing the details of the result of having executed the intent

@see ExchangeIntentResponse
*/
@objc(handleExchange:completion:)
optional func handle(intent: ExchangeIntent, completion: @escaping (ExchangeIntentResponse) -> Swift.Void)

/*!
@abstract Default values for parameters with dynamic options
@discussion Called to query the parameter default value.
*/
@available(iOS 14.0, macOS 10.16, watchOS 7.0, *)
@objc(defaultFromForExchange:)
optional func defaultFrom(for intent: ExchangeIntent) -> Exchange?

@available(iOS 14.0, macOS 10.16, watchOS 7.0, *)
@objc(defaultToForExchange:)
optional func defaultTo(for intent: ExchangeIntent) -> Exchange?

}

主要是需要我们集成写入我们的参数数组和有可能的需要设置默认值。

IntentHandler

接下来,我们新建一个 target 完成数据填充的工作:

还必须选择小部件 .intentdefinition 文件并将其添加到ExchangeWidgetIntentHandler 目标:

增加动态数据集:

1
2
3
4
5
6
7
8
9
10
11
import Intents

class IntentHandler: INExtension, ExchangeIntentHandling {
func provideFromOptionsCollection(for intent: ExchangeIntent, with completion: @escaping (INObjectCollection<Exchange>?, Error?) -> Void) {
completion(INObjectCollection(items: Exchange.exchanges), nil)
}

func provideToOptionsCollection(for intent: ExchangeIntent, with completion: @escaping (INObjectCollection<Exchange>?, Error?) -> Void) {
completion(INObjectCollection(items: Exchange.exchanges), nil)
}
}

数据集目前我们写成静态数组,之后可以根据需要动态调整:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static var exchanges: [Exchange] {
[
Exchange(identifier: "CNY", display: "人民币"),
Exchange(identifier: "USD", display: "美元"),
Exchange(identifier: "GBP", display: "英镑"),
Exchange(identifier: "EUR", display: "欧元"),
Exchange(identifier: "CAD", display: "加拿大元"),
Exchange(identifier: "HKD", display: "港元"),
Exchange(identifier: "MOP", display: "澳门元"),
Exchange(identifier: "THB", display: "泰铢"),
Exchange(identifier: "SGD", display: "新加坡元")
]
}

接下来需要把我们关联的 Intent 加入 Info 中:

测试

有了数据以后,我们测试看看:

随着我们的数据变化,看看显示结果:

总结

有了动态配置选项,下一步就是考虑如何做主 APP 和 Widget 的数据互动了。

Welcome to my other publishing channels