Perform a deeplink from SwiftUI widget on tap
- In the Widget view you need to create a
Link
and set itsdestination
url:
struct SimpleWidgetEntryView: View {
var entry: SimpleProvider.Entry
var body: some View {
Link(destination: URL(string: "widget://link1")!) {
Text("Link 1")
}
}
}
Note that Link
works in medium and large Widgets only. If you use a small Widget you need to use:
.widgetURL(URL(string: "widget://link0")!)
- In your App view receive the url using
onOpenURL
:
@main
struct WidgetTestApp: App {
var body: some Scene {
WindowGroup {
Text("Test")
.onOpenURL { url in
print("Received deep link: \(url)")
}
}
}
}
It is also possible to receive deep links in the SceneDelegate
by overriding:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)
You can find more explanation on how to use this function in this thread:
- Detect app launch from WidgetKit widget extension
Here is a GitHub repository with different Widget examples including the DeepLink Widget.
How to perform deeplink from widget to parent app in Objective C
Which method in AppDelegate I will get the callback?
You can use application:openURL:options:
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options;
SwiftUI small widget is not opening the iOS app on tap
I don’t know why the app doesn’t open (an iOS bug, I guess), but your deeplink won’t work because Link
isn’t available in the “small” widget size. You need to set the .widgetURL()
modifier on your view instead.
How to use Link in WidgetKit to define arbitrary regions, not just text links?
The type definition of Link
is actually struct Link<Label> where Label : View
so the only constraint to Label
is that it conforms to the View
protocol (despite the name indicating otherwise). My preferred initializer is init(destination:, label:)
so you can embed every view in the view builder like this:
Link(destination: URL(string: "some://dest")!) {
HStack {
Text("I'm part of the tappable area")
Text("Me too")
}
}
You can actually see this in action in the Emoji Rangers project from Apple (check AllCharactersView.swift
.
Detect app launch from WidgetKit widget extension
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")
}
How Can I Handle Tap Gesture on Widget?
Okay I created a new project with SwiftUI Environments (not old way AppDelegate and SceneDelegate).
Then I use Link for tap actions and I got it with .onOpenURL modifier in ContentView. It works :)
ContentView:
import SwiftUI
enum SelectedTab: Hashable {
case home
case standings
case options
}
struct ContentView: View {
@State var selectedTab: SelectedTab = .home
var body: some View {
TabView(selection: self.$selectedTab) {
Text("Home")
.tabItem {
Image(systemName: "house")
.renderingMode(.template)
Text("Home")
}.tag(SelectedTab.home)
Text("Standings")
.tabItem {
Image(systemName: "list.number")
.renderingMode(.template)
Text("Standings")
}.tag(SelectedTab.standings)
Text("Options")
.tabItem {
Image(systemName: "gear")
.renderingMode(.template)
Text("Options")
}.tag(SelectedTab.options)
.onOpenURL { (url) in
if url.absoluteString == "widget-deeplink://standings"{
self.selectedTab = .standings
}
}
}
}
}
Link usage example in Widget:
Link(destination: URL(string: "widget-deeplink://standings")!) {
Text("Link Test")
}
Related Topics
How to Get the Front Camera in Swift
Main.Async VS Main.Sync() VS Global().Async in Swift3 Gcd
Application(...Continue Useractivity...) Method Not Called in iOS 13
How to Add an Identifier to Auto Layout Constraints in Interface Builder
How to Scroll to a Particluar Index in Collection View in Swift
Fcm Push Notifications Do Not Work on iOS 11
Not Receiving Push Notifications from Firebase
Swift Compatibility Between Versions for a Library
How to Load Icarousel View from Storyboard or Xib
How to Restrict Uitextfield to Take Only Numbers in Swift
Make Uicollectionview Zoomable
Change the Root View of Uihostingcontroller in Swiftui
Error Itms-90086 Submitting App
How to Parse Iso 8601 Using Nsdateformatter with Optional Milliseconds Part