前言

如何让我们的 Widget 和用户交互?而不仅仅是一个展示栏?

这个问题想必大家开发的过程中都遇到过吧?目前 iOS14-beta1 是只支持点击(tap)操作的,也就是说 Widget 无法使用滚动等手势来完成交互的。

但是这里的点击和我们 APP 里面的点击还略有不同: 只能通过 Link 来操作, 不能使用点击事件来操作

同时这里的 Link 还和软件内的 Link 不同,这里的 Link 只能用于跳转到自己 APP 内,如果需要使用 DeepLink 等就必须要在软件内再次跳转。

如果你没有看过前面的文章建议先阅读前面的文章:

项目地址:https://github.com/Littleor/iWidget

打造支付小部件

如何打造一款支付小部件用来快速唤醒支付宝和微信的扫一扫和付款码?

这里就需要用到 Link 了,下面让我们从零开始写小部件

1. 创建 Widget

前面已经详细写了如何创建一个 Widget,这里就不再赘述。

我们这里直接使用上一节的可配置的内容小部件来作为底板修改

初始代码

2. 修改 Provider

这里我们要做的是一款快捷支付小部件,无需更新故把 Provider 中的 timeline 改为.never

.never 的小部件仍然可以通过 WidgetCenter 调用 API 更新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
struct PayToolsProvider: IntentTimelineProvider {
    typealias Entry = SimpleEntry
    public func snapshot(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date())
        completion(entry)
    }
    
    public func timeline(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        let currentDate = Date()
        let entry = SimpleEntry(date: currentDate)
        let timeline = Timeline(entries: [entry], policy: .never)
        completion(timeline)
    }
}

其中的 SimpleEntry 为:

1
2
3
4
struct SimpleEntry: TimelineEntry {
    public let date: Date
    // 去除了 configure 毕竟快捷支付小部件没啥可以配置的
}

3. 修改 View

View 是我们需要注意的重点,无论是 Link 还是 widgetURL 都需要通过 View 来配置 这里我们直接先贴代码。其中的 IconWidgetItem 为我封装的一个 View,完整代码详见 iWidget

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
struct PayToolsMediumView: View {
    var body: some View {
        HStack(spacing: 3.0) {
            IconWidgetItem(icon:"qrcode",bottomIcon: "alipay",size: 70)
            IconWidgetItem(icon: "pay",bottomIcon: "alipay",size: 70,url: "alipay://platformapi/startapp?appId=20000056")
                .padding([.top, .leading, .bottom])
            IconWidgetItem(icon: "qrcode",bottomIcon: "wechat",size: 70, url: "weixin://scanqrcode")
                .padding(.all)
            IconWidgetItem(icon: "pay",bottomIcon: "wechat",size: 70, url: "weixin://")
        }
    }
}

其中 IconWidgetItem 代码:

 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
struct IconWidgetItem:View {
    var icon:String = "qrcode"
    var bottomIcon:String = "alipay"
    var size: CGFloat = 60
    var url: String  = "alipayqr://platformapi/startapp?saId=10000007"
    var body: some View {
    // 这里的 Link 是关键
        Link(destination: URL(string: url)!) {
            ZStack {
                ZStack {
                    Image(icon)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                }
                .frame(width: size, height: size, alignment: .center)
                .zIndex(1)
                HStack() {
                    Spacer()
                    VStack {
                        Spacer()
                        HStack {
                            Image(bottomIcon)
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .opacity(1)
                            
                        }
                        .frame(width: size/3, height: size/3, alignment: .center)
                        .background(Color.white)
                        .cornerRadius(size/6)
                        .shadow(radius: 1)
                    }
                    
                }
                .zIndex(2)
            }.frame(width: size, height: size, alignment: .center)
        }
        
    }
}

IconWidgetItem 中的 Link 是关键点,配置了 Link 就可以让 Widget 点击后跳转 APP 的时候带上 URL。

但是这个时候是不能点击打开这个 Link 的。而是打开了 APP。

4. 软件内部跳转

因为 Widget 无法直接打开 Link,所以我们只能退而求其次,这里我采用的是使用 NavigationView 的 onOpenURL 方法来实现跳转,如果有更好的方法欢迎留言或提交 PR!

1
2
3
4
5
6
    NavigationView{
        //...View
    }
  .onOpenURL(perform: { (url) in
            UIApplication.shared.open(url)
        })

如此即可实现 Widget 的 Link 通过 APP 跳转。

后记

iOS14 提供的 Widgetkit 大概内容也就到这里结束了,Widget 开发往简单来说需要做的无非是 Provider 和 View 和一点配置,配置好 Provider 和 View 我相信你也可以做出优雅的小部件!

最后如果你认为这些文章对你有用,欢迎给该 Github 项目 iWidget 点个 Star。

项目地址:https://github.com/Littleor/iWidget