Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect app launch from WidgetKit widget extension

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.

like image 837
Daniel Storm Avatar asked Sep 02 '20 00:09

Daniel Storm


3 Answers

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")
}
like image 188
Daniel Storm Avatar answered Oct 10 '22 21:10

Daniel Storm


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.

like image 23
k-thorat Avatar answered Oct 10 '22 20:10

k-thorat


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.

like image 32
pawello2222 Avatar answered Oct 10 '22 21:10

pawello2222