一、什么是DeepLink
点击一个链接,可以在App内直接链接到某个页面。在UIKit时代,已经有很多的解决方案了。最近在做一个SwiftUI的项目。研究了下解决方案。
1、短信
ruby
SMS://
2、电话
arduino
tel://
3、微信扫一扫
arduino
weixin://dl/scan
我们在此创建一个名字为arc的工程,我们定义协议名为arc,域名为hong.com,个人主页的页面名为profilePage,那么,完整的链接地址应该就是arc://hong.com/profilePage,如果需要打开某个人的个人主页,我们需要加上一个参数,arc://hong.com/profilePage?name=michael
二、App是如何导航的
在屏幕较小的设备我们通常使用tab空间来区分不同的模块,使用导航来进入到该模块更深的层级,在较大屏幕的设备上一般使用侧边栏来区分不同的模块,同样使用导航来进入到该模块更深的层级。

二、模块内的Navigation导航
在导航方面,我们想要的是一个标识符对应一个页面,最终我找到了navigationstack来胜任这个工作。
developer.apple.com/documentati...
scss
NavigationStack {
List(parks) { park in
NavigationLink(park.name, value: park)
}
.navigationDestination(for: Park.self) { park in
ParkDetails(park: park)
}
}
我们创建一个ViewModel,创建一个homeNavStack变量来维护这个导航的深度信息
kotlin
import SwiftUI
// ViewModel for App
class AppData: ObservableObject {
/// Home NavigationStatck
@Published var homeNavStack: [String] = []
}
如果想回到导航的Root页面话,可以直接设置homeNavStack=[]
三、模块之间的导航
现在以iOS的tab为例
1、创建一个Tab的枚举
swift
import SwiftUI
public enum Tab:String, CaseIterable {
case home = "0"
case profile = "1"
@ViewBuilder
var label: some View {
switch self {
case .home:
Label("Home", systemImage: "house")
case .profile:
Label("Profile", systemImage: "person.crop.circle")
}
}
static func convert(from:String) -> Self?{
return Tab.allCases.first{ tab in
tab.rawValue.lowercased() == from.lowercased()
}
}
}
2、在AppData中新增一个变量维护当前选中的tab,默认选中home
less
import SwiftUI
// ViewModel for App
class AppData: ObservableObject {
@Published var activeTab: Tab = .home
/// Home NavigationStatck
@Published var homeNavStack: [String] = []
}
3、创建一个Router
swift
protocol DeepLink {
var pageParams: [String: String]? { get set }
}
struct Router {
static func NavDestinationForWith(_ page: String)-> AnyView{
var view:any View;
switch page {
case "purplepage":
view = PurlplePage()
case "yellowpage":
view = YellowPage()
case "aboutpage":
view = AboutPage()
default:
view = EmptyView()
}
if var deepLinkView = view as? any DeepLink & View{
deepLinkView.pageParams = ["name":"huanghong"]
return AnyView(deepLinkView)
}else{
return AnyView(view)
}
}
}
4、创建页面结构
swift
let scheme = "arc" // protocol
let host = "hong.com" // host
struct ContentView: View {
@EnvironmentObject private var appData:AppData
var body: some View {
TabView(selection: $appData.activeTab,
content: {
HomeView()
.tag(Tab.home)
.tabItem {
Tab.home.label
}
ProfileView()
.tag(Tab.profile)
.tabItem {
Tab.profile.label
}
})
.onOpenURL(perform:onOpenURL)
}
@ViewBuilder
func HomeView() -> some View{
NavigationStack(path: $appData.homeNavStack){
HomePage()
.navigationTitle("Home")
.navigationDestination(for: String.self) { page in
Router.NavDestinationForWith(page)
.environmentObject(appData)
}
}
}
@ViewBuilder
func ProfileView() -> some View{
NavigationStack(path: $appData.profileNavStack){
ProfilePage()
.navigationTitle("Profile")
.navigationDestination(for: String.self) { page in
Router.NavDestinationForWith(page)
}
}
}
/// 应用内打开链接
func onOpenURL(url:URL){
if (scheme != url.scheme){
return;
}
if (host != url.host()){
return;
}
// 解析page
let pathComponents = url.pathComponents
guard let page = pathComponents.last else{
return
}
// 解析params
let params = pageParams(url)
// Tab页面
if page.lowercased() == "tab" {
guard let params = params, let tabIndex = params["tabIndex"] ,let tabRawValue = Tab.convert(from: tabIndex) else {
return
}
appData.activeTab = tabRawValue
return
}
// 正常页面导航
switch appData.activeTab {
case .home:
appData.homeNavStack.append(page)
case .profile:
appData.profileNavStack.append(page)
}
}
/// 获取页面的参数
func pageParams(_ url: URL) -> Dictionary<String, String>? {
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)
guard let queryItems = components?.queryItems else{
return nil
}
var paramMap = [String: String]()
for item in queryItems {
if let value = item.value {
paramMap[item.name] = value
}
}
return paramMap
}
}
四、打开任意页面
1、在工程中配置scheme
2、打开任意页面
csharp
let url = URL.init(string: "arc://hong.com/aboutpage")!
UIApplication.shared.open(url)