Create Today Extension (Widget) with SwiftUI

Published by @SoNiceInfo at 7/5/2020


I'll show you how to create a Today Extension (widget) using the SwiftUI.

If you want to know about the new widgets from iOS 14 announced at WWDC20, please see Create Widget Extension.

Develop Today Extension with SwiftUI

Add Today Extension

Step to add Today Extension

Go to File → New → Target... then dialog appears, select Today Extension and press Select.
Enter the appropriate Product Name and Finish.

Enable Scheme of Today Extension

Press Activate when asked when activating "PRODUCT_NAME" scheme.
TodayViewController.swift, MainInterface.storyboard and info.plist will be added in the new directory.
You are now ready to create a Today Extension.

First version of Today Extension

By default, the Today Extension shows "Hello World".

Delete Hello World on MainInterface.storyboard

First version of Storyboard

The contents of the MainInterface.storyboard looks like this
This time we'll be developing with SwiftUI instead of Storyboard, so we'll remove the Hello World label.

Make Background default none at Storyboard

At this point, make the background to the none at the right pane. Or please select your color.

Prepare SwiftUI View

File → New → File... (⌘N) to select SwiftUI View.
Here, the file name is WidgetView.

//
//  WidgetView.swift
//

import SwiftUI

struct WidgetView: View {
    var body: some View {
        HStack {
            Image(systemName: "globe")
            Text("Hello, SwiftUI!")
        }
        .font(.title)
    }
}

struct WidgetView_Previews: PreviewProvider {
    static var previews: some View {
        WidgetView()
    }
}

Call WidgetView in TodayViewController

In viewDidLoad, use UIHostingController to call WidgetView.
Don't forget to import SwiftUI.
After that, let it automatically determine the display area and make the background clear.

//
//  TodayViewController.swift
//

import UIKit
import NotificationCenter
import SwiftUI

class TodayViewController: UIViewController, NCWidgetProviding {
        
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        let vc  = UIHostingController(rootView: WidgetView())
        self.addChild(vc)
        self.view.addSubview(vc.view)
        vc.didMove(toParent: self)

        vc.view.translatesAutoresizingMaskIntoConstraints = false
        vc.view.heightAnchor.constraint(equalTo: self.view.heightAnchor).isActive = true
        vc.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
        vc.view.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
        vc.view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
        vc.view.backgroundColor = UIColor.clear
    }
        
    func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
        // Perform any setup necessary in order to update the view.
        
        // If an error is encountered, use NCUpdateResult.Failed
        // If there's no update required, use NCUpdateResult.NoData
        // If there's an update, use NCUpdateResult.NewData
        
        completionHandler(NCUpdateResult.newData)
    }
    
}

Completion

We can create Today Extension with SwiftUI

I published the code at GitHub.d1v1b/WidgetSample: Today Extension Sample with SwiftUI

iOS 14 Support

New "Widgets" have been announced for iOS 14 that can be placed on the home screen.
You can continue to use the Today Extension in iOS 14 using the methods here.
If you want to know about the new widgets from iOS 14 announced at WWDC20, please see Create Widget Extension.

References

一部の画面だけSwiftUIを使いたいとき - Qiita


    I released iOS App!

    ToDo App

    Visualize Activity, Data sharing with iCloud, Dark mode supported.

    リリースしたToDoアプリのスクリーンショット

    IP Address bookmark.

    Check and bookamrk IP address of all interfaces with geolocation.

    リリースしたIPアドレス保存アプリのスクリーンショット