Статьи

iOS Universal Links для удобного взаимодействия с пользователем

Одной из наиболее интересных функций, представленных в iOS 9, были Universal Links . Поддержка этой функции в вашем приложении позволяет легко открывать любые ссылки на контент в Интернете в самом приложении. Если его нет на устройстве, система использует Safari для открытия ссылки.

Это отлично по ряду причин:

  • Вам не нужно беспокоиться о схемах URI и документировании поддерживаемых маршрутов / путей.
  • Это безопасно, потому что Apple требует загрузки файла конфигурации на ваш сервер (подробнее об этом позже). Поскольку у вас есть контроль над этим, маловероятно, что другое приложение может ассоциировать себя с вашими ссылками.
  • Та же ссылка, которая перенаправляет на ваш веб-контент, может быть использована и проанализирована в вашем приложении. Это облегчает обмен контентом.
  • Отступление просто работает , что означает, что вам не нужно беспокоиться о ситуациях, когда приложение может не быть установлено.

В этой статье я покажу, как настроить свой собственный сервер и обрабатывать соответствующие ссылки в вашем приложении.

Настройка сервера

Серверное приложение будет простым приложением Rails, которое отображает список авторов и некоторые их книги. Самый простой способ начать работу — клонировать приложение на Heroku, просто нажав кнопку ниже.

Развертывание

Если вы не хотите использовать эту опцию, вы также можете самостоятельно развернуть приложение, клонировав его на Github и передав его на хост по вашему выбору.

Вы можете увидеть приложение в действии здесь . По умолчанию отображается список авторов. При нажатии на любого автора отображается список написанных ими книг.

Файл приложения-сайта-ассоциации

Недостаточно просто запустить сервер в сети. Чтобы надежно связать ваше приложение iOS с сервером, Apple требует, чтобы вы предоставили доступ к файлу конфигурации, который называется apple-app-site-association . Это файл JSON, который описывает домен и поддерживаемые маршруты.

Файл apple-app-site-association должен быть доступен через HTTPS, без каких-либо перенаправлений, по адресу https: // {domain} / apple-app-site-association .

Примечание . В зависимости от используемого веб-приложения и платформ может потребоваться настройка маршрутов в веб-приложении для обработки указанного выше пути.

Файл выглядит так:

{ "applinks": { "apps": [ ], "details": [ { "appID": "{app_prefix}.{app_identifier}", "paths": [ "/path/to/content", "/path/to/other/*", "NOT /path/to/exclude" ] } ] } } 

Примечание : .json не должен добавляться к имени файла.

Ключи следующие:

  • apps : в качестве значения должен иметь пустой массив, и он должен присутствовать. Так Apple хочет.
  • details : представляет собой массив словарей, по одному для каждого приложения iOS, поддерживаемого веб-сайтом. Каждый словарь содержит информацию о приложении, команде и идентификаторах пакетов. В примере приложения это 72H8ZPD4X8.com.behindtechlines.UniversalLinksDemo и пути, поддерживаемые приложением.
 { "applinks": { "apps": [], "details": [ { "appID": "72H8ZPD4X8.com.behindtechlines.UniversalLinksDemo", "paths": [ "/authors", "/authors/*/books", "/authors/*" ] } ] } } 

Есть 3 способа определения путей:

  • Статический : весь поддерживаемый путь жестко задан для идентификации конкретной ссылки, например, / static / term
  • Подстановочные знаки : * может использоваться для сопоставления с динамическими путями, например, / авторы / * могут соответствовать пути к странице любого автора. ? внутри конкретных компонентов пути, например, авторы / 1? может использоваться для поиска любых авторов, чей ID начинается с 1.
  • Исключения : добавление пути к NOT исключает сопоставление этого пути.

Порядок, в котором пути упоминаются в массиве, важен. Более ранние индексы имеют более высокий приоритет. Как только путь совпадает, оценка останавливается, а другие пути игнорируются. Каждый путь чувствителен к регистру.

Поддержка нескольких доменов

Каждый домен, поддерживаемый в приложении, должен предоставлять свой собственный файл apple-app-site-association . Если содержимое, обслуживаемое каждым доменом, отличается, содержимое файла также изменится для поддержки соответствующих путей. В противном случае можно использовать один и тот же файл, но он должен быть доступен в каждом поддерживаемом домене.

Примечание . Это означает, что если в вашем приложении должны поддерживаться и example.com, и www.example.com , файл ассоциации должен быть доступен на обоих этих доменах.

Подписание файла приложения-сайта-ассоциации

Если ваше приложение предназначено для iOS 9, а ваш сервер использует HTTPS для обслуживания контента, вам не нужно подписывать файл. Если нет (например, при поддержке Handoff в iOS 8), он должен быть подписан с использованием сертификата SSL от признанного центра сертификации.

Примечание . Это не сертификат, предоставленный Apple для отправки вашего приложения в App Store. Он должен быть предоставлен третьей стороной, и рекомендуется использовать тот же сертификат, который вы используете для вашего HTTPS-сервера (хотя это и не обязательно).

Чтобы подписать файл, сначала создайте и сохраните его простую .txt версию. Далее в терминале выполните следующую команду:

 cat <unsigned_file>.txt | openssl smime -sign -inkey example.com.key -signer example.com.pem -certfile intermediate.pem -noattr -nodetach -outform DER > apple-app-site-association 

Это выведет подписанный файл в текущий каталог. Example.com.key , example.com.pem и middle.pem — это файлы, которые были бы доступны для вас вашим сертифицирующим органом.

Примечание . Если файл не подписан, он должен иметь Content-Type application/json . В противном случае это должно быть application/pkcs7-mime .

Настройка приложения

Следующее приложение, которое отражает сервер. Он будет ориентирован на iOS 9 и будет использовать Xcode 7.2 с Swift 2.1.

Приложение будет общаться с сервером и отображать следующее:

  • Список авторов : вызов /authors.json на сервере даст вам данные.
  • Профиль автора . Вызывается при нажатии автора. Конечной точкой в ​​этом случае является /authors/:id.json .
  • Список книг автора : доступно по адресу /authors/:id/books.json .

Код приложения можно найти на Github .

Вот как выглядит приложение:

Скриншот приложения 1

Скриншот приложения 2

Скриншот приложения 3

Важно — Требуются изменения

Если вы намереваетесь создать собственный экземпляр примера сервера и клонировать пример приложения iOS, внесите следующие изменения:

  • Измените идентификатор пакета на то, что будет использоваться в идентификаторе вашего приложения в Центре участников.
  • Команда должна быть той, которая связана с вашей учетной записью разработчика.
  • kBaseURL в AppDelegate.swift должен указывать на ваш экземпляр веб-сервера.
  • Обновите /public/association.json в приложении Rails, указав префикс и суффикс идентификатора приложения.

Требуются изменения

Включение универсальных ссылок

Настройка на стороне приложения требует двух вещей:

  • Настройка права приложения и включение универсальных ссылок.
  • Обработка входящих ссылок в вашем AppDelegate.

Настройка прав

Первым шагом в настройке прав вашего приложения является включение его для вашего идентификатора приложения. Сделайте это в Центре разработчиков Apple .

Нажмите на сертификаты, идентификаторы и профили, а затем идентификаторы . Выберите идентификатор приложения (сначала создайте его, если необходимо), нажмите « Изменить» и включите право « Связанные домены» .

Создание идентификатора приложения

Затем получите префикс и суффикс идентификатора приложения, щелкнув соответствующий идентификатор приложения.

Префикс идентификатора приложения

Префикс и суффикс идентификатора приложения должны совпадать с теми, которые указаны в файле apple-app-site-association .

Далее в Xcode выберите цель вашего приложения, нажмите Capabilities и переключите связанные домены на On . Добавьте запись для каждого домена, который поддерживает ваше приложение, с префиксом applinks:

Например : applinks:www.example.com и applinks:example.com .

Что выглядит следующим образом для примера приложения:

Entitlements

Примечание . Убедитесь, что вы выбрали ту же группу и ввели тот же идентификатор пакета, что и зарегистрированный идентификатор приложения в Центре участников. Также гарантируйте, что файл полномочий включен Xcode, выбирая файл и в Инспекторе Файлов , гарантируйте, что ваша цель проверена.

Целевое членство в приложении

Обработка входящих ссылок

application:continueUserActivity:restorationHandler: в методе UIApplicationDelegate в AppDelegate.swift обрабатывает входящие ссылки. Метод предоставляет объект NSUserActivity со значением NSUserActivityTypeBrowsingWeb и свойством webpageURL содержащим URL-адрес. Вы анализируете этот URL, чтобы определить правильное действие в приложении.

Например, в примере приложения:

 let router = SHNUrlRouter() func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { bindRoutes() return true } func bindRoutes(){ // Register routes that're handled let storyboard = UIStoryboard(name: "Main", bundle: nil) let root = self.window?.rootViewController as! UINavigationController router.register("/authors") { (params) -> Void in let list: AuthorsTableViewController = storyboard.instantiateViewControllerWithIdentifier("AuthorsTableViewController") as! AuthorsTableViewController root.pushViewController(list, animated: true) } router.register("/authors/{id}") { (params) -> Void in let profileVC: AuthorProfileViewController = storyboard.instantiateViewControllerWithIdentifier("AuthorProfileViewController") as! AuthorProfileViewController profileVC.authorID = Int(params["id"]!) root.pushViewController(profileVC, animated: true) } router.register("/authors/{id}/books") { (params) -> Void in let list: BooksTableViewController = storyboard.instantiateViewControllerWithIdentifier("BooksTableViewController") as! BooksTableViewController list.authorID = Int(params["id"]!) root.pushViewController(list, animated: true) } } func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool { if userActivity.activityType == NSUserActivityTypeBrowsingWeb { let url = userActivity.webpageURL! self.router.dispatch(url) } return true } 

Библиотека SHNURLRouter сопоставляет входящие ссылки и выполняет соответствующие действия.

Тестирование универсальных ссылок

Если у вас есть собственный экземпляр сервера, работающий и связанный с вашим приложением, теперь вы можете протестировать Universal Links.

Как правило, любая поддерживаемая ссылка, нажимаемая в Safari или в случаях UIWebView / WKWebView должна открывать приложение. Хороший источник тестирования — читайте мне о репозитории Github. Вы можете раскошелиться и отредактировать любое из примеров приложений в этой статье.

Если у вас нет собственного сервера или вы просто хотите увидеть это в действии, перейдите по ссылкам, приведенным здесь .

Примечание . Для iOS 9.2 и менее это будет работать только на устройстве. iOS 9.3 (еще на момент написания бета-версии) также поддерживает симулятор.

Вы можете сохранить ссылки в любом приложении, которое поддерживает их открытие, например, Telegram, и перейти оттуда.

Примечание . IOS запоминает выбор пользователя при открытии Universal Links. Если они нажмут верхнюю правую крошку, чтобы открыть ссылку в Safari, все дальнейшие щелчки перенаправят их в Safari, а не в приложение. Они могут вернуться к открытию приложения по умолчанию, выбрав « Открыть» в баннере приложения на веб-сайте.

Вывод

И это все. Не много кода, но много настроек. Ключевым выводом является то, что вам необходим контроль над собственным сервером для поддержки Universal Links. Если вы это сделаете, это лучший способ для перехода вашего пользователя с вашего сайта в ваше приложение.

Любые вопросы или комментарии, пожалуйста, дайте мне знать ниже.