WidgetKit — how to send data from Widget to main app

Back in the days of NCWidgetProviding, we had a button to open our app. We included code like the following in the app's info.plist:

	<key>CFBundleURLTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeRole</key>
			<string>Editor</string>
			<key>CFBundleURLName</key>
			<string>com.xxxx.yyyy/string>
			<key>CFBundleURLSchemes</key>
			<array>
				<string>yyyy</string>
			</array>
		</dict>
	</array>

and in the widget's button, we used code like:

    let appURL = URL(string: "yyyy://?url=\(zzz)")
    extensionContext?.open(appURL, completionHandler: nil)

How can I achieve the same result using WidgetKit? (I.e., sending a URI to my main app)?

The use case is that the widget displays a random record from a database and when the user taps on the widget, I want to open my app, displaying THAT SAME RECORD.

Thanks.

Replies

In my widget I have this wrapping the HStack of the main content:

Link(destination: updateEventToOpenInMainApp(event.name)) {
  HStack {
    ...
  }
  .widgetURL(updateEventToOpenInMainApp(event.name))
}

The updateEventToOpenInMainApp() function is this:

func updateEventToOpenInMainApp(_ name: String) -> URL {
	let activity: NSUserActivity = NSUserActivity.init(activityType: "ViewEventIntent")

	activity.title = kWidgetPreviewEvent // A String: "widget_PreviewEvent:"
	activity.userInfo = [kWidgetPreviewEvent : name]
	activity.becomeCurrent()

	let urlString: String = kWidgetPreviewEvent + name.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
	return URL(string: urlString)!
}

When the widget is tapped, the url is crafted as above, and sent to the main iOS app. The iOS app then has this in the AppDelegate (Objective-C):

- (BOOL)application:(UIApplication *)app openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
	if([url.path hasPrefix:kWidgetPreviewEvent]) {  // The prefix from earlier
		NSString *eventName = [[url.path stringByRemovingPercentEncoding] stringByReplacingOccurrencesOfString:kWidgetPreviewEvent withString:@""];
...

Works for me.

As @darkpaw code shows, widgetURL is the mechanism to wire up to your views and then to handle openURL in your SwiftUI app / views or ApplicationDelegate. Pre iOS 16, widgetURLs only worked on systemMedium and larger items from my recollection. It may have changed with all of the new Lock Screen widgets and support for widget kit on watchOS.

See WidgetURL API for more information.