2015/06/07

IIJmioのクーポンスイッチAPIを利用したApple Watchアプリケーションを公開しました

以前、ReactiveCocoaを利用したiOSサンプルアプリケーションを公開しましたが、それと同様のWatchサンプルアプリをGitHubで公開しました。

アプリ自体は非常に単純です。 iPhoneアプリではHddServiceCodeが表示される以外の実装はしていません。

契約ごとのクーポン残量の合計と、当日のクーポン利用状況のみが表示されます。

項目をタップすると、その契約にひも付いている電話番号と当日のクーポン利用状況が表示されます。

グランスでもほとんど同じ情報を表示します (ただし一つめの契約のみ)。

なお、Apple Watch側でブラウザを起動できませんので、あらかじめ本体アプリ側でOAuth認証を行っておく必要があります。

また、コンパイルして利用するにはだいたい次のようなことが必要です。

  • IIJMioクーポンAPIを取得してコードに埋め込む
  • entitlementを自分向けに書き替える
  • 署名を自分向けに書き替える

Watchアプリの構成

一般的なWatchアプリの構成は次の通りで、本アプリも同じです。

  • 本体アプリ
  • Watch Extension
  • WatchKitアプリ (ストーリーボードのみ)

普通のiOSアプリにターゲットにWatchKit Appを追加すると下の2つが追加されます。

Watch Extensionには (設定次第ですが) 次のような3つのコントローラクラスが追加されます。

  • InterfaceController (Watchアプリ)
  • NotificationController (Watch通知)
  • GlanceController (Watchグランス)

これらを別々に実装していくことになります。 今回は上2つを実装して、グランスは放置しています。

Tips

Groupを縦に並べたいときはLayoutをVerticalにする

WatchKit向けのUIではいろいろ配置に制限があったりします。

Groupには方向が決まっていて、デフォルトが横になっているので注意。

TableRowにNSObject派生クラスを指定

TableRowUITableViewCellみたいなものなのですが、該当するものはWatchKitにはありません。

かわりに、NSObject派生クラスをつくって、それをクラス指定してやれば利用できるようになります。

class TableRow : NSObject {
    @IBOutlet weak var hddServiceCode: WKInterfaceLabel!
    @IBOutlet weak var couponTotal: WKInterfaceLabel!
    @IBOutlet weak var couponUsedToday: WKInterfaceLabel!
}

セグエで呼ばれるメソッドがテーブルとそれ以外で異なる

  • テーブルにはcontextForSegueWithIdentifier:inTable:rowIndex:
  • テーブル以外はcontextForSegueWithIdentifier

Watch実機実行時にストーリーボードが変わってないことがある

ストーリーボードの内容を更新しても、Watch側で更新されていないことがあるみたいです。

新しく追加したUI部品でnilエラーになっていたりするのはこれが原因です。

iPhone側のWatchアプリで開発アプリをuninstall → Installすればよいです。

実機実行前にエラー “A signed resource has been added, modified, or deleted.” が出て実行できない

OS X 10.10.3, Xcode 6.3.2, CocoaPods 0.37.1の環境では、再度実行しようとすると次のようなエラーが出てしまいます。

そのため、毎回実行する前に、DerivedDataを削除する必要がありました (毎回フルコンパイルすることになるのでキつい)。

Appアイコン

ターゲットWatchAppを追加するだけでは、WatchKit App向けのアイコンを追加することはできません。

アセット上でNew App Iconをして作り直すのがてっとり早いみたいです。

また、このアセットをのTarget MembershipにWatchKit Appを追加する必要があるかもしれません。

KeyChain Sharing

Apple Watchでは単体でブラウザを起動できないので、Watch単体でOAuth認証はできません。

そこで、本体とWatchKit ExtensionでKeyChain Sharingを有効にした上で、

  1. 本体アプリ側でOAuth認証で得られたアクセストークンを取得してKeyChainに入れる
  2. WatchKit Extensionでそれを利用して、IIJMioのクーポンAPIにアクセス。情報を表示する

というようにする必要があります。

なお、セキュリティ面を考慮してアクセストークンにはキーチェインを利用していますが、そういう必要がない場合には後述するNSUserDefaultsを利用してもよいでしょう。

本体がロックされているときにキーチェインにアクセスできない

Watchアプリでは、iPhone本体がロックされているときには次のようなエラーが表示されます。

これは、本体がロックされているときには、Extensionがキーチェインにアクセスできないことが原因です (SecItemCopyMatchingなどでerrSecInteractionNotAllowedが返されます)。

この詳細については次の記事を参照してください (この記事バックグラウンドフェッチについて書かれていますが、エクステンションでも同じことが言えます)。

WatchKit Extensionがアクセストークンを取得したら、その後はずっと利用できますが、何らかのタイミングでWatchKit Extensionが終了することがあります。 そうするとトークンが失なわれて、再起動時に本体をロックされているときにはアクセストークンが得られずに、(今回のアプリだと) APIにアクセスできなくなります。

NSUserDefaultsで前の状態を記録

KeyChainにアクセスできないときには、何も情報が表示できなくなるので、以前の情報を保存しておいてエラー時にそれを表示するようにしました。

情報の保存にはNSUserDefaultsを利用しました。これについては以前記事を書いたので、それを参照してください。

Safx: App GroupsとNSUserDefaultsでiOSアプリ間のデータを共有する

このアプリでは本体側から得た情報も、WatchKit Extensionで利用する予定だったので、App Groupsをオンにしていますが、現状では本体側は実装されていませんので得に意味がありません。

関連リンク

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。