Привет, Хабр!
На связи Алексей Поддубный, iOS-разработчик AGIMA. Я расскажу, как в iOS работают диплинки, и разберу тонкости настройки популярных сервисов: где создавать ссылки с динамическими параметрами, как настраивать конфигурацию приложений и что делать после настройки. Инструкции основаны на оригинальных туториалах, которые мы перевели и адаптировали.
Диплинки, или глубинные ссылки, часто используют в рекламных кампаниях соцсетей. Они нужны чтобы вовлекать новых пользователей или интегрировать приложения с различными источниками трафика. Такая ссылка отправляет пользователя сразу на определенный раздел или товар, который он увидел в рекламной компании без перехода в браузер.
Что такое глубинные ссылки?
Человек листал ленту Facebook и увидел рекламу: доставка бургеров за 15 минут. Он кликает по ссылке и попадает в браузер на главную страницу. Рекламных предложений с «быстрыми» бургерами там нет, а без авторизации написать менеджеру нельзя. В результате страница закрывается, человек остается голодным и недовольным, а бизнес недополучил прибыль.
Чтобы дать пользователю желаемое «здесь и сейчас» нужна глубинная ссылка — Deep Link. Или Deferred Deep Linking — отложенная глубинная ссылка — если приложение не установлено. В отложенном варианте пользователь сначала попадает в App Store или Play Market для Android, а после установки — в нужный раздел приложения.
Как можно использовать диплинки
Интегрировать в рекламные кампании и привлекать новых пользователей.
Переносить пользователей из веба в мобайл: после установки приложения можно продолжить работу сразу с того места, на котором человек остановился.
Перенаправлять с электронной почты или SMS-сообщений в приложение на нужный раздел или товар.
Обмениваться данными между пользователями: люди могут делиться между собой приглашениями установить приложение или ссылками на конкретный товар. С помощью диплинков можно отследить поведение пользователей и оптимизировать будущие маркетинговые кампании.
Сервисы для интеграции диплинков
Есть много сервисов по внедрению диплинков. Мы чаще всего используем Firebase, AppsFlyer и Facebook поэтому будем сравнивать их. Справедливости ради, можно обойтись и без сторонних сервисов, но в этой статье такой подход мы рассматривать не будем.
Firebase |
AppsFlyer (OneLink) |
||
Описание |
Сервис содержит модуль для интеграции диплинков, Crashlytics, Аналитику, Push-уведомления и другие популярные модули |
Мощный и легкий в использовании инструмент для настройки диплинков, отслеживания установок и аналитики |
Механизм для настройки рекламных диплинков внутри продуктов Facebook |
Для чего использовать |
Для рекламных диплинков ведущих на веб- и мобильные устройства |
Для рекламных диплинков, ведущих на веб- и мобильные устройства |
Используется только в рекламных кампаниях Facebook и Instagram (сторис, лента) |
Плюсы |
+ Ссылки могут участвовать в поисковой индексации + Можно создать ссылку с динамическими параметрами, например когда каждому пользователю нужно выдать по ссылке с уникальным параметром +Можно добавлять UTM-параметры |
+ Работает на всех платформах + Легко интегрируется + Гибкая настройка диплинков, можно указать множество дополнительных параметров + Есть OneLink API для создания персонализированных ссылок и автоматизации процесса + Возможно создавать ссылки с динамическими параметрами + Deferred Deeplink без проблем работает в последних версиях iOS |
+ Позволяет интегрировать в рекламу Facebook + Удобно тестировать через тестовые устройства |
Минусы |
- Настраивается только для мобильных приложений на базе iOS / Android - Нет API для генерации ссылок - Нет возможности настраивать рекламные кампании в консоли Firebase |
Не выявлено |
- Тестирование возможно только через установку приложения Facebook Messenger - Из-за изменений в iOS 14 отложенный переход по глубинной ссылке больше не поддерживается |
Удобство ЛК для отслеживания аналитики |
Можно отслеживать количество кликов по ссылке после установки приложения |
Система отслеживания аналитики с множеством параметров: географическое распределение пользователей, источники трафика, установки по дням, переходы по ссылкам, показы, открытия приложения, показатели конверсии, неорганические и органические установки |
Отображает и разделяет количество органических и неорганических установок. Показывает время последней установки на каждой из платформ iOS / Android |
Дальше разберем, как интегрировать диплинки через описанные фреймворки.
#1: Настройка через Firebase
Создание ссылки в консоли Firebase
В консоли Firebase откройте раздел «Динамические ссылки». Создайте базовый домен, который будет использоваться в диплинках.
2. Нажмите на New Dynamic Link и перейдите к созданию диплинка.
Сформируйте вид короткой ссылки и нажмите Next.
3. Укажите ссылку, которая будет открываться у пользователей веба и в мобильном приложении. Правая часть ссылки — та, из которой будем извлекать параметры.
4. В следующем пункте укажите «Open the deep link in your iOS App» и выберите приложение из выпадающего списка.
5. Если ссылка будет использоваться для обеих платформ, то укажите и Android-приложение.
6. Укажите метатеги, UTM-метки или другие дополнительные параметры, нажмите «Сохранить».
Все, диплинк готов к дальнейшему использованию.
Конфигурация приложения
Откройте проект в Xcode и перейдите во вкладку Signing & Capabilities, допишите префикс applinks и добавьте ваш домен в Associated Domains.
Чтобы проверить правильность настройки, установите приложение на телефон и перейдите по ссылке в виде https://your_dynamic_links_domain/apple-app-site-association. В нашем случае — https://tr4d1.page.link/apple-app-site-association. После нажатия на ссылку вы должны попасть в приложение.
Для получения и обработки диплинков добавьте Firebase SDK.
1. Добавьте и установите Firebase SDK через cocoapods выполнив pod install.
pod 'Firebase/Analytics'
pod 'Firebase/DynamicLinks'
2. Импортируйте модуль Firebase в AppDelegate
import Firebase
3. В методе application:didFinishLaunchingWithOptions: вызовите FirebaseApp.configure() для инициализации SDK.
4. Реализуйте метод для открытия диплинков если приложение уже установлено у пользователя.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { [weakself] (dynamicLink, error) in
if let dynamicLink = dynamicLink, let deepUrl = dynamicLink.url {
self?.processDeepLink(url: deepUrl)
}
}
return handled
}
Настройка Deferred Deep Link для случаев когда приложение не было раньше установлено:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
application(
app, open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: ""
)
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
guard
let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url),
let deepUrl = dynamicLink.url else {
return false
}
processDeepLink(url: deepUrl)
return true
}
Метод для обработки диплинка:
private func processDeepLink(url: URL) {
let componets = url.absoluteString.components(separatedBy: "/")
guard
let type = componets.last,
let linkType = DeepLinkType(rawValue: type) else {
return
}
//используем linkType для дальнейшей навигации
//записываем linkType в переменную синглтона для дальнейшего открытия в базовом контроллере
DeepLinkHelper.sharedInstance.deepLinkType = linkType
//создаем уведомлении о диплинке, если базовый контроллер уже загружен - пользователь перешел по диплинку, когда приложение было запущено
NotificationCenter.default.post(name: Notification.Name("deepLinkNotification"), object: nil)
}
Опишем enum
enum DeepLinkType : String {
case subscription
}
Опишем синглтон для хранения диплинка
class DeepLinkHelper : NSObject {
static let sharedInstance =DeepLinkHelper()
var deepLinkType: DeepLinkType?
}
Опишем базовый контроллер
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// подписываемся на обработку уведомлений, в случае перехода по ним в запущенном приложении
NotificationCenter.default.addObserver(self, selector: #selector(proccessDeepLink), name: "deepLinkNotification", object: nil)
// вызываем метод обработки диплинка при загрузке контроллера - проверяем было ли запущено приложение по переходу через диплинк
processDeepLink()
}
@objc func proccessDeepLink() {
guard let deepLinkType = DeepLinkHelper.sharedInstance.deepLinkType else {
return
}
switch deepLinkType {
case .subscription:
// отображаем нужный контроллер
showSubscription()
default:
break
}
DeepLinkHelper.sharedInstance.deepLinkType = nil
}
}
func showSubscription() {
let vc = SubscriptionViewController()
let vm = SubscriptionViewModel()
vc.viewModel = vm
viewController.navigationController?.pushViewController(vc, animated: true)
}
Таким образом, когда пользователь переходит по короткой ссылке вида https://tr4d1.page.link/subscription, в обработчик попадает внутренняя ссылка https://deeplinkexample/subscription. После ее успешной обработки получается enumDeepLinkType.subscription, который можно использовать для открытия соответствующего раздела приложения.
Оригинал инструкции: https://firebase.google.com/docs/dynamic-links/ios/receive
#2: Настройка через AppsFlyer (Onelink)
Создание шаблона OneLink
1. Перейдите по ссылке https://hq1.appsflyer.com/onelink/setup?onelinkId=new создайте базовый шаблон и укажите его название.
2. Укажите поддомен, который будет использоваться в диплинках.
3. Из выпадающего списка выберите название приложения. Если ссылка будет использоваться для обеих платформ, то укажите и Android-приложение.
4. Настройте поведение ссылки для случаев если приложение не установлено. Здесь по умолчанию открывается приложение в AppStore, и этот параметр изменять не нужно, — он уже сконфигурирован на открытие приложения в AppStore.
5. Выберите действия, которые необходимо выполнить если приложение установлено. Здесь нужно изменить на запуск приложения с использованием Universal Links указав Team Id и Bundle Id приложения.
6. Если на вебе нужно открывать другую ссылку, а не перенаправлять пользователей в магазины приложений, укажите веб-ссылку. После этого шага нажмите «Сохранить» и перейдите к созданию самого диплинка.
Создание ссылки OneLink
1. Сформируйте вид короткий ссылки
2. Укажите название кампании
3. Добавьте дополнительные параметры атрибуции. Они могут быть предустановленными, например af_ad (имя рекламы), af_channel (канал рекламы) или свои собственные. Все параметры будут доступны в приложении после переходу по ссылке и ее обработки.
4. После добавления параметров сохраните ссылку. Диплинк готов к использованию. Ссылка доступна в коротком и длинном варианте.
Конфигурация приложения
Откройте проект в Xcode и перейдите во вкладку Signing & Capabilities, добавьте ваш домен в Associated Domains, дописав префикс applinks: по аналогии с конфигурацией Firebase.
Для получения и обработки диплинков необходимо добавить AppsFlyer SDK.
1. Добавьте и установите AppSlyer SDK через cocoapods выполнив pod install
pod 'AppsFlyerFramework'
2. Импортируйте модуль AppsFlyer в AppDelegate
import AppsFlyerLib
В методе application:didFinishLaunchingWithOptions: установите appsFlyerDevKey и appleAppID
AppsFlyerLib.shared().appsFlyerDevKey = AppConstants.appsFlyerDevKey
AppsFlyerLib.shared().appleAppID = AppConstants.appleAppID
AppsFlyerLib.shared().delegate = self
3. Реализуйте методы для извлечения ссылки и передачи ее в обработчик AppsFlyer
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping([UIUserActivityRestoring]?) -> Void) -> Bool {
AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
AppsFlyerLib.shared().handleOpen(url, sourceApplication: sourceApplication, withAnnotation: annotation)
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
AppsFlyerLib.shared().handleOpen(url, options: options)
application(
app, open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: ""
)
}
4. Также реализуйте методы SDK AppsFlyer onConversionDataSuccess и onAppOpenAttribution для обработки диплинков
extension AppDelegate: AppsFlyerLibDelegate {
// Метод вызывается при переходе по ссылке, если приложение не было ранее установлено и пользователь попал в него после установки из AppStore
func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]) {
// Проверяем, что ссылка была впервые открыта, используется, чтобы не было ложных срабатываний при последующих запусках приложения
guard let is_first_launch = conversionInfo["is_first_launch"] as? Bool, is_first_launch else { return }
// Извлекаем из словаря conversionInfo указанные при создании ссылки параметры и передаем их в обработчик
}
// Метод вызывается при переходе по ссылке если приложение установлено
func onAppOpenAttribution(_ attributionData: [AnyHashable: Any]) {
// Извлекаем из словаря attributionData указанные при создании ссылки параметры и передаем их в обработчик
}
}
Переходя по короткой ссылке вида https://tr4d1.onelink.me/Jvu2/subscription, в обработчик попадает развернутая ссылка https://tr4d1.onelink.me/Jvu2?pid=subscription&c=subscription&custom_value=1&af_ad=subscription. Все параметры этой ссылки находятся в словаре. Извлекая параметры, можно выполнить соответствующие действия в приложении.
Оригинал инструкции для AppsFlyer https://support.appsflyer.com/hc/en-us/articles/207032066-AppsFlyer-SDK-Integration-iOS#core-apis-get-conversion-data
#3: Настройка через Facebook
Конфигурация приложения
Откройте проект в Xcode и перейдите в Info.plist. Здесь необходимо добавить данные вашего приложения из Facebook.
<key>FacebookAppID</key>
<string>1847859691656630</string>
<key>FacebookDisplayName</key>
<string>DeeplinkExample</string>
Для получения и обработки диплинков необходимо добавить Facebook SDK.
1. Добавьте и установите Facebook SDK через cocoapods выполнив pod install.
pod 'FacebookSDK'
2. Импортируйте модуль Facebook в AppDelegate.
import FBSDKCoreKit
3. В Facebook для любого вида диплинков используется всего один метод:
func applicationDidBecomeActive(_ application: UIApplication) {
AppLinkUtility.fetchDeferredAppLink { [weak self] (url, error) in
guard let deepUrl = url else { return }
// передаем в обработчик полученный диплинк
self?.processDeepLink(url: deepUrl)
}
}
Диплинки в Facebook работают только при переходе по ним из рекламы. Для их тестирования нужно настроить тестовую рекламную кампанию. Скачать Facebook Messenger и авторизоваться под той же учетной записью, в которой настраиваются диплинки. Затем найти в ленте запись вашей рекламной кампании и нажать на нее для перехода по диплинку.
Откладка диплинков
Для тестирования и дебаггинга глубинных отложенных диплинков нужно удалить приложение с телефона. Перейти по диплинку и попасть в AppStore на страницу приложения, но не скачивать его. После чего установить приложение через Xcode на девайс, установить брейкпоинты на методах извлечения диплинков соответствующих SDK и произвести отладку.
Для отладки обычных отложенных диплинков, когда приложение уже установлено и выполняется просто переход по ссылке, нужно предварительно установить приложение через Xcode, но не запускать его. Это делается с помощью нажатия Option+Cmd+R. Откроется окно, в котором нужно поставить галочку Wait for the executable to be launched.
В данном случае Xcode установит приложение, но будет ждать на открытие его пользователем. Далее так же установите брейкпоинты на нужных методах и перейдите по диплинку.
→ Оригинал инструкции для Facebook
Рекомендации
Детально тестируйте каждую ссылку на открытие нужного раздела или продукта в приложении перед отправкой новой версии приложения с AppStore. Это экономит время на более быстрый старт будущих рекламных кампаний.
При добавлении каждого SDK или новой ссылки проверьте поведение ссылки при установленном приложении и, если оно отсутствует.
Интегрируйте сразу несколько SKD в одно приложение, например Facebook, Firebase и AppsFlyer. Тогда нужно смотреть чтобы добавление нового, не сломало работоспособность предыдущего. В таком случае хорошо иметь один обработчик, который будет вызываться каждым SDK.