この投稿はWatchKit Advent Calendar 2014の2日目の記事です。

前提知識

Watch Appの画面

以下の3種類があります。
WatchKitのページの中央あたりに写真が載っています。

WatchKit Apps

アプリの画面です。WKInterfaceControllerクラスを継承して作成します。

Glances

read-onlyな情報を提示する画面です。WKInterfaceControllerクラスを継承して作成します。

Actionable Notifications

通知画面です。WKUserNotificationInterfaceControllerクラスを継承して作成します。WKUserNotificationInterfaceControllerクラスはWKInterfaceControllerクラスを継承しています。

Handoffとは

HandoffはiOS8およびOSXv10.10で新たに導入された機能で、同じユーザに結びつけられた複数のデバイス間で、操作内容(アクティビティ)を引き継ぐことができます。
(via Handoffプログラミングガイド)

WatchKitでHandoff

そもそも、そんなことできるの?

WatchKit – Apple Developerの動画の25:20あたりでUse Handoff APIと書かれているのできっと使えるはず!

今すぐためせる?

後述しますが、一部シミュレータで試せます。

リファレンスを読み解く

リファレンスを確認すると、WKInterfaceControllerにそれっぽいAPIがありました。
(長いのでとりあえず動かしたい人は、”実装してみる”まで読み飛ばしてOKです。)

WKInterfaceController

WKInterfaceController Class Reference

以下の2つのAPIがHandoffに関係ありそうです。

actionForUserActivity:context:

リファレンス

リファレンス日本語訳

Return Value
  • ルートのInterfaceControllerのかわりに表示する画面のInterfaceControllerのIdentifier。
  • nilを返すとルートのInterfaceControllerが表示される。
Discussion
  • このメソッドを実装して、Handoffからアプリが起動された時に、どのInterfaceControllerを表示するかをWatchKitに伝えるために使用します。
  • Glanceをタップすると、Glanceに対応するアプリが起動します。
  • 通常であれば、ルートのInterfaceControllerが表示されます。
  • しかし、GlanceでupdateUserActivity:userInfo:メソッドを呼び出すと、システムが起動サイクルの早期に他のInterfaceControllerのIdentifier※を返すチャンスをくれます。
  • もし、Glanceが有効なIdentifierを返したら、システムはルートの画面の代わりにIdentifierに対応するInterfaceControllerを表示します。
  • このメソッドのデフォルト実装は何もしません。このメソッドをオーバーライドするとき、superを呼び出してはいけません。

※ IdentifierはStoryboardで設定します。

解説

GlanceでupdateUserActivity:userInfo:メソッドを実行すると、アプリ起動時に表示する画面を切り替えられるようになります。
userInfoに好きな情報を入れられるので、アプリ起動時に任意の画面でuserInfoの情報を表示することができそうです。

updateUserActivity:userInfo:

リファレンス

リファレンス日本語訳

Discussion
  • Glanceでは、このメソッドを呼び出して、表示している内容についての情報をuserInfoとして提供してください。ユーザがGlanceをタップするとアプリにコンテキスト情報が送信されます。
  • このメソッドを呼び出すと、アプリにアクティビティを送信します。システムがiPhoneに情報を配信し、iPhoneが他のデバイスに情報を伝播します。
  • InterfaceControllerのコード実行中はいつでもこのメソッドを呼び出すことができる。

解説

メソッド名の通り、アクティビティの更新ができるようです。

実装してみる

前置きが長くなりましたが、いよいよWatchKitでHandoffを使うアプリを実装してみましょう。
リファレンスを読み解いた結果、2種類のパターンがあることがわかりました。

Storyboard

以下のようになってるとします。(XcodeのスクリーンショットはNDAなので…)
storyboard

[パターン1] iPhoneのアクティビティをAppleWatchで継続する場合

Glanceからアプリを起動します。
このパターンはシミュレータで動くことを確認できます。

処理の流れ

以下の様な流れになります。

p1

  1. GlanceでupdateUserActivity:userInfo:を実行する。
  2. ユーザがGlanceをタップする。
  3. Firstに実装したactionForUserActivity:context:がアプリ起動時に表示したいInterfaceControllerのIdentifier(つまりSecondのIdentifier)を返す。
  4. システムがIdentifierに対応するInterfaceController(つまりSecond)を表示する。

GranceController.swift

どこかでupdateUserActivity:userInfo:を実行します。
今回は、initで実行しました。

override init(context: AnyObject?) {
    super.init(context: context)
    NSLog("%@ init", self)    
    updateUserActivity("net.haranicle.watchHandoff.sample", userInfo: ["hoge":"piyo"])
}

FirstInterfaceController.swift

actionForUserActivity:context:を実装して、SecondのIdentifierをreturnします。

override func actionForUserActivity(userActivity: [NSObject : AnyObject]?, context: AutoreleasingUnsafeMutablePointer<AnyObject?>) -> String? {
    NSLog("%@ actionForUserActivity", self)
    
    return "secondInterfaceControllerId"
}

これだけでGlanceをタップすると自動的にSecondが表示されるようになりました!
(一瞬Firstが表示されます。)

動かないときは…

iOSシミュレータでiCloudにログインしてみてください。
Glanceの起動方法がわからない場合はググって!(NDAこわい)

[パターン2] AppleWatchのアクティビティをiPhoneで継続する場合

先に断っておきますが、このパターンは動きませんでした。
WatchKitのバグなのか、僕のコードが悪いのかわかりませんが。
以下は予想でしかないです。間違っていたら指摘してください。

処理の流れ

p2

  1. First実行中の任意のタイミング(ボタン押下時にした)でupdateUserActivity:userInfo:を実行する。
  2. システムがiPhoneに情報(アクティビティ)を配信し、iPhoneが他のデバイスに情報を伝播します。
  3. ユーザがiOSデバイスのロック画面のHandoffからiOSアプリを起動します。
  4. HandoffでiOSアプリ起動時にで継続の処理(application:willContinueUserActivityWithType)が実行されます。

FirstInterfaceController.swift

ボタン押下時にupdateUserActivity:userInfo:を実行しましたが、ボタン押下時にWatch画面に回るポンデリングが表示されっぱなしになりました。
なにか間違ってるんでしょうか..? このパターンの検証は諦めました。

@IBAction func onButtonPushed() {
    updateUserActivity("net.haranicle.watchHandoff.buttonPushed", userInfo: ["hoge":"piyo"])
}

まとめ

今回は[パターン1]iPhoneのアクティビティをAppleWatchで継続する場合はWatchKitでもHandoffが動くことがわかりました。
早く実機でためしたい!!

参考

Getting started with Handoff

宣伝

Swiftでカスタムキーボードアプリ作りました。買ってね!
特殊文字キーボード