18

Tapping a WidgetKit widget automatically launches its parent application. How can I detect if my application was launched from its WidgetKit widget extension?

I'm unable to find any documentation on capturing this in the applications AppDelegate and/or SceneDelegate.

Daniel Storm
  • 18,301
  • 9
  • 84
  • 152

3 Answers3

33

To detect an app launch from a WidgetKit widget extension where the parent application supports scenes you'll need to implement scene(_:openURLContexts:), for launching from a background state, and scene(_:willConnectTo:options:), for launching from a cold state, in your parent application's SceneDelegate. Also, add widgetURL(_:) to your widget's view.

Widget's View:

struct WidgetEntryView: View {
    
    var entry: SimpleEntry
    
    private static let deeplinkURL: URL = URL(string: "widget-deeplink://")!

    var body: some View {
        Text(entry.date, style: .time)
            .widgetURL(WidgetEntryView.deeplinkURL)
    }
    
}

Parent application's SceneDelegate:

// App launched
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let _: UIWindowScene = scene as? UIWindowScene else { return }
    maybeOpenedFromWidget(urlContexts: connectionOptions.urlContexts)
}

// App opened from background
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    maybeOpenedFromWidget(urlContexts: URLContexts)
}

private func maybeOpenedFromWidget(urlContexts: Set<UIOpenURLContext>) {
    guard let _: UIOpenURLContext = urlContexts.first(where: { $0.url.scheme == "widget-deeplink" }) else { return }
    print(" Launched from widget")
}
Daniel Storm
  • 18,301
  • 9
  • 84
  • 152
  • 8
    Why about apps doesn't support scene delegate? can implement from AppDelegate? – iOS.Lover Sep 18 '20 at 14:38
  • 1
    I am doing without swift ui excepts widgets support. How can I handle without scene delegate? – PradeepKN Oct 12 '20 at 22:19
  • Which method gets callback in Objective c?? – Ajith Kumar Nov 17 '20 at 10:19
  • 2
    For Objective C and Older projects you can use this function to intercept the URL `- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options` – Menan Vadivel Mar 26 '21 at 23:11
  • @iOS.Lover Per [docs](https://developer.apple.com/documentation/widgetkit/creating-a-widget-extension) it depends on which you have implemented. "When the widget receives an interaction, the system activates the containing app and passes the URL to onOpenURL(perform:), application(_:open:options:), or application(_:open:), depending on the life cycle your app uses." – mfaani Mar 17 '22 at 14:42
11

SwiftUI 2 life cycle

  1. Add widgetURL to your Widget view:
struct SimpleWidgetEntryView: View {
    var entry: SimpleProvider.Entry

    private static let deeplinkURL = URL(string: "widget-deeplink://")!

    var body: some View {
        Text("Widget")
            .widgetURL(Self.deeplinkURL)
    }
}
  1. Detect if the app is opened with a deeplink in onOpenURL:
@main
struct WidgetTestApp: App {
    @State var linkActive = false

    var body: some Scene {
        WindowGroup {
            NavigationView {
                VStack {
                    NavigationLink("", destination: Text("Opened from Widget"), isActive: $linkActive).hidden()
                    Text("Opened from App")
                }
            }
            .onOpenURL { url in
                guard url.scheme == "widget-deeplink" else { return }
                linkActive = true
            }
        }
    }
}

Here is a GitHub repository with different Widget examples including the DeepLink Widget.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
9

If you are setting widgetURL or Link control for Widget UI then containing app opens with application(_:open:options:). You can set additional data in URL to know source.

If you are not using widgetUrl or link control then containing app opens with application(_:continue:restorationHandler:) and userInfo has WidgetCenter.UserInfoKey. That should tell you App opened from widget and information about user's interaction.

k-thorat
  • 4,873
  • 1
  • 27
  • 36