SwiftUI如何使用DeepLink技术

一、什么是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)

Github

相关推荐
好家伙VCC6 分钟前
**发散创新:用 Rust实现数据编织(DataWrangling)的高效流式处理架构**在现
java·开发语言·python·架构·rust
红云梦11 分钟前
互联网三高-高性能之多级缓存架构
java·redis·缓存·架构·cdn
Mintopia1 小时前
组件契约文档的标准结构(可复制模板)
前端·架构
AI周红伟1 小时前
周红伟:OpenClaw 企业级智能体架构与全栈实战
人工智能·微信·架构·云计算·腾讯云·openclaw
为爱停留1 小时前
引入大模型与 RAG:价格预测准确率提升与架构实践
架构
六月的可乐1 小时前
AI Agent:从零构建生产级AI智能体脚手架的架构思考
人工智能·ai·架构·langchain·前端框架·node.js·a
无忧智库1 小时前
从单体到云原生:解构大型供应链系统的微服务演进与多租户治理之道(PPT)
微服务·云原生·架构
星辰_mya1 小时前
MVCC 与事务隔离:MySQL 如何实现“读不阻塞写”?
java·数据库·mysql·面试·架构
凸头2 小时前
从“搜了就答”到“智能决策”:拥抱 RAG 2.0 时代的架构演进 ——Java 后端工程师视角下的 AI 应用工程化落地
java·人工智能·架构·rag
MobotStone3 小时前
我的 AI 代码清理方法论:从原型到生产,只需 5 步
算法·程序员·架构