URL Schemes или как передать данные между iOS приложениями

Думаю, все разработчики мобильных iOS приложений в курсе, что из собственного приложения можно запускать сторонние приложения. Например можно запустить клиент Youtube, кликнув на ссылку на видео, или вызвать почтовый клиент если нажать на кнопку «написать письмо». В конце концов — самый банальный пример — это открытие браузера при нажатии на гиперссылку. Подобное поведение реализуется путем добавления и настройки URL-схем в приложение. Более того, при помощи этого инструмента можно в операционной системе iOS зарегистрировать собственную URL-схему и использовать ее для передачи данных: т.е. реализовать запуск своего приложения из других приложений с заданными параметрами.

Задача

Нужно написать iOS приложение, из которого можно запустить системное приложение «Карты», стороннее приложения Youtube, а также собственное приложение. Для реализации двух первых пунктов нам потребуется разработать только одно приложение, однако для передачи данных именно в свое приложение нам понадобится это самое второе свое приложение. Т.е.  необходимо написать два iOS приложения одно из которых (для упрощения понимания мы назовем его Sender) будет с помощью URL-Scheme вызвать другое iOS приложение (назовем его Receiver). В зависимости от настройки приложения Sender в приложении Receiver, при его запуске из приложения Sender, будут меняться параметры отображения — цвет фона, надписи и пр.

Еще раз подчеркну, что подобным способом можно передать практически любые данные из одного приложения в другое — не только параметры отображения.

Решение

Создание Sender

Как было указано выше — данное приложение будет открывать сторонние приложения, а также вызывать приложение Receiver и передавать в него нужные нам параметры отображения. В Xcode создайте новое приложение, в качестве шаблона укажите Single View Application, назовите его Sender, язык разработки —  Swift.

В данном проекте необходимо собрать интерфейс, который будет состоять из нескольких надписей UILabel, одного текстового поля UITextField и трех кнопок UIButton. В MainStoryboard перетащите эти элементы на ViewController и задайте нужные ограничения.  Для удобства я задам цвет фона приложения и сделаю кнопки красивыми. Если у читателей возникнут вопросы как именно это сделать, то можно прочитать тут.  Также необходимо создать нужные IBOutlet и IBAction. Надеюсь читатели смогу сделать это самостоятельно, однако как именно это сделать можно прочитать в предыдущих уроках. Или можно задать вопрос в комментария и я или другие читатели с удовольствием ответят. Процесс создания интерфейса:

Код, который я добавил в ViewController:

//
//  proSwift.ru
//
//  Swift 3

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    
    @IBOutlet weak var mapsBtn: UIButton!
    @IBOutlet weak var youtubeBtn: UIButton!
    @IBOutlet weak var receiverBtn: UIButton!
    
    private func designFor(button: UIButton) {
        button.layer.cornerRadius = 8
        button.layer.shadowOffset = CGSize(width: 4, height: 4)
        button.layer.shadowRadius = 4
        button.layer.shadowColor = UIColor.black.cgColor
        button.layer.shadowOpacity = 0.6
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        designFor(button: mapsBtn)
        designFor(button: youtubeBtn)
        designFor(button: receiverBtn)
    }

    @IBAction func mapsBtnTapped(_ sender: UIButton) {
    }

    @IBAction func youtubeBtnTapped(_ sender: UIButton) {
    }
    
    @IBAction func receiverBtnTapped(_ sender: UIButton) {
    }
}

После компиляции интерфейс проекта выглядит вот таким образом:

 

 

Теперь нужно добавить код в созданные методы, которые вызываются по нажатию на кнопки. Весь фокус именно в них. Для кнопки карт добавьте следующий метод:

//
//  proSwift.ru
//
//  Swift 3

    @IBAction func mapsBtnTapped(_ sender: UIButton) {
        let path = "http://maps.apple.com/?q=" // 1
        let searchQuerry = textField.text!.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)! // 2
        let url = URL(string: path+searchQuerry)! // 3
        
        UIApplication.shared.open(url, options: [:], completionHandler: nil) // 4
        
    }

А для кнопки YouTube установите этот метод:

//
//  proSwift.ru
//
//  Swift 3

    @IBAction func youtubeBtnTapped(_ sender: UIButton) {
        let path = "http://youtube.com/results?search_query=" // 1
        let searchQuerry = textField.text!.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)! // 2
        let url = URL(string: path+searchQuerry)! // 3
        
        UIApplication.shared.open(url, options: [:], completionHandler: nil) // 4
    }

Внимательно рассмотрите эти два метода. Несмотря на разницу в целевой ссылке, — методы идентичны. Но давайте по порядку:

  1. Ссылка из URL схем нужного нам приложения. Они есть в свободном доступе в интернет — я нашел их все на официальном сайте Apple.
  2. Текст из строки textField мы переводим в набор символов, который применяется в URL
  3.  Собираем вместе URL для вызова приложения. В п.1 я взял схемы для поиска нужного запроса. Т.е. в нашем приложении мы пишем текст в строке, и нажимая на кнопку с картами или YouTube, мы откроем приложение и вызовем поиск по нашему запросу.
  4. Это ключевой метод, который осуществляет переход непосредственно к контенту, расположенному в передаваемой ссылке.

Давайте проверим работоспособность нашего кода.

ВНИМАНИЕ!!!! На текущий момент приложение YouTube не является системным для операционной системы iOS. Поэтому для проверки приложения рекомендую запускать его на реальном устройстве. Однако, даже если вы будете тестировать приложение на симуляторе — ничего страшного не произойдет. Просто вместо приложения YouTube запустится Safari и отроется страница  YouTube с результатами поиска

 Карты:

В строке поиска я ввел Burgers и при открыти приложения «Карты» я сразу увидел ближайшие заведения с бургерами. Даже если нужных заведений не найдено, приложение «Карты» открылось и получило запрос по строке из вашего приложения.

Теперь проверим следующую кнопку:

В качестве строки запроса я указал Starcraft 2. Думаю, результат будет понятен. Открывается приложение, и тут же срабатывает запрос поиска видео по нужной строке. Опять же, строку передали из стороннего (для приложения YouTube) вашего приложения.




Промежуточный итог

Итак, в нашем приложении мы реализовали запуск сторонних приложений и передачу им нужной информации. Мы сделали первую часть задания. Теперь же нам нужно создать свое приложение, которое зарегистрирует свою URL-схему в операционной системе iOS, что позволит организовать практическую любую интеграцию.

Метод вызова receiver

Однако перед реализацией приложения приемника, все же сначала стоит написать метод для третей кнопки в нашем приложении Sender. В нем мы реализуем проверку возможности запуска с помощью определенной URL-схемы и если это невозможно (а в нашем случае, пока нет приложения приемника, — это невозможно) мы сообщим об этом пользователю.

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

//
//  proSwift.ru
//
//  Swift 3

    @IBAction func receiverBtnTapped(_ sender: UIButton) {
        let path = "receiverapp://"
        let searchQuerry = textField.text!.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!
        let url = URL(string: path+searchQuerry)!
       
        if UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            let alert = UIAlertController(title: "Receiver не найден", message: "Приложение приемник ReceiverApp не установлено на данном устройстве", preferredStyle: .alert)
            let ok = UIAlertAction(title: "Ok", style: .default, handler: {
                _ in
                self.dismiss(animated: true, completion: nil)
            })
            alert.addAction(ok)
            
            self.present(alert, animated: true, completion: nil)
        }
    }

В данном методе следует обратить внимание на метод canOpenURL. Это метод проверит может ли iOS открыть передаваемую ссылку. Если в качестве URL-схемы будет передана схема, не зарегистрированная в iOS (и отличная, например, от http://,  или ftp:// ), этот метод вернет false. Мы обрабатываем этот вариант развития событий и выводим сообщение пользователю.

Также, идя на поводу у параноиков Apple, нашему приложению нужно разрешить использовать URL-схему. Поэтому мы идем в plist-файл проекта и добавляем ключ LSApplicationQueriesSchemes  и в качестве значения в массив устанавливаем  строку receiverapp

То же самое, толко в тестовом виде: в Project Navigator ctrl-клик на файл info.plist -> Open as -> Source Code добавьте строки:

    <key>LSApplicationQueriesSchemes</key>
    <array>
        <string>receiverapp</string>
    </array>

 

Приложение Receiver

Создайте новый проект в Xcode, используя шаблон Single View Application и назовите его Receiver. Перенесите несколько UILabel на View Controller, разместите их, задайте им ограничения и для одного создайте IBOutlet. У меня получилось так:

Все очень просто: запустите приложение, чтобы убедиться что оно заработало.

Далее нам необходимо зарегистрировать упомянутую нами ранее URL-схему receiverapp:// . Для этого идем в plist-файл проекта и добавляем в нем ключ URL types, а в нем добавляем ключ URL Scemes на одном уровне с ключом URL identifier. Чтобы вы не запутались привожу картинку как выглядит plist-файл и его код.

 

Или то же самое в текстовом виде: в Project Navigator ctrl-клик на файл info.plist -> Open as -> Source Code:

	<key>CFBundleURLTypes</key>
	<array>
		<dict>
			<key>CFBundleURLSchemes</key>
			<array>
				<string>receiverapp</string>
			</array>
			<key>CFBundleURLName</key>
			<string></string>
		</dict>
	</array>

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

Теперь немного порассуждаем: у нас приложение Receiver уже есть, оно работает, ни от кого не зависит. И даже регистрирует все необходимые параметры при установке. Оно запускается, и отображает View Controller. Однако оно ни как не реагирует на запуск себя из другого приложения. Более того, если сейчас запустить приложение Sender и нажать на третью кнопку, то приложение запуститься, точно также как если бы его запустил с экрана пользователь. Нет никакой разницы.

Это все потому, что нужно научить приложение реагировать на запуск его по URL-схеме. Для этого в файл AppDelegate нужно добавить следующий метод:

//
//  proSwift.ru
//
//  Swift 3

    func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
        
        let text = url.host?.removingPercentEncoding
        
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let vc = appDelegate.window!.rootViewController as! ViewController
        vc.textLabel.text = text
  
        return true
    }

 

В данном случае мы научили приложение реагировать на собственный запуск через URL-схему. В качестве текста мы взяли кусок строки, которая передалась нам как URL-ссылка. Однако через словарь options можно передать любые данные.  Если среди читателей будут желающие, я с удовольствием выложу пример.

Далее мы получили ссылку на отображаемый ViewController и передали ему полученный текст для отображения. Запускаем проект, переходим в приложение Sender, пишем какой-нибудь текст в строке textField и нажимаем на третью кнопку:

Думаю, этот простой пример позволит вам реализовать свои задумки и использовать данную разработку в качестве отправной точки.

Как всегда, жду критики, вопросов и тем для следующих уроков в комментариях.

Не забываете поддержать проект выключением блокиратора рекламы.




 

Sender: ссылка на GitHub

Receiver: ссылка на GitHub

8 Comments on “URL Schemes или как передать данные между iOS приложениями

  1. Оч круто, реальные,актуальные примеры, все подробно и вкусно, давно слежу за Вами. спасибо что не бросаете !

  2. Почему не осталвяете проект? потрогать бы, посмотреть как работает.

  3. Здравствуйте уважаемый администратор.
    Позвольте попросить Вас осветить тему по созданию приложения для конвертирования списка из .html страниц в электронную книгу формата .еpub.
    Которое бы включало возможность редактирования (выбросить ненужные ссылки и банеры) перед конвертацией в книгу. Подобное приложение есть в аппсторе Web2Book Pro — Convert and Pack Web Pages From Different Web Sites to An iBooks epub Book by stickto
    https://appsto.re/tr/xPTL0.i я им пользуюсь, но оно разработано под 32 битную систему, а значит с обновлением iOS до 11 версии с ним придётся распрощаться. Автор его забросил (не обновляет уже несколько лет) и на обращения не отвечает.
    Хочу подчеркнуть, я не требую от Вас написать приложение. Хотя мой курс программирования ограничивается знаниями 20 летней давности, я хочу учиться и постараться самому решить этот вопрос. Поэтому буду Вам признателен, если Вы, по возможности, реализуете на Вашем сайте обзор примеров способных помочь в реализации описанных мной целей.
    Спасибо.

  4. Здравствуйте.

    В приложении Receiver, в info.plist не прописан в поле URL types -> URL identifier идентификатор «ru.proSwift.receiverApp»

  5. И еще необходимо добавить в приложении Receiver, в info.plist, в поле URL types — Document Role с идентификатором «Editor»

  6. «Однако через словарь options можно передать любые данные. Если среди читателей будут желающие, я с удовольствием выложу пример.» Выложите, пожалуйста, пример.

  7. очень здоровская стать с классными пояснениями, жаль, что сайт не обновляется уже почти 4 года
    Хотелось бы увидеть обновленную данную статью, тк как я понимаю для ios 13 и выше она уже не актуальна 🙁

Добавить комментарий для Антон Отменить ответ

Ваш адрес email не будет опубликован.

*

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.