Dad Jokes & Puns is a mobile app that showcases all my favorite dad jokes. When you open the app, you'll see a list of jokes. Tapping on a joke will take you to the joke detail screen. The app also supports widgets and deep linking from the widget to the joke detail screen.
Behind the scenes, I utilized a custom URL scheme to handle deep linking. Here's all you need to support deep linking with a custom URL scheme.
struct Joke: Identifiable, Hashable {
var id: Int
let conetnt: String
}
enum Screen: Hashable {
case detail(Joke)
}
struct JokeListView: View {
@State private var presentedScreen: [Screen] = []
var jokes: [Joke] = [...]
var body: some View {
NavigationStack(path: $presentedScreen) {
List(jokes) { joke in
Text(joke.content)
.onTapGesture {
presentedScreen = [.detail(joke)]
}
}
.navigationDestination(for: Screen.self) { screen in
switch screen {
case .detail(let joke):
JokeDetailView(joke: joke)
}
}
}
.onOpenURL { url in
handleOpenURL(url)
}
}
}
struct JokeDetailView: View {
var joke: Joke
var body: some View {
Text(joke.content)
.font(.title)
.multilineTextAlignment(.center)
.padding()
}
}
dadjokes://open?id=123
struct SimpleEntry: TimelineEntry {
let date: Date
let joke: Joke
}
struct DadJokesWidgetEntryView : View {
var entry: Provider.Entry
var jokeDeeplink: URL? {
URL(string: "dadjokes://open?id=\\(entry.joke.id)")
}
var body: some View {
VStack {
Text(entry.joke.content)
}
.widgetURL(jokeDeeplink)
}
}
func handleOpenURL(_ url: URL) {
if let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
components.scheme == "dadjokes",
let jokeId = components.queryItems?.first(where: { $0.name == "id"} )?.value,
let joke = jokes.first(where: { $0.id == Int(jokeId) }) {
presentedScreen = [.detail(joke)]
}
}