iOS: Как да отворите дълбоки връзки, известия и преки пътища

Един инструмент за управление на всички тях

Били ли сте създавали някое приложение, което да се справя с Push Notifications? Ако приложението ви е нещо по-сложно от приложението „Здравей, свят!“, Тогава най-вероятно отговорът е „да“.

Какво ще кажете за отваряне на преки пътища? Когато всички нови устройства с iOS поддържат 3D докосване, тази функция се превръща в нещо повече от просто приятно допълнение.

Приложението ви поддържа ли универсалните връзки? Това е сравнително нова функция, която става популярна в съвременните приложения. Така че, ако не го използвате, може да искате да започнете.

Хубавото е, че лесно можете да намерите десетки учебни материали, примери и ръководства по всяка от тези три теми.

Но какво е приложението ви, за да поддържа всички тези функции? Наистина ли трябва да го прилагате като три отделни компонента?

Преди да продължим, нека да изясним условията:

  1. Universal Links е начинът да прехванете някои от URL адресите и вместо да обработвате URL адреса в Safari, отворете конкретна страница с приложение. Универсалните връзки изискват известна работна среда, така че ще се придържаме към Deep Връзки в този урок. Дълбоките връзки действат по подобен начин, но той обработва персонализираните схеми за URL адреси. Неговата реализация не е много по-различна, така че няма да е трудно да добавите поддръжка на Universal Links, ако имате нужда от нея.
  2. Пряк път е начинът да стартирате на конкретната страница въз основа на избран елемент за пряк път, когато натиснете иконата на приложението. Тази функция изисква устройството с възможност за 3D докосване.
  3. Известия: когато докоснете известието (отдалечено или локално), приложението ще се стартира на конкретна страница или ще извърши определени действия.

От това описание можете да видите, че всички тези три функции са просто различните типове с една и съща същност: когато приложението обработва някое от тях, то се стартира от определена страница.

Apple нарече това Launching Options (Опции за стартиране), които се обработват чрез метода на AppDelegate didFinishLaunchingWithOptions.

Въпреки това, когато става дума за внедряване на всички опции за стартиране, тя става объркваща и често води до стотици редове излишен код. Изпълнението става още по-сложно, когато приложението не се стартира, а навлиза в режим на преден план. Работата с пряк път, дълбокото свързване и обработката на известия се случват в различни делегатски методи и изглежда нямат нищо общо.

За да стана ясно, ще го заявя още веднъж: всички тези функции имат една и съща цел - отваряне на конкретна страница с приложение.

Въпросът е как да накараме всичко да работи заедно по приятен и чист начин.

Настройка на проекта

Преди да започнем да прилагаме някоя от опциите за стартиране, създайте списък със страници, до които искате да получите достъп. Да речем, ние изграждаме приложение за резервации на апартаменти и искаме да имаме бърз достъп до следните части:

  • Страница с моите съобщения (визуализация): достъпен чрез пряк път
  • Съобщения (специфичен чат): достъпни чрез push известие
  • Създайте нов списък: достъпен чрез пряк път само за хост профил
  • Моята активност: достъпна чрез пряк път
  • Заявка за резервация: достъпна както чрез имейл връзка (дълбока връзка), така и чрез push известие

Първо, създайте прост проект с ViewController, заглавие на навигацията и бутон Switch Profile Switch:

Настройка на проекта

View Controller ще има текущ тип профил и механизъм за превключване между профили.

Не използвам никакви модели за дизайн на софтуер, тъй като това не е част от този урок. В истинското приложение ще трябва да намерите по-добра структура, отколкото просто да съхранявате ProfileType право в ViewController.
enum ProfileType: String {
   case guest = "Гост" // по подразбиране
   case host = "Хост"
}
клас ViewController: UIViewController {
   var currentProfile = ProfileType.guest
   замени функцията viewDidLoad () {
      super.viewDidLoad ()
      configureFor (profileType: currentProfile)
   }
   @IBAction func didPressSwitchProfile (_ изпращач: Всеки) {
      currentProfile = currentProfile == .guest? .host: .guest
      configureFor (profileType: currentProfile)
   }
   func configureFor (profileType: ProfileType) {
      title = profileType.rawValue
   }
}

Един единствен инструмент за управление на всички тях

За да изравним целта на тази статия, когато отворим конкретна страница за приложение, ще я нарека Deep Link, без значение какъв механизъм използваме.

Сега, когато имаме основна структура и потребителски интерфейс, нека организираме нашия списък с елементи на Deep Link:

enum DeeplinkType {
   enum Съобщения {
      case root
      данни за случая (id: String)
   }
   съобщения от регистъра (Съобщения)
   делова дейност
   случай новСписък
   заявка за регистър (id: String)
}
В този урок няма да обхващам теорията за бързото изброяване. Можете да прочетете тук, ако се нуждаете от разяснение как да използвате вложени ендуми и enums със свързани стойности.

След това можем да създадем сингъл мениджър, който ще има всички опции за дълбоко свързване:

нека Deeplinker = DeepLinkManager ()
клас DeepLinkManager {
   fileprivate init () {}
}

Добавете незадължително свойство, което ще поддържа текущия DeeplinkType:

нека Deeplinker = DeepLinkManager ()
клас DeepLinkManager {
   fileprivate init () {}
   частен var deeplinkType: DeeplinkType?
}

Въз основа на този deeplinkType приложението ще реши коя страница трябва да отвори:

нека Deeplinker = DeepLinkManager ()
клас DeepLinkManager {
   fileprivate init () {}
   частен var deeplinkType: DeeplinkType?
   // проверете съществуващите дълбочини и извършете действие
   func checkDeepLink () {
   }
}

Независимо дали приложението стартира или влиза в режим на преден план, то ще извика метода didBecomeActive appDelegate. Тук ще проверим за съществуващи дълбоки връзки, с които можем да се справим:

func applicationDidBecomeActive (_ приложение: UIA приложение) {
   // обработване на всяка връзка
   Deeplinker.checkDeepLink ()
}

Всеки път, когато приложението стане активно, то ще проверява дали има дълбока връзка за отваряне. Нека създадем клас на навигатор, който ще отвори конкретна страница с приложения въз основа на DeeplinkType:

клас DeeplinkNavigator {
   статичен нека споделен = DeeplinkNavigator ()
   private init () {}
   
   func procedToDeeplink (_ тип: DeeplinkType) {
   }
}

В този урок, ние просто ще покажем сигнал с името на DeeplinkType, който обработихме:

частен var alarController = UIAlertController ()
private func displayAlert (заглавие: String) {
   alertController = UIAlertController (заглавие: заглавие, съобщение: нула, предпочитаноStyle: .alert)
   нека okButton = UIAlertAction (заглавие: "Ok", стил: .default, обработващ: nil)
   alertController.addAction (okButton)
   ако нека vc = UIApplication.shared.keyWindow? .rootViewController {
      ако vc.presentedViewController! = nil {
         alarController.dismiss (анимиран: невярно, завършване: {
            vc.present (self.alertController, анимиран: вярно, завършване: нула)
         })
      } else {
          vc.present (alarmController, анимиран: вярно, завършване: нула)
      }
   }
}

В processToDeeplink превключваме между DeeplinkTypes и решаваме какъв сигнал да се покаже:

func procedToDeeplink (_ тип: DeeplinkType) {
   тип превключвател {
   случай. активност:
      displayAlert (заглавие: "Дейност")
   case .messages (.root):
      displayAlert (заглавие: "Корен на съобщенията")
   case .messages (.details (id: let id)):
      displayAlert (заглавие: "Подробности за съобщенията \ (id)")
   case .newListing:
      displayAlert (заглавие: "Нова обява")
   case .request (id: нека id):
      displayAlert (заглавие: "Подробности за заявка \ (id)")
   }
}

Върнете се към DeepLinkManager и използвайте навигатора за работа с deepLink:

// проверете съществуващите дълбочини и извършете действие
func checkDeepLink () {
   пази нека deeplinkType = deeplinkType else {
      връщане
   }
 
   DeeplinkNavigator.shared.proceedToDeeplink (deeplinkType)
   // нулиране на връзката след обработка
   self.deeplinkType = нула // (1)
}
Не забравяйте да нулирате deepLink до нула (1), след като го използвате. В противен случай същата връзка ще се обработва отново, когато отворите приложението следващия път.

Сега трябва само да проверим дали има някакви дълбоки връзки (преки пътища, дълбоки връзки или известия), които трябва да се обработят, да ги анализираме до DeeplinkType и да им дадем DeepLinkManager.

Първо, трябва да направим основна настройка за преки пътища, дълбоки връзки и известия.

Въпреки че искаме DeepLinkManager да обработва всякакъв вид дълбоки връзки, не забравяйте за SRP (принцип на единична отговорност): няма да смесваме заедно начините, по които анализираме различни типове дълбоки връзки.

Shortcuts

Често използваният начин за създаване на статични преки пътища е използването на файла info.plist. Ето кратък урок, ако искате да го проверите.

В нашия случай някои от преките пътища ще бъдат динамични. Така че, ние ще направим всичко по код. Този метод ви дава повече гъвкавост и контрол и всъщност е много по-лесен за разбиране.

Първо създаваме ShortcutParser. Този клас ще отговаря единствено за преките пътища.

клас ShortcutParser {
   статичен нека споделен = ShortcutParser ()
   private init () {}
}

След това трябва да определим възможните клавиши за бърз достъп:

enum ShortcutKey: String {
   case newListing = "com.myApp.newListing"
   case activity = "com.myApp.activity"
   case messages = "com.MyApp.messages"
}

В ShortcutParser създаваме метод registerShortcutsFor, който ще регистрира преките пътища за различните типове потребители.

func registerShortcuts (за profileType: ProfileType) {
   нека ActivityIcon = UIApplicationShortcutIcon (templateImageName: "Икона за предупреждение")
   нека ActivityShortcutItem = UIApplicationShortcutItem (тип: ShortcutKey.activity.rawValue, localizedTitle: "Скорошна активност", локализиранSubtitle: nil, икона: ActivityIcon, userInfo: nil)
   нека messageIcon = UIApplicationShortcutIcon (templateImageName: "Messenger Icon")
   нека messageShortcutItem = UIApplicationShortcutItem (тип: ShortcutKey.messages.rawValue, localizedTitle: „Съобщения“, локализиранSubtitle: nil, икона: messageIcon, userInfo: nil)
   UIApplication.shared.shortcutItems = [ActivityShortcutItem, messageShortcutItem]
Switch profileType {
      случай .host:
         нека newListingIcon = UIApplicationShortcutIcon (templateImageName: "Икона на нова обява")
         нека newListingShortcutItem = UIApplicationShortcutItem (тип: ShortcutKey.newListing.rawValue, localizedTitle: "Нова обява", localizedSubtitle: nil, икона: newListingIcon, userInfo: nil)
    UIApplication.shared.shortcutItems? .Append (newListingShortcutItem)
      случай .guest:
         почивка
   }
}

Ние създаваме ActivityShortcutItem и messageShortcutItem и за двата типа профил. Ако текущият потребител е хост, добавяме новListingShortcutItem. За всеки пряк път използваме UIApplicationShortcutIcon (тази икона ще се покаже до заглавието на пряк път, когато натиснете иконата на приложението).

Ще наречем този метод от нашия ViewController: когато потребителят превключи профила, преките пътища ще бъдат пренастроени въз основа на новия тип профил:

func configureFor (profileType: ProfileType) {
   title = profileType.rawValue
   ShortcutParser.registerShortcuts (за: profileType)
}
За статичните преки пътища е по-добре да зададете преките пътища от appDelegate, така че приложението не трябва да зарежда ViewController, преди да зададе преките пътища

Създайте и стартирайте приложението и тествайте поведението му:

  1. Натиснете върху иконата на приложение, за да видите опциите за бързи клавиши
  2. Превключете профила
  3. Натиснете отново иконата на приложение, за да видите още един набор от опции за бърз достъп

Ако обаче докоснете някой от преките пътища, той просто ще отвори приложението на страницата по подразбиране. Това е така, защото добавихме само преките пътища към приложението, но все още не сме казали на приложението как да се справи с тях.

Превключете към AppDelegate и добавете метода за делегат на PerformActionForShortcutItem:

// МАРК: Преки пътища
приложение func (_ приложение: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, запълванеHandler: @escaping (Bool) -> void) {
}

Този метод ще открие кога пряк път е задействан, а запълванетоHandler ще каже на делегата дали да се справи или не. Отново няма да поставяме никаква логика за пряк път в appDelegate. Вместо това създаваме метод в DeeplinkManager:

@discardableResult
func handleShortcut (елемент: UIApplicationShortcutItem) -> Bool {
   deeplinkType = ... // ще анализираме елемента тук
   върнете deeplinkType! = нула
}

Този метод първо ще се опита да анализира елемента за пряк път към DeeplinkType и след това ще върне булевата стойност, показвайки дали синтактичният анализ е успешен или не. В същото време тя ще запази парсирания пряк път в променливата deeplinkType.

@discardableResult казва на компилатора да игнорира стойността на резултата, ако не я използваме, така че нямаме предупреждение за "неизползван резултат"

Върнете се към appDelegate и завършете PerformActionFor метод:

// МАРК: Преки пътища
приложение func (_ приложение: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, запълванеHandler: @escaping (Bool) -> void) {
   fillHandler (Deeplinker.handleShortcut (артикул: shortcutItem))
}

Последното нещо, което трябва да направим, е да анализираме елемента с пряк път към DeeplinkType. Вече имаме клас ShortcutParser, който е отговорен за всички действия, свързани с преки пътища. Добавете друг метод:

func handleShortcut (_ пряк път: UIApplicationShortcutItem) -> DeeplinkType? {
   превключване shortcut.type {
   case ShortcutKey.activity.rawValue:
      връщане .активност
   case ShortcutKey.messages.rawValue:
      връщане .messages (.root)
   case ShortcutKey.newListing.rawValue:
      връщане .нов списък
   по подразбиране:
      връщане нула
   }
}

Сега се върнете към DeeplinkManager и завършете метод на handleShortcut:

@discardableResult
func handleShortcut (елемент: UIApplicationShortcutItem) -> Bool {
   deeplinkType = ShortcutParser.shared.handleShortcut (елемент)
   върнете deeplinkType! = нула
}

Това е цялата настройка, която ни е необходима, за да се справим с преките пътища! Нека да преминем през него стъпка по стъпка още веднъж. Когато докоснем иконата за пряк път:

  1. Действието на пряк път задейства метода appDelegate performActionForShortcutItem
  2. метод performActionForShortcutItem предава ShortcutItem на DeeplinkManager
  3. DeeplinkManager се опитва да анализира ShortcutItem до DeeplinkType, използвайки ShortcutParser
  4. При applicationDidBecomeActive извършваме проверка за всички DeeplinkTypes
  5. Ако DeeplinkType съществува (това означава, че стъпка 3 е успешна), правим подходящи действия, използвайки DeeplinkNavigator
  6. След като прякът се обработи, DeeplinkManager нулира текущия елемент на пряк път до нула, така че няма да бъде използван отново

Стартирайте приложението и тествайте как работи в 2 сценария: когато приложението се стартира от затворено състояние и когато приложението се възобнови от фонов режим. И в двата случая трябва да видите сигнала с подходящо съобщение:

Дълбоки връзки

Дълбоковите връзки, с които ще се справим, ще имат следния формат:

deeplinkTutorial: // съобщения / 1
deeplinkTutorial: // заявка / 1

Копирайте и запазете тези URL адреси в „Бележки“ на вашето тестващо устройство. Ако докоснете някоя от връзките, нищо няма да се случи.

Ако това беше Universal Link, докосването на връзката ще отвори браузър с URL адрес на връзката.

Когато приключим с този раздел, докосването на URL адреса ще отвори подходящата страница в нашето приложение.

AppDelegate ще открие дали приложението е било отворено с URL връзка с дълбока връзка и ще задейства метода openUrl:

// МАРКА: Дълбоки връзки
приложение func (_ приложение: UIA приложение, отворен URL адрес: URL, опции: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> Bool {
}

Връщаната стойност казва на делегата дали да отвори URL адреса или не.

Ако искате да поддържате универсалните връзки (въведени в iOS9), добавете и следния делегат метод:

// МАРК: Универсални връзки
приложение func (_ приложение: UIA приложение, продължете потребителАктивност: NSUserActivity, възстановяванеHandler: @escaping ([Any]?) -> void) -> Bool {
   ако userActivity.activityType == NSUserActivityTypeBrowsingWeb {
      ако нека url = userActivity.webpageURL {
         
      }
   }
   върнете невярно
}
ContunueUserActivity също се задейства, когато стартирате приложението чрез елементите Spotlighs (които не са обхванати в този урок).

Следвайки същия модел, който използвахме за преките пътища, създаваме DeeplinkParser:

клас DeeplinkParser {
   статичен нека споделен = DeeplinkParser ()
   private init () {}
}

За да анализираме Deeplink, създаваме метод, който приема URL адрес и връща незадължителния DeeplinkType:

func parseDeepLink (_ url: URL) -> DeeplinkType? {
   пазете компоненти компоненти = URLComponents (url: url, resolutioningAgainstBaseURL: true), нека host = components.host else {
      връщане нула
   }
   var pathComponents = components.path.com компоненти (sepaBy: "/")
   // първият компонент е празен
   pathComponents.removeFirst ()
   превключване на хост {
   случай "съобщения":
      ако нека messageId = pathComponents.first {
         върнете DeeplinkType.messages (.details (id: messageId))
      }
   случай "искане":
      ако нека requestId = pathComponents.first {
         върнете DeeplinkType.request (id: requestId)
      }
   по подразбиране:
      почивка
   }
   връщане нула
}
Обърнете внимание, че този метод на анализ ще зависи от вашата структура на връзки и моето решение е само пример.

Сега можем да свържем този анализатор към нашия основен клас на дълбоки връзки. Добавете този метод в DeeplinkManager:

@discardableResult
func handleDeeplink (url: URL) -> Bool {
   deeplinkType = DeeplinkParser.shared.parseDeepLink (URL)
   върнете deeplinkType! = нула
}

В appDelegate завършваме методите openUrl и ContinuUserActivity:

// МАРКА: Дълбоки връзки
приложение func (_ приложение: UIA приложение, отворен URL адрес: URL, опции: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> Bool {
   върнете Deeplinker.handleDeeplink (url: url)
}
// МАРК: Универсални връзки
приложение func (_ приложение: UIA приложение, продължете потребителАктивност: NSUserActivity, възстановяванеHandler: @escaping ([Any]?) -> void) -> Bool {
   ако userActivity.activityType == NSUserActivityTypeBrowsingWeb {
      ако нека url = userActivity.webpageURL {
         върнете Deeplinker.handleDeeplink (url: url)
      }
   }
   върнете невярно
}

Има още едно нещо, което трябва да направим: да кажем на нашето приложение каква връзка трябва да открие. Добавете този фрагмент на код към файла info.plist (щракнете с десния бутон върху info.plist -> Open As -> Source Code):

<Ключ> CFBundleURLTypes 
<Масив>
   
      <Ключ> CFBundleURLName 
      <Низ> com.deeplinkTut.Deeplink 
      <Ключ> CFBundleURLSchemes 
      <Масив>
         <Низ> deeplinkTutorial 
      
   
Уверете се, че не нарушавате XML файловата структура.

След като добавите този код, опитайте се да отворите списъка като списък на свойствата. Трябва да видите следните редове:

Това ще накара приложението да открива само връзките с URL адреса „deeplinkTutorial“.

Нека отново преминем през всички стъпки:

  1. Потребителите чукат по връзката извън приложението
  2. AppDelegate открива връзката и задейства метода на делегат openUrl (или метода за делегиране на ContinueUserActivity за универсалните връзки)
  3. методът openUrl предава връзката към Deeplink Manager
  4. Deeplink Manager се опитва да анализира връзката към Deeplink Type с помощта на DeeplinkParser
  5. При applicationDidBecomeActive извършваме проверка за всички DeeplinkTypes
  6. Ако DeeplinkType съществува (това означава, че стъпка 4 е успешна), правим подходящи действия, използвайки DeeplinkNavigator
  7. След като прякът се обработи, DeeplinkManager нулира текущия елемент на пряк път до нула, така че няма да бъде използван отново

Стартирайте приложението и се опитайте да отворите връзката, която сте запазили в бележките си:

Известия

Конфигурирането на проекта в подкрепа на push известия не е част от този урок, но подробните примери можете да намерите тук и тук.

За изпращане на APNS известия можете да използвате локален сървър и PusherAPI (това е един от простите начини).

Ще покрием само частта между натискане на известието за натискане и виждане на резултата.

Когато приложението е затворено или работи на фона повече, докосването на банера за известия ще задейства метода didReceiveRemoteNotification appDelegate:

приложение func (_ приложение: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler запълванеHandler: @escaping (UIBackgroundFetchResult) -> void) {
   
}
Този метод също ще се задейства, когато приложението получи известие за натискане, докато се изпълнява в режим на преден план. Тъй като ние обмисляме сценариите само когато искате да отворите приложението на определена страница, няма да покриваме обработката на известия в режим на преден план.

За да обработвате известията, ще създадем NotificationParser:

клас NotificationParser {
   static let shared = NotificationParser ()
   private init () {}
   func handleНотификация (_ userInfo: [AnyHashable: Any]) -> DeeplinkType? {
      връщане нула
   }
}

Сега можем да свържем този метод с Deeplink Manager:

func handleRemoteNotification (_ известие: [AnyHashable: Any]) {
   deeplinkType = NotificationParser.shared.handleНотификация (известие)
}

И завършете метода на appDelegate didReceiveRemoteNotification:

приложение func (_ приложение: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler запълванеHandler: @escaping (UIBackgroundFetchResult) -> void) {
   Deeplinker.handleRemoteNotification (USERINFO)
}

Последната стъпка е да завършите метода на разбор в NotificationParser. Това ще зависи от вашата структура на известия, но основната техника за разбор ще бъде подобна:

func handleНотификация (_ userInfo: [AnyHashable: Any]) -> DeeplinkType? {
   ако нека data = userInfo ["data"] като? [Низ: Някой] {
      ако нека messageId = data ["messageId"] като? Низ {
         върнете DeeplinkType.messages (.details (id: messageId))
      }
   }
   връщане нула
}

Ако сте конфигурирали приложението да поддържа push известията и искате да го тествате, ето известието, което използвам, за да доставя съобщение:

apns: {
    aps: {
        тревога: {
            заглавие: „Ново съобщение!“,
            подзаглавие: "",
            тяло: "Здравей!"
        }
        "изменяемо съдържание": 0,
        категория: "тласкач"
    }
    данни: {
        "messageId": "1"
    }
}
Използвам локален NodeJS сървър и Pusher API за изпращане на известия в този урок. Необходими са само няколко минути за настройка и изискват основните познания за NodeJS или някои умения за поставяне на копие.

Стартирайте приложението, отведете го във фонов режим и изпратете известие. След като получите известието, докоснете го, за да отворите приложението:

Ето какво се случва зад сцената:

  1. Когато докоснете известието, приложението задейства метода на делегат didReceiveRemoteNotification
  2. didReceiveRemoteNotification предава информацията за известяване на диспечера на Deeplink
  3. Deeplink Manager се опитва да анализира информацията за потребителя на известието до типа Deeplink, като използва NotificationParser
  4. При applicationDidBecomeActive извършваме проверка за всички DeeplinkTypes
  5. Ако DeeplinkType съществува (това означава, че стъпка 3 е успешна), правим подходящи действия, използвайки DeeplinkNavigator
  6. След като прякът се обработи, DeeplinkManager нулира текущия елемент на пряк път до нула, така че няма да бъде използван отново

Използвайки този подход, можете лесно да добавите или модифицирате всеки от елементите без значителни промени в кода. И което е по-важно, можете да анализирате всяка дълбока връзка, като използвате подходящия анализатор. Например, за да добавите „Нова заявка“ в обработващия съобщение, трябва само да промените метода на обработка на уведомление в NotificationParser:

func handleНотификация (_ userInfo: [AnyHashable: Any]) -> DeeplinkType? {
   ако нека data = userInfo ["data"] като? [Низ: Някой] {
      ако нека messageId = data ["messageId"] като? Низ {
         върнете DeeplinkType.messages (.details (id: messageId))
      }
      ако оставим requestId = data ["requestId"] като? Низ {
         върнете DeeplinkType.request (.details (id: requestId))
      }
   }
   връщане нула
}
Обърнете внимание, че не използваме didFinishLaunchingWithOptions за нито една от тези преки връзки. Всичко се обработва чрез applicationDidBecomeActive.

Честито! Сега приложението ви има универсална поддръжка на преки пътища, дълбинни връзки и известия!

Вижте окончателния проект тук:

Благодаря за четенето! Ако ви харесва този урок, моля натиснете .

Пиша и за блога на American Express Engineering. Вижте и другите ми творби и произведенията на моите талантливи колеги в AmericanExpress.io.