20
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[watch OS1] WatchKitの初期表示画面を動的に変更する方法

Last updated at Posted at 2015-03-26

watch OS1 専用

**ここで書いていることはwatch OS1のためのものです。watch OS2の場合はWKExtensionDelegateというクラスがあるので、そちらでハンドリング可能だと思います(未検証)。

AppleWatchにはAppDelegateがない

WatchKitで画面を作成するとこんな感じになると思います(GlanceとNotificationはオプションなのでない場合もある)。

画面構成.png

ユーザーの状態などによってWatchAppに表示する画面を切り替えたい場合があったりします。ユーザーがログイン済だったらタイムラインを表示、未ログインだったらログインページを表示する、みたいな場合です。

iPhoneだったらAppDelegateなどでうまく処理して表示の切り替えを行うことになるのですが、残念ながらAppleWatchにはAppDelegateがないので、Storyboardでis Initial ControllerがつけられたWKInterfaceControllerが最初に呼ばれるようになります。

initial.png

動的にコントローラーを変更する役割のWKInterfaceControllerを用意する

最初、これを解決する方法が分からず「どうしようもないFrameworkだな」くらいに思っていたのですが、WKInterfaceControllerにAppDelegateに似た役割を持たせれば解決可能でした。

WKInterfaceControllerにはreloadRootControllersWithNamesというクラスメソッドが用意されており、第一引数にStoryboardで設定した各コントローラーのidentifierの配列を、第二引数のcontextsには各コントローラーに渡したいデータを渡します。


class func reloadRootControllersWithNames(_ names: [AnyObject],
                                 contexts contexts: [AnyObject]?)

このメソッドを利用すると、ルートのコントローラーから全て置き換わるため、ユーザーの状態によって異なる画面構成を提供することも可能になります。

サンプル

以下はEntryPointInterfaceControllerをinitial Controllerにし、iOS8.2のiPhoneからプリインストールされているApple Watchアプリに設定項目を追加します(Settings BundleをiPhoneアプリのターゲットに追加して設定項目を整えればOK)。

Settings Bundleの設定はこんな感じです(最下部の段が空欄になっていますがAppGroupsの設定を忘れないようにしてください1)。

settings_bundle.png

iPhone側のAppleWatchアプリではこのように表示されます。

apple-watch_setting1.png

apple-watch_setting2.png

iPhoneのAppleWatchアプリで設定した項目をNSUserDefaultsから読み込んでWatchAppの画面を切り替えるためのサンプルコードがこちらです。

class EntryPointInterfaceController: WKInterfaceController {

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
        
        let defaults: NSUserDefaults = NSUserDefaults(suiteName: "/* AppGroupsのidentifierを入れてください */")!
        let typeString: NSString? = defaults.valueForKey("screen") as? NSString
        
        if let type = typeString {
            
            if type.isEqualToString("login-screen") {
                WKInterfaceController.reloadRootControllersWithNames(["login"], contexts: nil)
            } else {
                WKInterfaceController.reloadRootControllersWithNames(["userInfo"], contexts: nil)
            }
            
        } else {
                WKInterfaceController.reloadRootControllersWithNames(["login"], contexts: nil)
        }

    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }
}

なお、このEntryPointInterfaceControllerawakeWithContextメソッド内でルートコントローラーを切り替える処理を行っているので画面に表示されることはありません。

もしなにかしら表示させたいのであればwillActivate()メソッド内でNSTimerなど少し時間をおいてreloadRootControllersWithNamesメソッドを呼び出せば良いと思います。

そのほかベストプラクティスとAppleがうたっている手法についてもまとめてあるので、AppleWatch開発をしている方はご覧になってみてください。

AppleWatch開発のベストプラクティス 〜WatchKit Development Tipsに書かれていることをまとめた〜

まとめ

現時点で実機でのテストができませんし、なかなか挙動が見えないのが辛いところですが、いろいろ開発していると足りない部分をうまく補って自然なように見せる工夫がAppleWatchには必要だと感じます。

バッテリー問題が足を引っ張っていろいろな制限がかかっていると思うので、将来的にはこういった苦しい工夫をしなくても良くなるのではないかと思いますが、新しいデバイスのアプリを開発する醍醐味ってこういうところにあるんじゃないかな〜なんて思って楽しんで開発しています。

デベロッパーそれぞれが色々な工夫を施して出してくるはずなので(というかせざるを得ないのですが)、発売するまでにどれくらいのアプリが対応されるか楽しみですね。

  1. WatchAppはiPhoneアプリのExtensionなのでAppGroupsの設定が必須になります。プロジェクト内の各ターゲットはもちろん、Settings Bundle、NSUserDefaultsを生成する際もAppGroupsの設定を忘れないようにしてください。

20
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?