Статьи

Введение в Handoff

С iOS 8 и OS X Yosemite Apple представила новую замечательную функцию для разработчиков — Handoff . Handoff позволяет приложениям передавать данные и информацию о состоянии приложения с одного устройства на другое через Bluetooth. Это позволяет пользователям ваших приложений запускать задачу на одном из своих устройств, а затем непрерывно выполнять ее на другом.

Примером этого может быть начало написания сообщения на вашем iPhone, а затем завершение и отправка того же сообщения на вашем iPad. В этом уроке я покажу вам, как вы можете использовать Handoff в своих собственных приложениях с помощью очень простого приложения для создания заметок.

Это руководство требует, чтобы вы работали с Xcode 6+ и имели два устройства, совместимых с Handoff. Не все устройства iOS 8 имеют Bluetooth LE (Low Energy), который требуется для передачи обслуживания. Поэтому эта функция доступна и может быть протестирована только на следующих устройствах:

  • iPhone 5 и позже
  • iPad 4-го поколения, включая каждую модель iPad Air
  • Ipad мини
  • iPod Touch 5-го поколения

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

Создайте новый проект в Xcode и выберите шаблон приложения Single View из раздела iOS> Приложение .

Шаблон проекта

Настройте проект, как показано ниже. Обратите внимание, что для языка установлено значение Swift, а для устройстваUniversal .

Варианты проекта

Как только Xcode создаст ваш проект, откройте ViewController.swift и замените реализацию класса ViewController следующей реализацией:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {
 
    var noteTitleField: UITextField!
    var noteContentView: UITextView!
     
    override func viewDidAppear(animated: Bool) {
        self.noteTitleField = UITextField(frame: CGRect(x: 12, y: 28, width: self.view.frame.width — 22, height: 20))
        self.noteTitleField.placeholder = «Note Title»
        self.noteTitleField.delegate = self
         
        self.noteContentView = UITextView(frame: CGRect(x: 8, y: 56, width: self.view.frame.width — 16, height: self.view.frame.height — 64))
        self.noteContentView.text = «Note Content»
        self.noteContentView.delegate = self
         
        self.view.addSubview(self.noteTitleField)
        self.view.addSubview(self.noteContentView)
    }
     
    func textViewDidBeginEditing(textView: UITextView) {
        if textView.text == «Note Content» {
            textView.text = «»
        }
    }
     
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
     
}

Реализация довольно проста. Он заставляет класс ViewController принять протоколы UITextFieldDelegate и UITextViewDelegate , а также добавляет UITextField и UITextView в представление контроллера представления для ввода текста.

Создайте и запустите приложение на одном из ваших тестовых устройств, и вы должны увидеть очень простой пользовательский интерфейс с двумя полями ввода, текстовым полем для заголовка и текстовым представлением для содержимого заметки.

Начальный интерфейс пользователя

Действия, переданные между устройствами с Handoff, моделируются классом NSUserActivity . Вы узнаете больше об этом классе и о том, как использовать его позже в этом уроке. Во-первых, ваше приложение должно быть настроено для успешного создания этих действий.

Каждому виду активности, поддерживаемому вашим приложением, должен быть присвоен уникальный идентификатор, аналогично тому, как каждое приложение iOS имеет свой уникальный идентификатор. Эти идентификаторы могут быть любыми, но рекомендуется использовать запись обратного DNS, например com.tutsplus.handoff-ввод.note . Экземпляр приложения, работающего на каждом устройстве, также должен быть подписан одной и той же командой разработчиков iOS для правильного распознавания действий.

Сначала вам нужно добавить идентификаторы активности, которые поддерживает ваше приложение, в Info.plist цели. Откройте Info.plist цели и добавьте ключ NSUserActivityTypes . Сделайте этот элемент массивом и добавьте один элемент com.tutsplus.handoff-ввод.note , как показано на снимке экрана ниже.

Определение типов активности пользователя

Затем выберите проект в Навигаторе проектов и в редакторе справа откройте вкладку Общие . В разделе « Идентичность » выберите « Команда» для правильной команды разработчиков iOS.

Выберите правильную команду разработчиков

Выполнив эти шаги, при условии, что вы вошли в одну учетную запись iCloud и подключены к одной и той же сети Wi-Fi на каждом из ваших тестирующих устройств, ваше приложение готово к запуску с использованием Handoff.

Затем вам нужно добавить некоторый код для отправки активности пользователя с одного устройства на другое. Обновите метод ViewController класса ViewController как показано ниже.

1
2
3
4
5
6
7
8
9
override func viewDidLoad() {
    super.viewDidLoad()
     
    let activity = NSUserActivity(activityType: «com.tutsplus.handoff-introduction.note»)
    activity.title = «Note»
    activity.userInfo = [«title»: «», «content»: «»]
    userActivity = activity
    userActivity?.becomeCurrent()
}

Это создает базовый объект NSUserActivity с идентификатором, который вы добавили в Info.plist вашей цели ранее. Вы даете этому объекту активности title и словарь userInfo с пустыми строковыми значениями для заголовка и ключей содержимого .

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

Затем вы назначаете это новое действие userActivity вашего экземпляра ViewController чтобы API-интерфейс ViewController имел ссылку на него. Класс UIViewController наследует это свойство от класса UIResponder .

Наконец, вы вызываете becomeCurrent для объекта действия, чтобы сообщить системе, что это текущее действие пользователя, которое будет отправлено приложением.

Теперь вы успешно настроили свою пользовательскую активность, но мы также должны заполнить ее некоторым содержанием, когда пользователь пишет свою заметку. Для этого мы обновляем текущее действие пользователя, переопределяя метод updateUserActivityState(_:) в классе ViewController . Этот метод периодически вызывается API Handoff для обновления текущей активности пользователя. Добавьте следующий код в класс ViewController .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
override func updateUserActivityState(activity: NSUserActivity) {
    activity.addUserInfoEntriesFromDictionary([«title»: self.noteTitleField.text, «content»: self.noteContentView.text])
    super.updateUserActivityState(activity)
}
 
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    self.updateUserActivityState(userActivity!)
    return true
}
 
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    self.updateUserActivityState(userActivity!)
    return true
}

Метод updateUserActivityState(_:) дает нам ссылку на текущее действие пользователя и заменяет значения в словаре userInfo на последние значения из вашего приложения. Обратите внимание, что мы также вызываем этот метод в суперклассе.

Мы также реализовали два других метода: textField(_:shouldChangeCharactersInRange:replacementString:) протокола textView(_:shouldChangeTextInRange:replacementText:) и textView(_:shouldChangeTextInRange:replacementText:) протокола UITextViewDelegate . В этих методах мы обновляем текущую активность пользователя всякий раз, когда изменяется текст в любом из полей ввода. Хотя в этом нет необходимости, это гарантирует, что ваша деятельность всегда будет содержать самую свежую информацию.

Теперь вы готовы протестировать свое приложение с Handoff. Создайте и запустите приложение на обоих ваших тестовых устройствах. Нажмите кнопку блокировки на одном устройстве, чтобы перевести устройство в спящий режим, оставив приложение открытым на другом. Разбудите устройство, которое вы только что заблокировали, и вы увидите значок приложения в левом нижнем углу экрана блокировки. Выполните жест смахивания на этом значке, и ваше приложение возобновит работу через Handoff.

Кроме того, вы можете дважды щелкнуть кнопку «Домой», чтобы войти в переключатель приложений, и ваше приложение с поддержкой Handoff появится в левой части главного экрана. На данный момент ваше приложение возобновляет работу только с тем же пустым интерфейсом. Давайте исправим это сейчас.

Восстановление приложения из NSUserActivity обрабатывается вашим делегатом приложения. Затем делегат приложения передает объект активности пользователя в корневой контроллер представления приложения, чтобы восстановить себя. Если контроллер представления, который должен обрабатывать действие, не является корневым контроллером представления вашего приложения, то вы просто передаете его из корневого контроллера представления в иерархию контроллера представления, пока не достигнете желаемого места в своем приложении.

Откройте AppDelegate.swift и добавьте следующий метод в класс AppDelegate :

1
2
3
4
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]!) -> Void) -> Bool {
    self.window?.rootViewController?.restoreUserActivityState(userActivity)
    return true
}

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

Затем откройте ViewController.swift и добавьте следующий метод в класс ViewController :

1
2
3
4
override func restoreUserActivityState(activity: NSUserActivity) {
    self.noteTitleField.text = activity.userInfo?[«title»] as!
    self.noteContentView.text = activity.userInfo?[«content»] as!
}

Подобно методу updateUserActivityState(_:) restoreUserActivityState(_:) ранее в этом руководстве, вы переопределяете метод restoreUserActivityState(_:) для получения информации из объекта NSUserActivity . В вашей реализации этого метода вы обновляете оба поля ввода данными, хранящимися в объекте пользовательской активности.

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

Данные успешно переданы

В отличие от многих API-интерфейсов, предоставляемых Apple для iOS, обработка ошибок не является простой при использовании Handoff, если вы не знаете, где эти ошибки необходимо обрабатывать. Первая точка, в которой ваше приложение будет уведомлено об ошибке передачи обслуживания, — это application(_:didFailToContinueUserActivityWithType:error:) в классе делегата приложения. В этом методе вы можете определить причину ошибки и тип деятельности, к которой относится ошибка. Обратите внимание, что тип объекта NSUserActivity совпадает с уникальным идентификатором, который вы ему назначаете.

Когда ваше приложение переходит к операции передачи обслуживания, оно сначала должно загрузить данные, связанные с операцией, с исходного устройства через Bluetooth. До завершения этой загрузки, однако, вызывается другой метод делегата application(_:willContinueUserActivityWithType:) : application(_:willContinueUserActivityWithType:) . В этом необязательном методе вы можете вернуть логическое значение, чтобы сообщить API Handoff, хотите ли вы продолжать получать пользовательские действия. В некоторых ситуациях это может быть полезно, так как вы можете отключить определенный тип NSUserActivity при соблюдении определенных условий.

В этом уроке я показал вам, как вы можете использовать класс NSUserActivity для простого применения Handoff в ваших собственных приложениях для iOS 8. Вы создали очень простое приложение, способное передавать данные по беспроводной связи на другое устройство через Bluetooth.

Хотя пример приложения, которое мы рассмотрели в этом учебном пособии, был очень простым, ваши собственные приложения могут иметь столько типов пользовательских действий, сколько вам нужно для широкого спектра функций. Как всегда, если у вас есть какие-либо комментарии или вопросы, оставьте их в комментариях ниже.