<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          iOS 中的深度鏈接和 URL 方案

          共 12491字,需瀏覽 25分鐘

           ·

          2022-11-15 07:38

          ????關(guān)注后回復(fù) “進(jìn)群” ,拉你進(jìn)程序員交流群????

          從 URL 打開應(yīng)用程序是一項(xiàng)非常強(qiáng)大的 iOS 功能。它將用戶吸引到您的應(yīng)用程序,并可以創(chuàng)建特定功能的快捷方式。本周,我們將深入探討 iOS 上的深度鏈接以及如何為您的應(yīng)用創(chuàng)建 URL 方案。

          當(dāng)我們談?wù)撘苿?dòng)應(yīng)用程序的深度鏈接時(shí),它意味著創(chuàng)建一個(gè)特定的 URL 來打開移動(dòng)應(yīng)用程序。它分為兩種格式:

          • 您的應(yīng)用注冊的自定義 URL 方案:scheme://videos
          • 從注冊域打開您的應(yīng)用程序的通用鏈接:[1]mydomain.com/videos

          今天,我們將專注于前者。

          我將主要關(guān)注 UIKit 實(shí)現(xiàn)的代碼,但如果您也在尋找它,我還將簡要介紹 SwiftUI。

          設(shè)置 URL 方案

          無論您使用的是 SwiftUI 還是 UIKit,為 iOS 設(shè)置自定義 URL 方案都是相同的。在 Xcode 中,在您的項(xiàng)目配置下,選擇您的目標(biāo)并導(dǎo)航到Info選項(xiàng)卡。您會(huì)URL Types在底部看到一個(gè)部分。

          深層鏈接 url 方案

          單擊+,我可以創(chuàng)建一個(gè)新類型。對(duì)于標(biāo)識(shí)符,我經(jīng)常重復(fù)使用 app bundle。對(duì)于 URL 方案,我建議使用應(yīng)用程序名稱(或縮短)盡可能短。它不應(yīng)包含任何自定義字符。例如,我將使用deeplink.

          而已。該應(yīng)用程序已準(zhǔn)備好識(shí)別新 URL,現(xiàn)在我們需要在收到新 URL 時(shí)對(duì)其進(jìn)行處理。

          SwiftUI 深度鏈接。

          如果你沒有任何AppDelegateSceneDelegate文件,這是 SwiftUI 實(shí)現(xiàn)的大多數(shù)情況,我們沒有太多工作要做。

          在 App 實(shí)現(xiàn)中,我們可以捕獲從onOpenURL(perform:)操作中打開的 url。

          import SwiftUI

          @main
          struct DeeplinkSampleApp: App {
              var body: some Scene {
                  WindowGroup {
                      ContentView()
                          .onOpenURL { url in
                              print(url.absoluteString)
                          }
                  }
              }
          }

          為了測試它,我可以在模擬器上安裝應(yīng)用程序并從終端應(yīng)用程序啟動(dòng)給定的 url

          xcrun simctl openurl booted "deeplink://test"

          很酷!讓我們看看 UIKit 的實(shí)現(xiàn)有何不同。

          UIKit 深層鏈接

          在紙面上,UIKit 或 SwiftUI 不應(yīng)該對(duì)我們處理深度鏈接的方式產(chǎn)生影響。然而,它主要?dú)w結(jié)為對(duì)于 UIKit 應(yīng)用程序更常見的一個(gè)AppDelegate或一個(gè)。SceneDelegate

          對(duì)于只有 的舊應(yīng)用AppDelegate,該應(yīng)用通過以下方法捕獲深度鏈接打開。

          extension AppDelegate {

              func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {

                  print(url.absolueString)
                  return true
              }
          }

          如果應(yīng)用程序可以處理給定的 url,則該函數(shù)返回一個(gè)布爾值。

          對(duì)于包含 的較新應(yīng)用程序,SceneDelegate回調(diào)將在那里。重要的是要注意AppDelegate,即使您實(shí)現(xiàn)它,也不會(huì)調(diào)用它。

          extension SceneDelegate {
              func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
                  guard let firstUrl = URLContexts.first?.url else {
                      return
                  }

                  print(firstUrl.absoluteString)
              }
          }

          在這個(gè)實(shí)現(xiàn)中,我們可以注意到我們不再需要返回任何結(jié)果。但是,現(xiàn)在傳遞的參數(shù)是 aSet<>而不僅僅是 a URL,它是打開一個(gè)或多個(gè) URL。我沒有一個(gè)用例,我們會(huì)擁有更多的 URL,所以我暫時(shí)只保留一個(gè)。

          與之前一樣,我們可以在模擬器上安裝應(yīng)用程序并嘗試查看是否所有設(shè)置正確。我們應(yīng)該看到打印我們的深層鏈接 URL。

          xcrun simctl openurl booted "deeplink://test"

          設(shè)置完成后,我們的想法是創(chuàng)建路線以識(shí)別和打開正確的屏幕。讓我們潛入水中。

          深度鏈接處理程序?qū)崿F(xiàn)

          這個(gè)想法很簡單,對(duì)于給定的鏈接,我們需要確定我們應(yīng)該打開什么用戶旅程或屏幕。因?yàn)樗鼈兛梢允钦麄€(gè)應(yīng)用程序的許多功能,并且因?yàn)槲覀兿M苊獯罅?code style="font-size: 14px;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">switch case處理它,所以我們將變得更聰明并且分而治之。

          對(duì)于這個(gè)例子,讓我們想象一下我們有一個(gè)視頻編輯應(yīng)用程序。它們是 3 個(gè)主要選項(xiàng)卡,用于編輯新視頻、列出已編輯的視頻,然后是包含不同應(yīng)用程序和用戶信息的帳戶頁面。

          我們可以想到三個(gè)主要路徑

          • deeplink://videos/new- 開始新的視頻編輯之旅

          • deeplink://videos- 登陸視頻列表選項(xiàng)卡屏幕

          • deeplink://account- 登陸帳戶屏幕

          首先,我將創(chuàng)建一個(gè)深度鏈接處理程序協(xié)議來定義任何新處理程序的最低要求。

          protocol DeeplinkHandlerProtocol {
              func canOpenURL(_ url: URL) -> Bool
              func openURL(_ url: URL)
          }

          我還將定義一個(gè)DeeplinkCoordinator將保留在處理程序上并找到正確使用的處理程序。它還像AppDelegatehas 一樣返回一個(gè)布爾值,因此我們可以在不同的實(shí)現(xiàn)中使用。

          protocol DeeplinkCoordinatorProtocol {
              @discardableResult
              func handleURL(_ url: URL) -> Bool
          }

          final class DeeplinkCoordinator {

              let handlers: [DeeplinkHandlerProtocol]

              init(handlers: [DeeplinkHandlerProtocol]) {
                  self.handlers = handlers
              }
          }

          extension DeeplinkCoordinator: DeeplinkCoordinatorProtocol {

              @discardableResult
              func handleURL(_ url: URL) -> Bool{
                  guard let handler = handlers.first(where: { $0.canOpenURL(url) }) else {
                      return false
                  }

                  handler.openURL(url)
                  return true
              }
          }

          現(xiàn)在我們可以定義單獨(dú)的處理程序,每個(gè)不同的路徑一個(gè)。讓我們首先從最簡單的帳戶旅程開始。

          final class AccountDeeplinkHandler: DeeplinkHandlerProtocol {

              private weak var rootViewController: UIViewController?
              init(rootViewController: UIViewController?) {
                  self.rootViewController = rootViewController
              }

              // MARK: - DeeplinkHandlerProtocol

              func canOpenURL(_ url: URL) -> Bool {
                  return url.absoluteString == "deeplink://account"
              }

              func openURL(_ url: URL) {
                  guard canOpenURL(url) else {
                      return
                  }

                  // mock the navigation
                  let viewController = UIViewController()
                  viewController.title = "Account"
                  viewController.view.backgroundColor = .yellow
                  rootViewController?.present(viewController, animated: true)
              }
          }

          為了簡單起見,我只測試匹配的 url 并導(dǎo)航到正確的屏幕。我還設(shè)置了背景顏色,看看我的著陸點(diǎn)是什么。在您的情況下,我們可以只設(shè)置正確的UIViewController而不是空的。

          我會(huì)為不同的視頻旅程做同樣的事情。

          final class VideoDeeplinkHandler: DeeplinkHandlerProtocol {

              private weak var rootViewController: UIViewController?
              init(rootViewController: UIViewController?) {
                  self.rootViewController = rootViewController
              }

              // MARK: - DeeplinkHandlerProtocol

              func canOpenURL(_ url: URL) -> Bool {
                  return url.absoluteString.hasPrefix("deeplink://videos")
              }
              func openURL(_ url: URL) {
                  guard canOpenURL(url) else {
                      return
                  }

                  // mock the navigation
                  let viewController = UIViewController()
                  switch url.path {
                  case "/new":
                      viewController.title = "Video Editing"
                      viewController.view.backgroundColor = .orange
                  default:
                      viewController.title = "Video Listing"
                      viewController.view.backgroundColor = .cyan
                  }

                  rootViewController?.present(viewController, animated: true)
              }
          }

          現(xiàn)在我們可以將它們注入到DeeplinkCoordinator并讓它處理正確的路由。我們將有兩個(gè)變體,第一個(gè)用于AppDelegate.

          class AppDelegate: UIResponder, UIApplicationDelegate {

              lazy var deeplinkCoordinator: DeeplinkCoordinatorProtocol = {
                  return DeeplinkCoordinator(handlers: [
                      AccountDeeplinkHandler(rootViewController: self.rootViewController),
                      VideoDeeplinkHandler(rootViewController: self.rootViewController)
                  ])
              }

              var rootViewController: UIViewController? {
                  return window?.rootViewController
              }

              // ...

              func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {
                  return deeplinkCoordinator.handleURL(url)
              }
          }

          第二個(gè)為SceneDelegate

          class SceneDelegate: UIResponder, UIWindowSceneDelegate {

              lazy var deeplinkCoordinator: DeeplinkCoordinatorProtocol = {
                  return DeeplinkCoordinator(handlers: [
                      AccountDeeplinkHandler(rootViewController: self.rootViewController),
                      VideoDeeplinkHandler(rootViewController: self.rootViewController)
                  ])
              }()

              var rootViewController: UIViewController? {
                  return window?.rootViewController
              }

              // ...

              func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
                  guard let firstUrl = URLContexts.first?.url else {
                      return
                  }

                  deeplinkCoordinator.handleURL(firstUrl)
              }

          我們可以像目前一樣再次測試它,希望能落在正確的屏幕上(期待橙色背景)。

          xcrun simctl openurl booted "deeplink://videos/new"

          深度鏈接-ios

          總而言之,一旦設(shè)置了 URL 方案,我們就定義了一個(gè)漏斗來捕獲用于打開應(yīng)用程序的所有深層鏈接,并利用面向協(xié)議的編程來創(chuàng)建處理程序的多個(gè)實(shí)現(xiàn),每個(gè)特定路徑一個(gè)。

          此實(shí)現(xiàn)可針對(duì)較新的路徑進(jìn)行擴(kuò)展,并且可以輕松進(jìn)行單元測試以確保每個(gè)部分都按預(yù)期運(yùn)行。

          話雖如此,為了更安全的行為,可能會(huì)有一些改進(jìn),比如驗(yàn)證完整路徑而不是相對(duì)路徑。僅導(dǎo)航present,但它專注于處理程序而不是轉(zhuǎn)換本身。

          在安全說明中,如果您還在深度鏈接中傳遞參數(shù),請確保驗(yàn)證預(yù)期的類型和值。如果我們不小心,它可能會(huì)暴露不同的注入漏洞。

          從那里,您應(yīng)該很好地了解如何使用和處理深度鏈接來打開您的應(yīng)用程序并跳轉(zhuǎn)到特定屏幕。此代碼可在Github[2]上找到。

          參考資料

          [1]

          通用鏈接:: https://benoitpasquier.com/universal-links-ios/

          [2]

          Github: https://github.com/popei69/samples/tree/master/DeeplinkSample


          來源:小小小_小朋友

          https://juejin.cn/post/7077816330543431710


          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點(diǎn)這里好文分享給更多人↓↓

          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天操天天添 | 亚洲一级电影片 | 人妻无码操逼 | 天天碰人人操人人 | 最新国产毛片 |