Hatena::ブログ(Diary)

Over&Out その後 このページをアンテナに追加 RSSフィード Twitter

2015-04-24

WatchKit もろもろ実機検証

Apple Watch をたまたま発売日当日ゲットできたので、いろいろと WatchKit アプリ開発に携わってきた 中で、「実機でやってみないと確信が持てないな。。」と思っていた諸々について検証してみました。


Xcodeからの実機インストール

Parent App をインストールして、Apple Watch アプリからインストールするのか、どうなのか・・・?


というところがよくわかってなかったのですが、やってみると何のことはない、Xcode から WatchKit App の Scheme を選び、Apple Watchとペアリングした iPhone を選択して Runするだけでした。


f:id:shu223:20150424135908j:image:w400


ちなみに親アプリを実機インストールするだけでもいけました。(ペアリング済みのWatchにアプリが自動的にインストールされる)


あと実機デバッグ時も普通にブレークポイントで止まってくれました。


親アプリからローカル通知を発行するとWatchKit Appで受けられるのか?

ドキュメント読む限りではできそうだけど、シミュレータでは通知受信時の見た目しか確認できないので、実際どうなのか・・・「親アプリとWatchアプリのどちらが通知を受け取るか」はiOSが制御する、と書いてあるし、親アプリが自分で受け取ってしまうということもありうるのか・・・!?


というわけで、次のように親アプリ側で「ボタンを押したら10秒後にローカル通知を発行する」という実装をしておいて、

UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
- (IBAction)notifyBtnTapped:(id)sender {
    
    UILocalNotification *localNotification = [UILocalNotification new];
    localNotification.alertBody = @"Hello!";
    localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10.];
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}

Apple Watch とペアリングした状態で試してみました。


ケース1: 親アプリがフォアグラウンド状態にある

通知発行ボタンを押して、そのまま親アプリが起動した状態にしておいた場合


Apple Watch側では通知を受け取らず


ケース2: 親アプリがバックグラウンド、iPhoneはロックされていない状態

通知ボタンを押して、ホームボタンで親アプリをバックグラウンド状態にし、iPhoneはロックせずにそのままにしておいた場合


親アプリでは通知バナーが表示されたが、Apple Watch側では通知を受け取らず


ケース3: iPhone側がロック状態にある

通知ボタンを押して、電源ボタンでiPhoneをロック状態にした場合


親アプリ、Apple Watch両方で通知を受け取った



というわけで、iPhone側ですぐに反応できない場合にウォッチ側で通知を受け取って表示する、という制御のようです。


Apple Watch 自体の BLE 仕様

Apple Watch の BLE 機能をデベロッパが制御できないのは WatchKit の API を見ればわかることですが、BLE自体は積んでるはず。アドバタイズメントパケット飛んでるのかな・・・?と見てみたところ・・・


f:id:shu223:20150424134509j:image:w375


普通にありました。


さすがに接続は拒否されるだろう、と思いつつダメ元で繋いでみたら・・・


f:id:shu223:20150424134554p:image:w240


何の問題もなく繋げました。


(繋いでみてわかる範囲で)Apple Watch の BLE 仕様をまとめてみるとこんな感じ。

  • アドバタイズメントパケット
    • Connectable
    • サービスUUIDのアドバタイズはなし
  • サービス
    • UUID: D0611xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    • キャラクタリスティックを1つだけ保持(下記)
  • キャラクタリスティック
    • UUID: 8667xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    • Properties: Write, Notify

Notification の Subscribe(Light Blue のUIだと Listen)も普通にできました。



念のため参考図書です↓↓


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898


【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF


デジタルクラウンでスクロール

アップルApple Watchのアプリ開発で、できないことのまとめ」という記事に、

開発者向けツールのWatchKitでは、タッチスクリーン上で指を使ったスクロールを可能にするAPIが提供されておらず、デジタルクラウンも使えない仕様となっています。

という記述があり、「明示的にAPIはなくても、普通に WKInterfaceTable とかのスクロールはデジタルクラウンでできるのでは?」と思ってましたが、どうなのでしょうか・・・?


→ WKInterfaceTable はデジタルクラウンでスクロールできました。


フォアグラウンドにある親アプリの制御

前述のWatchKitでできないことのまとめ記事に、こんな記述もありました。

  • 離れたiPhoneのカメラへのアクセスはできない

ただし、アップルは自社のカメラアプリからの利用は可能にするようです。

これも、カメラ機能を持った親アプリをフォアグラウンドにしておけば、普通に `openParentApplication:reply:` でシャッター切れるんじゃないか、と思ったので、試してみました。


親アプリ側で下記のように実装をしておいて、


(ViewController)

<UIImagePickerControllerDelegate>
@property (nonatomic, strong) UIImagePickerController *pickerCtr;
self.pickerCtr = [[UIImagePickerController alloc] init];
self.pickerCtr.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:self.pickerCtr animated:YES completion:nil];
- (void)takePicture {
    
    [self.pickerCtr takePicture];
}

(AppDelegate)

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply
{
    CameraViewController *vc = (CameraViewController *)self.window.rootViewController;
    [vc takePicture];
}

WatchKit Extension 側では下記のように実装をしました。

- (IBAction)takePicture:(id)sender {
    
    [WKInterfaceController openParentApplication:@{@"command": @"take_picture"}
                                           reply:^(NSDictionary *replyInfo, NSError *error) {
                                           }];
}

で、親アプリを起動しておいて、WathKit App側のボタンを押すと・・・


無事シャッターが切れました


結論:WatchKit App からフォアグラウンドにある親アプリのカメラ機能等を制御することは可能*1


iPhone側のBLE機能を利用

ウォッチ側のBLE機能はデベロッパは「直接的には」利用できないことは上に書いた通りですが、次の2通りの方法でiPhone側のBLE機能を利用することが考えられます。

  • WatchKit Extension で Core Bluetooth を利用
  • 親アプリで Core Bluetooth を利用

自分が実装したとある案件では親アプリが既にBLE利用機能を有していたので後者を選択しました。


ここではシンプルな例として、「ウォッチ側のボタンを押したら、バックグラウンドにいる親アプリが外部デバイス(ペリフェラル)との接続を確立する」ということを考えてみます。


バックグラウンドにおけるBLEのふるまいや制約については拙著に詳しく書いたのでここでは割愛するとして、WatchKit App をトリガとして Parent App にBLE関連処理を行わせる際のポイントとなるのは、BLEはスキャン、接続、サービス/キャラクタリスティック探索、Read/Write 等々、基本的には非同期的にレスポンスが返ってくる処理ばかりである、というところです。


`openParentApplication:reply:` は同期処理だし、非同期処理完了後にバックグラウンドの親アプリ側から WatchKit App を起こしたりデータを渡したりするAPIはありません。プッシュ通知やローカル通知を使う方法はありますが、プッシュ通知はタイムラグもありますし、ローカル通知は上で行った検証の通りウォッチ側で受け取れないケースが多すぎます。


で、僕はWatchKit Appからポーリングする実装にしました。


(ウォッチ側)

- (IBAction)connectBtnTapped:(WKInterfaceButton *)sender {
    
    // 接続処理開始をparentに依頼する
    [WKInterfaceController openParentApplication:@{@"command": @"connect"}
                                           reply:
     ^(NSDictionary *replyInfo, NSError *error) {

         if (error) {
             return;
         }
         
         [self.connectBtn setEnabled:NO];
         [self.connectBtn setTitle:@"Connecting..."];
         
         startTime = [[NSDate date] timeIntervalSince1970];
         
         self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5
                                                       target:self
                                                     selector:@selector(handleTimer:)
                                                     userInfo:nil
                                                      repeats:YES];
     }];
}

- (void)handleTimer:(NSTimer *)timer {
    
    NSTimeInterval interval = [[NSDate date] timeIntervalSince1970] - startTime;

    if (interval >= kTimeoutInterval) {
        
        // タイムアウト
        [self invalidateTimerIfNeeded];
        [self resetInterfaces];
    }

    // 接続状態をparentに確認する
    [WKInterfaceController openParentApplication:@{@"command": @"status"}
                                           reply:
     ^(NSDictionary *replyInfo, NSError *error) {
         
         if (error) {
             return;
         }

         BOOL isReady = [replyInfo[@"is_ready"] boolValue];
         
         if (isReady) {
             // 次の処理へ
         }
     }];
}

(親アプリ側)

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo
              reply:(void (^)(NSDictionary *))reply
{
    NSString *command = userInfo[@"command"];
    NSDictionary *replyDic;
    
    // connection 開始
    if ([command isEqualToString:@"connect"]) {
        
        replyDic = [self startConnecting];
    }
    // BLE接続ステータスを返す
    else if([command isEqualToString:@"status"]) {
        
        BOOL isReady = [[BLEManager sharedManager] isReadyForControl];
        
        replyDic = @{@"is_ready": @(isReady)};
    }
    // 中略

    reply(replyDic);
}

AppleWatchは実機がないのでシミュレータでしか試せない、BLE機能はシミュレータでは使えないというジレンマで検証できずにいたわけですが、今日手に入ったのでさっそく試してみたところ・・・


無事動作しました



しつこいようですが参考図書になります。。m(__)m

↓↓↓↓


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898


【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF




【フリーランス制作実績まとめ その5】WatchKitアプリ、技術書出版、BLE関連、GitHub世界第7位

いま表参道ソフトバンクの Apple Watch 当日販売分の行列に並びつつこれを書いております。恒例の3ヶ月ごとの制作実績まとめです。今回は2015年2月〜4月分。


(バックナンバー)


WatchMe Messanger

500 startups のときに同期だった PocketSupernova チームがリリースした Apple Watch のために最適化されたビデオメッセージングアプリ


なんと、日本の AppStore でどーんとフィーチャーされてます。


f:id:shu223:20150424082030j:image:w220


WatchMe Messanger は動画を使ったメッセージ交換アプリで、ウォッチ側では、

  • 届いた動画をウォッチ上でプレビューできる
  • ウォッチから素早く絵文字やSmartRepliesで返信できる

ということができます。要は友達から何かメッセージが来てスマホを出さずにすぐに確認できて、返信できる、というものです。


f:id:shu223:20150424082057p:image:w540


2015年に入っていろいろな Apple Watch アプリ開発の相談を受けましたが、WatchKit でできることがかなり少ないこともあり、「それ、あまりウォッチでやる意味ないような・・・」という企画も多い中、このアプリは Unda, VideoSelfie と動画コミュニケーションに特化して邁進してきた PocketSupernova の強みと、ウォッチというデバイス/インターフェースの特性をうまく活かしていて素晴らしい、と CEO の Oscar からアイデアを初めて聞いたときに思いました。


で、何を手伝ったかというと、開発初期の、フィージビリティ調査/プロト開発的なことを担当しました。WatchMe 開発にあたって「実装してみないとわからない」的な部分を洗い出して検証し、実際に動くものとして実装しました。


  • WatchKit Extension とサーバーサイド連携
    • アカウントを親アプリと共有するしくみ
  • 動画をウォッチ側でどうプレビューするか?
    • 動画を連番画像ファイルとして書き出すクラス
    • 連番画像を Parent app から WatchKit Extension に受け渡すしくみ
    • 解像度・枚数とパフォーマンスの関係
  • 各種カスタムUIの実現方法

等々。この仕事があって、iOSオールスターズ勉強会での発表に繋がったのでした。


"WatchMe Messanger" はウォッチを既に持ってる方はもちろん、まだ持ってない方も楽しめるアプリなのでぜひダウンロードしてみてください!


PLEN2

プリンタブルなオープンソース小型ロボット「PLEN2」のiOSアプリ開発を担当しました。*2


f:id:shu223:20150424082135j:image:w600


次のような特徴を持っています。

  • 身長約20cm、重さ約600gの小柄なサイズながら、18個の関節を持ち、高度な運動性能を備えたロボット
  • プリンタブル
    • 主要な部品はCADデータを公開、自分でカスタマイズ可能!
  • プログラマブル
    • メインの制御ボードはArduino互換
    • サンプルプログラムも公開。
  • ROS対応版もラインナップ
    • ロボット用オープンソース・ミドルウエアの「ROS(Robot Operating System)」対応版制御ボードもラインナップ
    • 本格的なロボット開発も可能!

なんとも物欲をくすぐられます・・・!!


kibidango では目標の230%に到達し、絶賛Back募集中の KickStarter でも既に目標額は超えています。(残り11日!)


今回はシンプルなアプリ制作のお手伝いでしたが、今後もいろいろと一緒にやらせていただくことになりそうです。


Smart Drive

そろそろ半年近いお付き合いになる Smart Drive 社のデバイスも、既に量産を開始していて、諸々始まっています。


f:id:shu223:20150424082204p:image:w97

DriveOn


f:id:shu223:20150424082223p:image:w240


諸々始まっているのですが、プレスリリースがまだのようなので、情報公開はこのぐらいで控えておきます・・・


(2015.4.28 追記)

ついに!フランスの保険・金融グループである AXA とスマートドライブの業務提携についてプレスリリースが出ました。

今後は、両社共同プロジェクトにて、アクサダイレクトの自動車保険事業とSmartDriveのテレマティクス※2サービス事業の高付加価値化の可能性を検討するなど、お客さまの安全運転の促進や事故予防につながるイノベーティブな新商品・新サービスの提供により、企業価値を更に高めるよう、スピード感を持ってまい進してまいります。


車の OBDII 端子というのは昔からあるものだし、そこからデータを取れるなら、今の時代であればBLEでスマホに飛ばして可視化したり、っていうのは IoT や Connected Car といった文脈からいっても実に自然な着想なので、そういう製品はいくつか既に出てき始めている中で、他製品との差異になって、ビジネス面の核にもなる「保険会社のアライアンス」というところを粛々と進めてきてついに実現したのはホント素晴らしいなと。


ちなみにこのアクサ社との開発が始動する頃、僕はiOS×BLE本の執筆で手一杯になってたので、知り合いの某素晴らしいiOSエンジニアを紹介しました。僕は傍観してただけ。。*3


ちなみにちなみに、アクサ社は Ingress 最強のシールド「AXA Shield」の AXA です。


f:id:shu223:20150428085619p:image:w200


とある新規ウェアラブルデバイス

完全に新規案件で、デバイスの仕様検討するところから、アプリもほぼまるっとお手伝いしています。


先日の中国出張も本案件絡み。

f:id:shu223:20150420054152j:image:w600


個人的にも早く使いたく、リリースするのが非常に楽しみなプロダクトです。*4


Eight の BLE名刺交換機能

Sansan さんが提供する名刺管理アプリ「Eight」に、BLEを用いて名刺を交換できる機能を実装しています。


f:id:shu223:20150424155046j:image:w200


従来バージョンにもAirDropでの名刺交換機能が入っていたのですが、AirDropはBluetoothに加えてWiFi接続も必要な上、なぜか相手が見つからない、ということも多いのでサッとBLEで交換できるというのはかなりユーザビリティが向上すると思われます。


あと、Android版はNFCで交換機能が実装されているのですが、BLEとすることで iOS ↔ Android 間でも名刺交換できるようになるのも大きいかと。


Moff SDK

Moff も引き続きお手伝いしていて、直近ではアプリのBLE制御、センサ値の処理/解析、モーション検出まわりの機能を切り出した SDKをつくりました。


さっそくTokyo MotionControl Network(通称TMCN)さんがいろいろとハックして先日のSXSWで展示もされていたようです。



現在はまだクローズドで展開しているので、SDKでつくってみたいものがある方はぜひ Moff 社にお問い合わせを!


WHILL

基板・ファームの更新もあって前回アップデートから半年ぐらい経ってしまいましたが、WHILLアプリの新バージョンもリリースされました。


f:id:shu223:20150424082506p:image:w240


また、Apple Watch から WHILL を操作できる WatchKit appも実装しました。さすがにWHILLは「電動車いす」というプロダクトの特性上、実機検証なしでリリースするわけにもいかないので、ストアにはまだ未申請です。


「鷹の爪団」のWatchKit App

「鷹の爪団」のコンテンツやグッズを展開するDLEさんにお声がけいただいて、

  • DLEさんがブレストで出したWatchKitの様々な企画についてフィードバック
    • できる、できない、部分的にできる、代わりにこうすればできる、等々
  • 1つ企画を選ぶ
  • そのまま開発へ突入(先方のデザイナーさんも作業)
  • 納品&先方のエンジニアさんに引き継ぎ

という1日コースでした *5 。開発合宿感があって楽しかったです。


ウォッチフェイスをカスタマイズするアイデアや、ウォッチ側での音の再生を前提とするアイデアなど残念ながら実現できないものが多くある中で、実現可能&DLEのコンテンツが活きる&その日のうちに完成できそう、ということで、たまごっち的に「吉田くん」を Apple Watch 上で育成する「よしだっち」を開発しました。



(追記)

冒頭に書いた通り Apple Watch 当日分購入の行列に並んでこの記事を書いてたのですが、開店直前にDLEさんがアプリの宣伝にやってきましたw


f:id:shu223:20150424113742j:image:w400

(総統)


『iOS×BLE Core Bluetoothプログラミング』出版!

ここ半年ぐらいのメインプロジェクト。konashi 開発者の松村礼央さんとの共著で、全480ページの大作です。


iOS×BLE Core Bluetoothプログラミング


BLEはこれから、という方にも、既にがっつり案件でやっている人にも役立つ内容となっています。電子版もあるのでぜひ!


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898


【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF


PodCastデビュー!

TimeTicketを開発・運営するレレレ社の山本大策さんよりお声がけいただき、PROTOTYPE.FM というポッドキャストに出演しました。


Podcast出演は初めてだったので、「話すぞ!」という気合が空回りして大策さんのナレーションに相槌かぶせまくりだったり、話もなかなか要領を得なくて素人感丸出しでお恥ずかしい内容ですが、10分ぐらい我慢して聞いてると慣れてくるのでぜひ!


前編はBLEにまったく興味のない大策さんにBLEについて解説したり、WatchKit や GitHub アワードについて話しています。

「今回のキーワード」 BLE(Bluetooth Low Energy)/Pebble/Arduino/konashi/iPhone同士でも動作確認可能/技術書『iOS×BLE Core Bluetooth プログラミング』/WatchKit/GitHubアワード


後編はキャリアの話。

「今回のキーワード」 自分で手を動かすこと/プログラミングはできなかった/社内ニート/iPhoneアプリ開発との出会い/フリーランスとしての働き方/見積りはしない/フリーランスに向いているタイプ/発信することの優先度が高い/何かを始めることが重要/追い詰められると出るパワー/失敗しても最終的にはプラスになる


ちなみに収録時間までに都内に戻れずWHILLオフィス(@鶴見小野)の会議室を借りてSkype収録していたのですが、知らずにWHILLのCTO福岡さんが入ってくるアクシデントもそのまま入っています笑


GitHub Awards 世界第7位!!!!

GitHub Awards という、言語別に各アカウントのスター数の累計をベースにランキングにしたサイトで、Objective-C 部門で世界第7位(!)となりました。


f:id:shu223:20150424220806j:image:w600


ちなみに一つ上の Brad Larson さんは GPU Image の人、一つ下の Robbie Hanson さんは CocoaAsyncSocket、XMPPFramework、CocoaHTTPServer の人です。周りがすごすぎる・・・!


僕(shu223)のリポジトリの内訳は、スター100以上のものを列挙するとこんな感じです。


*1:PowerPointを制御できるアプリとかもあるので、予想はついていたことですが。。

*2:※リリースはまだ

*3:僕が手伝ってたのは、スマートドライブ社のアプリ「DriveOn」

*4:情報公開はまだ先になりそうです

*5:もともと「Apple Watch について講義してくれないか?」という相談だったのですが、講義するほどのこともない&自分の価値はつくってなんぼなので上記コースを提案させていただいたのでした

2015-04-19

iOSアプリ開発案件で中国出張に行ってきました

とある案件で、中国は深セン(深圳/Shenzhen)に行ってきました。


f:id:shu223:20150420054152j:image:w600


もともとその案件では基板/ファーム部分を中国の会社が担当していて(BLEを介してのiOS側を僕が担当)、

  • こちらから要件を送る
  • (1〜3週間待つ)
  • 「できた」とファーム焼き込み済みサンプル基板が(中国から)届く
  • 検証してみると、色々要件を満たしてない(修正要件をまとめて1に戻る)

ということを二度ほど繰り返して、「これは埒が明かないのでは。。」と危惧していたところにタイミング良くそのお客さんが中国に工場見学等を目的に出張に行くというので「僕も行って向こうのエンジニアの隣で一緒に作業するときっとはかどりますよ」と便乗させていただいたのでした。


以下、出張の準備や、やったことのメモです。


旅程

出張、といってもたったの2泊3日、木曜の早朝に出て土曜の夜には帰国してました。


4/16(木)
  • 9:35成田発、約5時間後、香港着
  • 「HKTDC Hong Kong Electronics Fair 2015」(展示会)へ
  • 香港と深センの国境まで電車で移動
  • 深センからは車(迎えに来てくれていた)→ 会食

(香港→深センの国境。普通に通勤してる人も多いらしい)


4/17(金)
  • 基板・ファーム開発、生産を担当してくれる会社へ
  • 工場見学
  • あとはひたすら開発

f:id:shu223:20150420063608j:image:w600

(工場見学。左:ファーム書き込みの様子、右:電波を遮蔽するBluetooth検証用の個室)


4/18(土)
  • 深セン→香港へ移動、Shared Van 的なのを利用
  • Global Sources Electronics」(展示会)へ
  • 16:25香港発、帰国

f:id:shu223:20150420064132j:image:w400

(展示会に出ていた斬新なデザインの IoT キャップ)



航空券は諸々込みで6万円ほど(お客さんのと便を合わせたので、最安ではなかった)。


準備

よく知られている通り、中国は Gmail をはじめとする Google の各種サービス、Facebook (もちろん Messanger 含む)、LINE、Twitter 等々に繋げない、という不便すぎる制限がかかっています。


そんな中国に行く、ということを Facebook に書いたら、多くの方々が貴重な情報を寄せてくれました。


  • EC2でVPN立てとくのがオススメです!

この辺でしょうか。iPhone用の OpenVPN クライアントも App Store に出てます。

とりあえずであれば一ヶ月間無料のセカイVPNを契約して、帰国後無料期間中に解約、という手もありだと思います

先月まで深センにいましたが、ここ最近VPNの締め付けがきつくなっているのを実感したのであまり期待しない方が良いと思います。

昨年行った時はリモートデスクトップのホストを日本に残して対応しました。

先日北京に行って来ました。セカイVPN はホテルの Wifi だと安定して繋がりましたがレンタルのモバイルルータからだとほとんど繋がらず。余裕があれば自分で VPN サーバ用意するのがよいかも。あと、Shadowsocks というアプリはオススメ。これだけで、Facebook も Google も繋がりますよ。現地の中国人の方に教えてもらいました。


で、いろいろあって家を出る30分前ぐらいに準備を始めたので、VPN はセットアップする時間がなく断念、サクッとやれる対策としてやっていったのが、

  • Gmail の転送設定(Yahoo へ)
  • Shadowsocks のインストール

の2つ。Shadowsocks はブラウザアプリで、ややこしい設定も必要なく、Facebook や Twitter や Gmail にアクセスできました。


f:id:shu223:20150420055908p:image:w100


ただ、欠点としては、Ingress や Instagram など、ブラウザから使えないアプリはこの方法だとどうしようもないです。あとアプリ開発で Facebook の API たたきたい、といった場面でもアウト。やはり次回行く機会あればVPN立てようかと。



ちなみにコンセントは空港で全世界規格対応の変換プラグを買ったのですが、ホテルでもオフィスでも結局一度も使いませんでした。(日本規格のがそのまま入る)


共同作業の成果

あちらのファームエンジニアさんと隣で作業することで、

  • 要件を伝える
  • 「できた」と言われたら検証
  • できてない点を伝えて差し戻す(できていれば次の要件へ)

というのをその場で十数回は繰り返したので、これを海をまたいでデバイスをやりとりしていたかもしれないことを考えると、この1日だけで数週間分ぐらいの遅れのリスクを回避できたかと。やはりハードウェア絡みの案件は隣で作業するのが一番手っ取り早い、と再認識。


(ファームウェアエンジニアのホアンさん。この道十数年のベテラン)



お客さんとも中華料理と青島ビールを囲みつつ色々話せたし、開発も捗ったしでいいことずくめの中国出張でした。


f:id:shu223:20150420060736j:image:w350


2015-04-15

オープンソースになった ResearchKit の中身を見てみる

昨日、Apple が ResearchKit フレームワークのソースコードをまるっと GitHub で公開しました。



ここで「おお ResearchKit!!・・・って何だっけ・・・?」ってなった方も実は多いのではないでしょうか。僕はすっかり忘れててググって思い出したのですが、


医療に携わる科学者が研究のために、必要なデータを集めることができるフレームワーク


というやつです *1


Apple の新しいフレームワークのソースコードが公開されるという機会もなかなかないので、中身を見てみました。


試してみる

何はともあれ何ができるのか体感するためにも、まずは動かしてみたいところ。


さっそくリポジトリから git clone して Xcode で開いてみると・・・


f:id:shu223:20150415190139p:image:w197


フレームワークとドキュメント用のSchemeしかない・・・デモは・・・?


iOS Dev Centerを探してもサンプルコードがないので、「自分でつくっていっちょプルリクでも送るか」と思ってつくりはじめて数分後、ふとプロジェクトの別フォルダを見てみたら、既にありました・・・


ResearchKit.xcodeproj ではなく、samples/ORKCatalog/ORKCatalog.xcodeproj を開くと、デモアプリをビルドできます。


ただし、"No matching provisioning profiles found" になると思うので、その場合は Xcode で Fix Issue します。(それでも何かエラーになる場合は、iOS Dev Center に行って、該当する App ID について HealthKit が有効になっているか確認する)


ORKCatalog はこんな感じのデモアプリです。


f:id:shu223:20150415190351p:image:w200



試しに一番上の "Scale Question" を選択するとこんな画面に遷移しました。


f:id:shu223:20150415190414p:image:w200



3番めの "Time of Day Question" を選択するとこんな画面。


f:id:shu223:20150415190440p:image:w200



タスクをやり終えて、Resultsタブを選択するとこんな「結果」が表示されました。


f:id:shu223:20150415190516p:image:w200



なるほど、ResearchKitというのは、iOSの標準UIコンポーネントによる入力、タッチパネル上でのジェスチャ、加速度センサやGPS、マイク等のセンサ類をうまく使いまわして問診を行い、HealthKitと連携させてデータ収集・管理を行いやすくするフレームワーク、ということでしょうか・・・!?(とりあえず僕はそう解釈しました)


APIを見てみる

ORKCatalog のソースから、どう ResearchKit を使っているのかみてみました。ちなみに ResearchKit フレームワークは Objective-C で実装されていますが、ORKCatalog は Swift で実装されています。


ヘッダのインポート、プロトコルへの準拠
import ResearchKit
class TaskListViewController: UITableViewController, ORKTaskViewControllerDelegate {

セル選択時の処理

※日本語コメントは僕が付け加えたものです。

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)

    // 選択されたセルに対応する TaskListRow オブジェクトを取得    
    // Present the task view controller that the user asked for.
    let taskListRow = taskListRows[indexPath.row]
    
    // 取得した TaskListRow オブジェクトにひも付けられた ORKTask を取得
    // Create a task from the `TaskListRow` to present in the `ORKTaskViewController`.
    let task = taskListRow.representedTask
    
    // 取得した ORKTask オブジェクトから、対応する ORKTaskViewController オブジェクトを生成
    /*
        Passing `nil` for the `taskRunUUID` lets the task view controller
        generate an identifier for this run of the task.
    */
    let taskViewController = ORKTaskViewController(task: task, taskRunUUID: nil)

    // ORKTaskViewControllerDelegate をセット
    // Make sure we receive events from `taskViewController`.
    taskViewController.delegate = self
    
    // データを保存するディレクトリをセット
    // Assign a directory to store `taskViewController` output.
    taskViewController.outputDirectory = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String, isDirectory: true)

    // 遷移する
    /*
        We present the task directly, but it is also possible to use segues.
        The task property of the task view controller can be set any time before
        the task view controller is presented.
    */
    presentViewController(taskViewController, animated: true, completion: nil)
}

ORKTask オブジェクトの生成

上記でセル選択時に TaskListRow を通じて取得している ORKTask オブジェクトは、タスクごとに TaskListRow.swift で生成メソッドが別々に実装されています。


たとえば、上で出てきた「Scale Question」タスクの ORKTask オブジェクトの生成コードはこんな感じです。


private var scaleQuestionTask: ORKTask {
    var steps = [ORKStep]()
    
    // The first step is a scale control with 10 discrete ticks.
    let step1AnswerFormat = ORKAnswerFormat.scaleAnswerFormatWithMaxValue(10, minValue: 1, step: 1, defaultValue: NSIntegerMax)
    
    let questionStep1 = ORKQuestionStep(identifier: Identifier.DiscreteScaleQuestionStep.rawValue, title: exampleQuestionText, answer: step1AnswerFormat)
    
    questionStep1.text = exampleDetailText
    
    steps += [questionStep1]
    
    // The second step is a scale control that allows continuous movement.
    let step2AnswerFormat = ORKAnswerFormat.continuousScaleAnswerFormatWithMaxValue(5.0, minValue: 1.0, defaultValue: 99.0, maximumFractionDigits: 2)
    
    let questionStep2 = ORKQuestionStep(identifier: Identifier.ContinuousScaleQuestionStep.rawValue, title: exampleQuestionText, answer: step2AnswerFormat)
    
    questionStep2.text = exampleDetailText
    
    steps += [questionStep2]
    
    return ORKOrderedTask(identifier: Identifier.ScaleQuestionTask.rawValue, steps: steps)
}

また、"Time of Day Question" の ORKTask オブジェクト生成コードはこんな感じ。

private var timeOfDayQuestionTask: ORKTask {
    /*
        Because we don't specify a default, the picker will default to the
        time the step is presented. For questions like "What time do you have
        breakfast?", it would make sense to set the default on the answer
        format.
    */
    let answerFormat = ORKAnswerFormat.timeOfDayAnswerFormat()
    
    let questionStep = ORKQuestionStep(identifier: Identifier.TimeOfDayQuestionStep.rawValue, title: exampleQuestionText, answer: answerFormat)
    
    questionStep.text = exampleDetailText
    
    return ORKOrderedTask(identifier: Identifier.TimeOfDayQuestionTask.rawValue, steps: [questionStep])
}

ORKAnswerFormat で回答のフォーマットを選び、タスクの ORKQuestionStep (タスク内における各質問)を生成、それらを1つ以上指定して ORKOrderedTask を生成、という手順のようです。


ORKTaskViewControllerDelegate の実装

タスクが完了すると ORKTaskViewControllerDelegate の `taskViewController:didFinishWithReason:error:` が呼ばれます。


func taskViewController(taskViewController: ORKTaskViewController, didFinishWithReason reason: ORKTaskViewControllerFinishReason, error: NSError?) {
    /*
        The `reason` passed to this method indicates why the task view
        controller finished: Did the user cancel, save, or actually complete
        the task; or was there an error?

        The actual result of the task is on the `result` property of the task
        view controller.
    */
    taskResultFinishedCompletionHandler?(taskViewController.result)

    taskViewController.dismissViewControllerAnimated(true, completion: nil)
}

タスクが完了したのか、保存されたのか、失敗したのか、といったタスク終了の理由が引数に入ってきます。(下記は ORKTaskViewControllerFinishReason の定義)

enum ORKTaskViewControllerFinishReason : Int {
    
    case Saved
    
    case Discarded
    
    case Completed
    
    case Failed
}

フレームワークのソースを見てみる

せっかくオープンソースになったので、フレームワークのソースも見てみました。


全体像

ResearchKit.h を見てみるとパブリックヘッダだけでもかなり多いので、全体像を把握すべく、objc_dep を使ってクラスの依存関係を可視化してみました。


f:id:shu223:20150415190945p:image:w600


なんというカオス・・・依存関係図を画像としてexportしたら横幅12,164ピクセルにもなってしまいました・・・


ちなみに余談ですが、以前 facebook のアニメーションライブラリ pop のソースを読もうとしてみた際にも依存関係が複雑過ぎると感じたので整理してプルリクを送ったことがありますが、あれを遥かに凌ぐカオスっぷりです。。


一部フォルダだけに絞って依存関係を見てみると、相互依存などは少なく、比較的スッキリしていたので、単にとにかくクラスの数が多いためかなと。


気になったクラス

具体的に ResearchKit の実装のどこを見たい、というのもないので、適当に見てて気になったクラスや実装を挙げていきます。


ORKHTMLPDFWriter

HTMLを渡すとPDFに変換してそのバイナリデータを出力してくれるクラス。

- (void)writePDFFromHTML:(NSString *)html withCompletionBlock:(void (^)(NSData *data, NSError *error))completionBlock;

実装を見てみると、意外とシンプルで、

UIPrintFormatter *formatter = self.webView.viewPrintFormatter;
    
ORKHTMLPDFPageRenderer *renderer = [[ORKHTMLPDFPageRenderer alloc] init];

// (中略)
    
[renderer addPrintFormatter:formatter startingAtPageAtIndex:0];

UIWebView のプリントフォーマッタを使用、ORKHTMLPDFPageRenderer というクラスでレンダリング。ちなみに ORKHTMLPDFPageRenderer は UIPrintPageRenderer のサブクラス。こんなクラス知らなかったのですが、iOS 4.2 からあるようです。


ORKAudioContentView

ORKAudioStepViewController で使われる波形表示ビュー。


f:id:shu223:20150415191035p:image:w200


最近個人的に波形表示のあるアプリをつくることが多いので、Appleはこう作ってるのかーと。(自分の作り方とだいたい同じだった)


ORKDataLogger

実装ファイルは 1,600行以上もあって、まだちゃんと見てないのですが、最近いろいろとロガーOSSを見てどれも欲しいのと違って自作したということもあり、ResearchKitのloggerはどこがどう他のloggerと違うのか、それをどう実装しているのか興味あります。


ORKHelpers

ResearchKit 全体で使用しているマクロやヘルパーメソッドが詰まっています。何か便利なものがあるかもしれません。


ORKSkin

多くのビュークラスから参照されています。これで全体の見た目を統一しているようです。ORKScreenType で iPhone 4, 5, 6 を分類し、それに応じてソースにベタ書きした数値を返しています。

CGFloat ORKGetMetricForScreenType(ORKScreenMetric metric, ORKScreenType screenType) {
    
    static  const CGFloat metrics[ORKScreenMetric_COUNT][ORKScreenType_COUNT] = {
        // iPhone 6,iPhone 5, iPhone 4
        {       128,     100,      100},      // ORKScreenMetricTopToCaptionBaseline
        {        35,      32,       24},      // ORKScreenMetricFontSizeHeadline
        {        38,      32,       28},      // ORKScreenMetricMaxFontSizeHeadline
        {        30,      30,       24},      // ORKScreenMetricFontSizeSurveyHeadline
        {        32,      32,       28},      // ORKScreenMetricMaxFontSizeSurveyHeadline
        {        17,      17,       16},      // ORKScreenMetricFontSizeSubheadline
        // (中略)
    };
    
    return metrics[metric][screenType];
}

(つづく・・・)


所感

僕は医療関係者ではなく、そっち関連の知識もないので、「このフレームワークをつかえばあんなアプリやこんなアプリがつくれる・・・!」というところでのワクワク感はそんなにないのですが、Appleのフレームワークにプルリクを送れて、マージしてもらえる(かも)、というところには非常に可能性を感じます。


実際にプルリクは続々と届いており、コミット履歴を見るとわりと小さい修正でもマージされたりしています。


f:id:shu223:20150415192059p:image:w600


README にも Contribution という項目があり、全然 Welcome な雰囲気なので、何か修正したい点を見つけたらリクエストしてみようと思います。



ResearchKitを使った医療関連アプリのお仕事もお待ちしております!


2015-03-24

BLEと私

せっかく書籍を出すというありがたい機会にも恵まれたので、短いようで長い、BLEとの馴れ初めから書籍を出すまでの思い出を振り返ってみようと思います。



iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898


2013年・夏:Pebble をきっかけにスマホ連携ガジェットに興味を持つ

当時、シリコンバレーを拠点とするスタートアップ AppSocially で働いていました。


iOSアプリに友達招待機能を提供するSDKを開発していて、Facebook や Twitter 等のSNS連携が技術的な肝であり、Core Bluetoothや外部デバイスはまったく縁がなかったのですが、代表の高橋氏のところに届いたPebble *1 を見せてもらったのがそもそものきっかけだった気がします。



f:id:shu223:20150323140317j:image:w500



iOSのSDKも用意されていて自分でつくったアプリとも連携させられるというところにiOSエンジニアとして強烈に惹かれるものがあり、そこから「日本に戻ることになったらiOSと連携するガジェットを買い漁ろう」(当時アメリカでの住居はAirbnbを転々としていた&日本のアパートは引き払っていたので通販を利用しづらかった)という密かなワクワク感を抱き始めたのでした。


2013年9月:Arduino のワークショップに参加する → プチ挫折

諸々の事情で帰国することになり、まだリモートでAppSociallyの仕事はしていたものの、せっかく日本に帰ったので、週末は新幹線で都内まで出て行って(※福島の妻の実家に居候していた)ワークショップやハッカソンに参加するようにしていました。


で、自分で電子工作してガジェットつくれたら楽しいだろうなぁというのもあって、Arduinoのワークショップに参加したのですが、


f:id:shu223:20150323144716j:image:w400

記念すべき初のLチカ 2013.9.22


Lチカ *2 〜音声合成LSIを使ってしゃべらせる、というところを体験してみて、自分で好きなものをつくれるようになるまでの道のりは遠いということを痛感してしまったのでした。


2013年11月:iOS×外部デバイスの連載開始

自分でデバイスをつくるのは無理だ、という点はあきらめたものの、やはりガジェットまわりに興味はあったので、じゃあ「市販品で iOS SDK が用意されているもので楽しもう」ということで、自分の勉強をドライブするためにも、こういう連載を gihyo.jp の中の人の方に提案し、

無事企画が通り、連載開始となったのでした。


そしてこの連載の記念すべき第1回は konashi なのですが、本当にたまたまその掲載の前週、konashi を使ったワークショップに参加し、今回の共著者である松村礼央さんと初めてお会いしたのでした。(この時点ではまだBLEのビの字もわかってない


2013年12月:iBeacon の仕事が来る

Twitterでの繋がりで、iBeaconの仕事が舞い込んできました。



iOS+デバイス連携的なことに興味を持ち、連載を始めたりブログに書いてたりしてたのを知っていた MTL の @i2key さんからの絶妙のトスでした。ほんと何がやりたいとか書いとくといいことあると思いました。


これが後に火鍋レストランへのiBeacon導入につながっていきます。


2014年1月:BLEについて調べ始める

同じ頃、(NDAで書けないのですが、)とある新規ウェアラブルデバイス開発の相談がありました。で、「WiFiのようなインフラ無しで、ワイヤレスで通信したい」という要件に対して、じゃあ Core Bluetooth だろう、ってことで BLE について調べ始めたのでした。


これらの記事も今読むと相当やばい(誤解・間違いが多分にある)のですが、上原さんがやっている WF-BTLE グループに Bluetooth Low Energy と Bluetooth 4.0 を混同したトンチンカンな質問を投稿して丁寧にご回答いただいたのも確かこの頃です。


2014年2月:IRKit開発者の大塚さんからの叱咤激励

この頃、IRKitを出したばかりの大塚さんと飲む機会がありました。


そこで、「ハードウェア開発に興味あるけどハード側できないので、BLEに詳しくなってハードウェアプロジェクトでアプリ開発をやっていきたい」という話をしたら、最近のブログ記事の質が低い、というご指摘をいただいた流れからの)


「じゃあもっと勉強しないとね」(=まだそんなんじゃ通用しないよ)


というお言葉をいただき、もっと勉強しよう、と思ったのでした。


ちなみに本記事の趣旨からはそれますが、当ブログを始めるきっかけをくれたのも大塚さんです。


2014年3月:WHILLから仕事が来る

500startups時代に同期だった縁で、次世代パーソナルモビリティ「WHILL」からBLEを用いてWHILL本体と連携するiOSアプリ開発の話が舞い込みました。


(町田の開発拠点(当時)にて初めてWHILLに試乗。2014.4.5)


もともとWHILLというプロダクトもチームもすごくリスペクトしていて、しかも興味のあるBLE利用、ということで嬉しいオファーでした。最初のスカイプでCTO福岡さんが「CANが〜」と話し始めたときに「CAN????」となったのもいい思い出です。ウェブやアプリの開発現場とは何もかも違っていて、いろいろとカルチャーショックでした。


2014年4月:MoffのCTO米坂さんと会う

Qiitaのミートアップに参加した際、MoffのCTO米坂さんと初めてお会いし、Moffのアプリ開発のお仕事のお話をいただいたのでした。


当時Moffは、Kickstarterで目標の4倍となる金額を調達し話題をさらったばかりで、


f:id:shu223:20150323140032p:image:w600


それをFacebookのタイムラインでちょうど見かけたばかりで「おもしろいプロダクトだなぁ」と思っていた僕はもちろん飛びつきました。


2014年5月:書籍の執筆依頼

正確にはメールを頂いたのが4/28、初打ち合わせは5/1。僕の書いたブログ記事や連載記事を見て、フリーで編集者をされている大内さん(数々の技術書を出版されている)よりお声がけをいただきました。


一も二もなく飛びついた・・・というわけではなく、相当迷いました。


自分としては、「なぜ自分がBLEの本を書くのか?」というところにまだ答えを見いだせなかったからです。自分の知識の多くは上原さんをはじめ多くの方がWeb上に書いた記事やコードで勉強させてもらったわけだし、(ここまでの経緯をみるとよくわかると思いますが、)僕より詳しい人は大勢いるだろうし。


少なくともBLEの規格まわりについては自分は書けない、ということで大内さんが交渉してくれたのが共著者の松村礼央さんでした。


で、松村さんや大内さんとディスカッションを重ねるうち、

  • 「ペリフェラルとかキャラクタリスティックとか当初よくわからなかった」「BLE云々より、始めはただただガジェットいじりたかっただけ」というあたりの気持ちがよくわかる
  • 松村さんはkonashi、僕はWHILLやMoff等の実案件をこなしていて、そういう二人がタッグを組むのはいろいろと宿るものがありそう

というところで、自分がBLEの本を書く、ということがハラオチしてやっと原稿書き始めたのがなんと5ヶ月後(!)の10月。。(その節はご迷惑をおかけしました)


2015年3月23日:書籍出版

長くなってしまったのでここで一気に時間が飛びますが、その後いろいろなBLE絡みのお仕事があり、

2014年11月あたりから開発案件を少しおさえて、書籍執筆に専念しはじめました。



そして2015年3月、そんな汗と涙の詰まった書籍が、ついに発売となりました!



BLEを使ったiOSアプリ開発の解説書です。480ページの大ボリューム!BLEについてはゼロから学べるようになっています。また、「ハマりどころ逆引き辞典」は僕が実際に案件の中でハマって書き溜めたものなので、参考にするとかなりの時間短縮になると思います


というわけで「既にCore Bluetoothでアプリ開発をしている」方も、「ちょっと興味あるけどハードル高そうでまだ手を出してない」という方も、どうぞよろしくお願いいたします!


iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 626



*1:彼は Kickstarter でbackしてたのでいち早く入手していた

*2:LEDを光らせる。電子工作界のHello World的なもの

2015-03-23

『iOS×BLE Core Bluetoothプログラミング』という本を書きました

konashi 開発者の松村礼央さんと、iOS エンジニアの堤の共著で執筆させていただいた技術書「iOS × BLE Core Bluetooth プログラミング」がついに本日発売となりました!


iOS×BLE Core Bluetoothプログラミング


企画当初の予定ページ数(230ページぐらい)を大きく越え、480ページの大ボリュームになりました。企画が決まってからだと足かけ1年、共著の松村さんも僕も編集の大内さんも(おそらくDTPさんやデザイナーさんも)徹夜しまくりでデスマーチの様相を呈しつつ仕上げた労作なので、ぜひみなさまにポチッと・・・お願いしたいところではありますが、ニッチなテーマですし、価格も少々高めではあるので、本記事の内容紹介をご一読いただき、ピンとくるものがあればぜひお求めいただけると幸いです。



iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898


【電子版】(PDF・達人出版会)

iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF


書籍の概要

タイトルの通り、BLEを利用したiOSアプリ開発の解説書です。


大きく分けて2つのパートにわかれていて、

  • 最初のパート、第1章から第3章は、konashiの開発者である松村礼央さんによる執筆で、BLEという通信規格そのものについての解説
  • 第2のパート、第4章から第12章は、(iOSエンジニアである)堤による執筆で、Core Bluetoothを中心に、BLEを用いたiOSアプリ開発の解説

となっています。



各章の詳細項目は後述するとして、iOSにおける実装方法の解説だけじゃなくて、BLEの規格そのものについての解説もしっかり書いてあるのが本書のポイントのひとつで、そのあたりを堤が生半可な知識で書いても有用性が低いだろうということで、フィジカルなレイヤーから熟知されている松村さんとタッグを組ませていただいた、という経緯があります。


特筆すべきは松村さんが書かれた「3. BLEを理解する」で、なんとこの章だけで約150ページ(!)もあります。Bluetooth SIGによるドキュメント "Core Specification" は英語で約2700ページもあり、とても読める気はしないので、iOSエンジニア向けに噛み砕いて解説してくれているこの章だけでも個人的には「買い」だと思っています。



その他の概要・特徴紹介代わりに、「まえがき」に書いた内容を載せてみます。(赤字等の一部装飾はこの記事用に編集したもの。書籍自体は1色刷りです。)


まえがき

「BLEって何?」という質問に答えようとすると

  • 2.4GHz帯の電波を用いた–––
  • 超低消費電力を特徴とし–––

などなど、色々と説明すべきことがあるのですが、筆者(堤)のようなアプリ開発者の視点から端的にいうと、 「スマホアプリと外部デバイスをワイヤレスでつなげられる通信方式」 ということになります。


BLEという通信規格自体への興味はさておき、「スマホアプリと外部デバイスを連携させる」という分野に興味のあるアプリエンジニアの方は結構多いのではないでしょうか。

筆者も例外ではなく、そもそもBLEとの馴れ初めを振り返ると、「BLE」自体は意識せず、ただただ「iOSアプリと外部デバイスを連携させて何かやるのって楽しそう」という動機でkonashiを購入したのが始まりでした。


その後、次世代パーソナルモビリティ「WHILL」、ウェアラブルなおもちゃ「Moff」など、さまざまな案件にiOSアプリエンジニアとして関わらせていただくうちにBLEに関する知識も深まっていき、こうして書籍まで執筆させていただいているわけですが、ずっとベースにあったのは「スマホアプリと外部デバイスと連携させるのは楽しい」これに尽きます。


私個人のそういった経験もあり、「楽しそう」「つくってみたい」から入って、だんだんBLEのしっかりした知識もつくように構成したのが本書です。


たとえば、私は当初「セントラル」「ペリフェラル」「キャラクタリスティック」「アドバタイズ」という専門用語を難しく感じた経験があったので、4章「Core Bluetooth 入門」の序盤では、「周辺のBLEデバイスを探索する」「接続する」といったようになるべく専門用語を使わず説明するようにしています。


また、最初は「周辺のBLEデバイスを探索したい」だけなのに、そこでオプションの解説まで含めてしまうと、イベントディスパッチ用のキューの話やサービスによる絞り込みを行うかどうか、その場合バックグラウンドではどういった挙動になるか・・・といきなり新しい事柄が一度にたくさん出てきてしまい混乱のもとになるので、各項では新しく学ぶ事項を必要最小限にとどめ、後からより詳細を知りたくなったときに関連ページに飛べるよう、各項に「関連項目」の欄を設けています。


本書では、こういった「楽しそう」「つくってみたい」という気持ちを削がないための工夫を随所にしています。



松村・堤という実際にBLEプロダクトを開発した執筆陣がその経験に基いて書いているので、実践的な内容になっているのも本書のポイントです。


たとえば、「10. 開発ツール・ユーティリティ」で紹介しているツール群は、どれも筆者が日々の開発で使用しているものですし、「11. ハマりどころ逆引き辞典」は、筆者が実際に開発現場においてハマって大量の時間を食いつぶした汗と涙が凝縮されています。また本書の随所で、リファレンスなどからは汲み取りづらい注意点やポイントについて触れています。


そして松村の執筆した3章「BLEを理解する」では、超濃厚なBLE仕様に関する解説が展開されています。実案件においてBLEの特色を活かしたプロダクト設計をする際に、あるいはアプリエンジニアがハードウェアエンジニアと意思疎通する際に、これらの知識が役立ちます。



筆者はBLEと出会い、アプリの開発の楽しみがiOSデバイスの制約を越えて一気に広がったような感覚を得ました。読者のみなさまも、ぜひ、本書を片手に、iOS ✕ BLE の広大な可能性を楽しんでいただければ幸いです。


対象読者

本書は、iOSアプリ開発には慣れていることを前提としています。


したがって、Objective-C や Swift の言語そのものについてや、Xcode の一般的な操作方法、Gitやターミナルの基本的な扱い等々については解説を省略しています。UIKit や NSFoundation といった iOS SDK の一般的なフレームワークについても前提知識として取り扱っています。


逆に、BLEについては、知識ゼロからでOKです。


「BLEって何?」「何が嬉しいの?」という状態から読み進められるよう配慮し、構成してあります。


ゼロから入れるようにしつつも、かなり詳細な内容までカバーしているので、本書の内容をマスターすれば、実際に新規ハードウェア開発プロジェクトにiOSエンジニアとして入り、活躍することも可能かと思います。


経験者向けの見どころ

ある程度 BLE および Core Bluetooth の経験がある人にとっても、BLEの規格自体について説明している3章(松村さん執筆)は相当学びがあると思われます。(#僕は新しく勉強になることだらけでした。。)


また僕が執筆したiOSプログラミングのパートにも、何か新しい発見はあるかもしれません。「ペリフェラルへの再接続」「状態の保存と復元」など、Core Bluetooth では「知らなくても大抵の実装ケースにおいて問題ないが、知らないと損」なことが多くありますし、「Service Changed」サービスへの対応方法等、ググってもあまり具体的な実装方法が出てこない(2015年3月堤調べ)事項についても書いてあります。


実案件でBLEさわりはじめてるけどまだあまり自信がない、という方には11章「ハマりどころ逆引き辞典」が役立つと思います。実際に堤が数々の実案件でハマりつつ書き溜めてきた内容なので、かなりの時間短縮になるのでは、と思っています。


各章の概要と目次:Part1. BLE編

ここから具体的な目次を紹介していきます。各引用テキストは章扉にあるものです。


Part 1 は、松村さんによる「BLEという通信規格そのもの」についての解説です。iOS云々は抜きにして、まずBLEってなんぞや?というところを知るためのパートです。


1. はじめに

BLE(Bluetooth Low Enery)は、

従来のBluetoothとはどう異なるのでしょうか?

本章ではBLEのイメージをざっくりつかんでいきます。

  • 1-1. BLEとは何か

2. BLEをとりあえず体験する

BLEを使ったiPhoneとデバイスの通信を体験してみましょう。

本章ではツールキット「konashi」を使って、

まず用意されたアプリからkonashiを操作してみましょう。

後半では、konashi SDKを使って、自作アプリも作ってみます。

  • 2-1. konashiでBLEを体験する
  • 2-2. 初級編:konashiをとりあえず体験する
  • 2-3. 中級編:konashiをiOS-SDKを利用して制御する

3. BLEを理解する

本章では、BLEの規格をわかりやすく解説していきます。

iOSデベロッパーとしてどう仕様を読み解けばいいかも随所に明記していますので、

実装に役立てることができます。

  • 3-1. BLEの概要
  • 3-2. BLEの構造
    • 3-2-1. BLEのプロトコルスタック(アーキテクチャ)
    • 3-2-2. ATT(Attribute Protocol)
    • 3-2-3. GAP(Generic Access Profile)
    • 3-2-4. GATT(Generic Attribute Profile)
  • 3-3. BLEのネットワークトポロジー
    • 3-3-1. ブロードキャスト型トポロジー
    • 3-3-2. 接続型トポロジー
  • 3-4. BLEでのネットワークと通信の制御
    • 3-4-1. Bluetoothの無線仕様とPHY層(LE Physical)
    • 3-4-2. LL 層(Link Layer)
    • 3-4-3. LL 層における注意点
    • 3-4-4. Bluetooth Device Address
    • 3-4-5. AdvertisingとScanning
    • 3-4-6. Connection
  • 3-5. L2CAP(Logical Link Control and Adaption Protocol)によるパケットの制御
    • 3-5-1. L2CAP層(Logical Link Control and Adaption Protocol)
  • 3-6. BLEのパケットフォーマット
    • 3-6-1. Basic Packet Format
    • 3-6-2. Advertising Channel PDU
    • 3-6-3. Advertising PDU
    • 3-6-4. Scanning PDU
    • 3-6-5. Initiating PDU
    • 3-6-6. Data Channel PDU
    • 3-6-7. CRC(Cyclic Redundancy Check)
    • 3-6-8. L2CAP層でのパケットフォーマット
  • 3-7. LL層における通信のやり取り
    • 3-7-1. Bluetooth Device Addressによるフィルタリング
    • 3-7-2. Advertising Channelにおける通信
    • 3-7-3. Data Channelにおける通信
  • 3-8. GAP(Generic Access Profile)の詳細を知る
    • 3-8-1. GAPとは何か
    • 3-8-2. GAPによる「役割」の管理
    • 3-8-3. ModeとProcedure
    • 3-8-4. GAPによる「動作」の管理
    • 3-8-5. GAPによる「セキュリティ」の管理
  • 3-9. ATT(Attribute Protocol)とGATT(Generic Attribute Profile)の詳細を知る
    • 3-9-1. ATTとは何か
    • 3-9-2. Attribute の構造
    • 3-9-3. ATTサーバ/クライアントの対応するメソッドとPDU
  • 3-10. GATTとService
    • 3-10-1. Service の構造
    • 3-10-2. Characteristic の定義
    • 3-10-3. GATTによるService Changed、Characteristic
    • 3-10-4. GAPによるService、Characteristic
    • 3-10-5. GATT プロファイルのAttribute Type の一覧
    • 3-10-6. GATT プロファイルで利用できる機能
  • 3-11. iOSエンジニアのBLEあんちょこ
    • 3-11-1. Bluetooth Accessory Design Guidelines for Apple Products
    • 3-11.2. BLEはなぜ低消費電力なのか
    • 3-11.3. Core Bluetoothにおける20octet が何を示すのか

各章の概要と目次:Part2. iOSプログラミング編

Part 2 は、(iOSエンジニアである)堤による「BLEを用いたiOSアプリ開発」の解説パートです。


4. Core Bluetooth入門

本章から「iOSプログラミング編」として、Core Bluetoothの実装方法を解説していきます。

本章では、はじめの一歩目として、周辺のBLEデバイスを探索し、発見したデバイスに接続する、

そして接続したデバイスとデータのやりとりを行う、というBLEの通信の一連の流れを、

基本事項だけに絞って解説します。

  • 4-1. 周辺のBLEデバイスを検索する
  • 4-2. BLEデバイスに接続する
  • 4-3. 接続したBLEデバイスのサービス・キャラクタリスティックを検索する
  • 4-4. 接続したBLEデバイスからデータを読み出す(Read)
  • 4-5. 接続したBLEデバイスへデータを書き込む(Write)
  • 4-6. 接続したBLEデバイスからデータの更新通知を受け取る(Notify)

5. ペリフェラルの実装

前章「Core Bluetooth入門」では、スキャン、接続、データのやり取りなど、

セントラルとしてふるまうアプリの基本的な項目について解説しました。

本章では、ペリフェラルとしてふるまうアプリの実装方法、

すなわちiOSデバイスをペリフェラルとする方法について解説します。

  • 5-1. セントラルから発見されるようにする(アドバタイズの開始)
  • 5-2. サービスを追加する
  • 5-3. サービスをアドバタイズする
  • 5-4. セントラルからのReadリクエストに応答する
  • 5-5. セントラルからのWriteリクエストに応答する
  • 5-6. セントラルへデータの更新を通知する(Notify)

6. 電力消費量、パフォーマンスの改善

本章では、Apple の「Core Bluetooth プログラミングガイド」の

「ベストプラクティス」について書かれているパートをベースにしつつ、

関連事項や注意点などを加えながら、

「低消費電力」「パフォーマンス向上」につながる実装方法を解説していきます。

  • 6-1. スキャンの最適化
    • 6-1-1. スキャンを明示的に停止する
    • 6-1-2. 特定のサービスを指定してスキャンする
    • 6-1-3. できるだけスキャンの検出イベントをまとめる
  • 6-2. ペリフェラルとの通信の最適化
    • 6-2-1. 必要なサービスのみ探索する
    • 6-2-2. 必要なキャラクタリスティックのみ探索する
  • 6-3. ペリフェラルとの接続の最適化
    • 6-3-1. 接続の必要がなくなり次第すぐに切断する/ペンディングされている接続要求をキャンセルする
    • 6-3-2. ペリフェラルに再接続する
  • 6-4. イベントディスパッチ用のキューを変更する(セントラル)
  • 6-5. アドバタイズの最適化
  • 6-6. イベントディスパッチ用のキューを変更する(ペリフェラル)

7. バックグラウンド実行モード

本章では、Core Bluetoothで実装したBLEの機能をバックグラウンドで動作させる方法と、

バックグラウンドにおける制約(できること/できないこと)について解説します。

また「状態の保存と復元」という、非常に強力な機能についても詳細に解説します。

  • 7-1. バックグラウンド実行モードへの対応方法
    • 7-1-1. 対応方法1:Capalities パネルを利用
    • 7-1-2. 対応方法2:info.plistを直接編集
  • 7-2. バックグラウンド実行モードの挙動
    • 7-2-1. バックグラウンド実行モードでできること
    • 7-2-2. バックグラウンドにおける制約(ペリフェラル・セントラル共通)
    • 7-2-3. バックグラウンドにおける制約(セントラル)
    • 7-2-4. バックグラウンドにおける制約(ペリフェラル)
  • 7-3. アプリが停止しても、代わりにタスクを実行するようシステムに要求する(状態の保存と復元)
    • 7-3-1. バックグラウンド実行モードだけでは問題となるケース
    • 7-3-2. 「状態の保存と復元」機能でできること
    • 7-3-3. 実装にあたっての注意点
    • 7-3-4. セントラルにおける「状態の保存と復元」機能の実装方法
    • 7-3-5. ペリフェラルにおける「状態の保存と復元」機能の実装方法
  • 7-4. バックグラウンド実行モードを使用せず、バックグラウンドでのイベント発生をアラート表示する

8. Core Bluetoothその他の機能

本章では、これまでの章では説明していないさまざまなAPI や、

それを利用した実装方法について解説していきます。

「その他」といっても、ペリフェラルへ再接続する方法や、

UUIDやアドバタイズメントデータの詳細、サービス変更を検知する方法など、

BLEを利用したアプリ開発をしていると避けては通れない重要事項が多くありますので、

ひととおりおさえておくことをおすすめします。

  • 8-1. ペリフェラルに再接続する
    • 8-1-1. 既知のペリフェラルへの再接続
    • 8-1-2. 接続済みのペリフェラルに再接続する
    • 8-1-3. 再接続処理のフロー
  • 8-2. Bluetoothがオフの場合にユーザーにアラートを表示する
  • 8-3. UUID 詳解
    • 8-3-1. CBUUIDの生成
    • 8-3-2. 16ビット短縮表現
    • 8-3-3. CBUUIDの比較
    • 8-3-4. ペリフェラルのUUIDについて
  • 8-4. アドバタイズメントデータ詳解
    • 8-4-1. アドバタイズメント・データの辞書で使用されるキー
    • 8-4-2. アドバタイズメントデータの制約
  • 8-5. CBPeripheralのnameが示す「デバイス名」について
  • 8-6. 静的な値を持つキャラクタリスティック
  • 8-7. サービスに他のサービスを組み込む〜「プライマリサービス」と「セカンダリサービス」
    • 8-7-1. セカンダリサービスとは?
  • 8-8. サービスの変更を検知する

9. Core Bluetooth以外のBLE関連機能

iOSでは、Core Bluetooth以外にも、さまざまな機能やフレームワークでBLEが用いられています。

ANCSやiBeaconなど、いずれもiOSアプリの可能性を広げる重要な機能ばかりです。

本章では、それらの「iOSにおけるCore Bluetooth以外のBLE関連機能」について解説します。

  • 9-1. iOSの電話着信やメール受信の通知を外部デバイスから取得する(ANCS)
    • 9-1-1. ANCSとは?
    • 9-1-2. ANCS のGATT
    • 9-1-3. ANCS の実装方法
  • 9-2. iBeaconとBLE
    • 9-2-1. ビーコン=アドバタイズ専用デバイス
    • 9-2-2. iBeaconのアドバタイズメントパケット
    • 9-2-3. Core Bluetoothに対するiBeaconのアドバンテージ
    • 9-2-4. BLEの知見をiBeacon利用アプリの開発に活かす
  • 9-3. MIDI 信号をBLEで送受信する(MIDI over Bluetooth LE)
    • 9-3-1. CoreAudioKit
  • 9-4. BLEが利用可能なiOSデバイスのみインストールできるようにする
    • 9-4-1. Required device capabilities
    • 9-4-2. これまでに販売されたiOSデバイスのBLE 対応状況一覧

10. 開発ツール・ユーティリティ

本章では、BLEを利用したiOSアプリ開発に役立つ開発ツールや、

コマンドラインユーティリティを紹介していきます。

  • 10-1. 128ビットUUIDを生成するコマンド「uuidgen」
  • 10-2. 開発に便利なiOSアプリ「LightBlue」
  • 10-3. Apple 製開発用ツール「Bluetooth Explorer」
  • 10-4. 「PacketLogger」でBLEのパケットを見る

11. ハマりどころ逆引き辞典

iOSでBLEを利用するアプリを開発していると、

「スキャンで見つからない」「つながらない」といった場面はよく出てきます。

通信相手が新規開発デバイスだとそちらを疑いたくなることもありますが、

iOS側でのよくある実装ミスや勘違いというのも多くあります。

また、原因の判断方法や対処法を知っていれば一瞬で解決できるところを、

それらを知らずに、さまざまな検証やコードの修正のトライ&エラーで

時間を費やしてしまう、といったこともよくあります。

本章では、そんなiOS×BLE開発におけるよくあるトラブルと、

その解決のためのチェックポイントについて解説します。

  • トラブル1:スキャンに失敗する
  • トラブル2:接続に失敗する
  • トラブル3:サービスまたはキャラクタリスティックが見つからない
  • トラブル4:Writeで失敗する
  • トラブル5:キャラクタリスティックの値がおかしい
  • トラブル6:バックグラウンドでのスキャンが動作しない
  • トラブル7:バックグラウンドのペリフェラルが見つからない
  • トラブル8:セントラルの「状態の保存と復元」に失敗する
  • トラブル9:ペリフェラルの「状態の保存と復元」に失敗する
  • トラブル10:iBeaconが見つからない

12. BLEを使用するiOSアプリ レシピ集

これまでの章では、何らかのAPI や機能を説明するための単機能サンプルを提示してきましたが、

ここではそれらの機能を横断的に扱うアプリのレシピを提示し、その実装のポイントを解説します。

4つのレシピはiOS×BLEの分野において人気のある題材を集めつつ、

本書の内容がまんべんなく復習できるような内容にしてあります。

  • レシピ1:心拍数モニタアプリ
  • レシピ2:活動量計デバイスとアプリ
  • レシピ3:ジェスチャ認識ウェアラブルデバイス&アプリ
  • レシピ4:すれちがい通信アプリ

Appendix. BLEを使ったサービスを開発するということ



以上、書籍の目次でした。



書籍についてのFAQ

以下、本書について、よく聞かれる質問です。

Swift?Objective-C?

Part 2 は、ほとんどの節についてダウンロードサンプルを用意しています。(今数えたら、Part 2 だけで Xcode プロジェクトの数が 52 個ありました。)


で、セントラル・ペリフェラルの基本事項の解説にあたる4章・5章については ObjC・Swift 両方のサンプルを用意し、掲載しています。


その後の章についてはObjCをベースに解説しています。


konashiがないと読み進められない?

いくつかの例でkonashiを使ってますが、もちろん、お持ちでなくても全然大丈夫です。iPhone同士で通信する、Macと通信する、SensorTagを使う、といった諸々の代替方法も紹介しています。


f:id:shu223:20150323092420p:image:w600

(本書内の図版で使用している各種BLEデバイスの模式図)


BLE、用語がややこしくて敬遠している

筆者も、「ペリフェラル」とか「キャラクタリスティック」といった用語が難しそうで、ずっと敬遠してました。Core Bluetooth編の最初の章(4章)序盤では、なるべくそういう用語を使わないように「周辺のデバイスを探す」「接続する」といった感じで解説しています。(このあたりの配慮については、上に載せた「まえがき」もご参照ください)


BLE云々はよくわからないけどとにかく何かつくってみたい

いきなり12章のレシピからはじめてみるのも手です。「心拍数モニタアプリ」「活動量計デバイスとアプリ」「ジェスチャ認識ウェアラブルデバイス&アプリ」「すれちがい通信」とiOS✕BLEの分野において人気のある題材を集めつつ、本書の内容がまんべんなく復習できるようなサンプルにしてあります。関連項目もまとめてあるので、つくりながら必要に応じて戻って学習する、という学習スタイルも可能です。


BLEデバイスを買わないと気分が出ない

たとえば12章の「レシピ1. 心拍数モニタアプリ」「レシピ2. 活動量計デバイスとアプリ」はデバイス側をiPhoneで代用するレシピにしているので、(気分は出ないかもしれませんが)専用デバイス無しですぐに試してみることができます。また「レシピ4. すれちがい通信」も、iPhone同士で試せるレシピです。


「Bluetooth Low Energyをはじめよう」とどっちを買っていいかわからない

僕も買いました!原著も持ってましたが、和書も改めて。良書です。


Bluetooth Low Energyをはじめよう (Make:PROJECTS)
Kevin Townsend Carles Cufi Akiba Robert Davidson
オライリージャパン
売り上げランキング: 1,674


それぞれのAmazonのカテゴリの違いが、書籍のベクトルの違い・棲み分けを表しているかと思います。

  • Bluetooth Low Energyをはじめよう・・・カテゴリ:自作パソコン
  • iOS×BLE Core Bluetoothプログラミング・・・カテゴリ:モバイルプログラミング

目次を見ても内容のかぶりはほとんどなく、ボリューム的にもだいぶ違いがあります(そのぶん価格帯もちがう)。


f:id:shu223:20150322191754j:image:w300


なので、個人的には両方購入しても損はないと思いますが、ざっくり、

  • BLE という技術全体の概要を把握したい方・・・「〜をはじめよう」
  • BLEを使ったiOSアプリの実装に興味がある方・・・本書

みたいな感じかなと。


高い

すいません、価格はおさえたかったのですが。。なにぶんニッチな技術分野なもので、初回発行部数少なめなのと、ページ数やらの関係で、これぐらいになってしまうとのことです。このあたりは筆者側ではほとんどどうにもできない大人の世界のことなので、なにとぞご理解を。。


評判など

iOS x BLE Core Bluetooth プログラミング - maaash.jp

IRKit開発者による大塚さん( @maaash )によるレビュー記事。

BLEを使いiPhoneと通信するハードウェアを開発しようとする時、

まず身につけるべきは、問題が起きた時の切り分け能力だと思う。


iPhone側はアプリから見るとCoreBluetoothという抽象化したレイヤなので、

アプリ開発者は「scanFor…してるのに見つからないよ?」

デバイス側では「advertiseしてるよ?」

となった時にすぐパケットロガーを出せると話が早い。


この辺もちゃんと10章,10-3,10-4で書いてあってすばらしい。

実戦をこなしている著者陣ならでは。

ふわっとiOSアプリの作り方を解説するだけではなく、BLEについて詳しい3章があるのが心強い。

ハードウェアを作るならば、Bluetooth4の仕様を読むことになるだろう。

だが Core_V4.0.pdf は2302ページもあってしんどい。


そんなときにまずこの3章を日本語で読んで挑めるとかなりスムーズになるだろう。 自分も仕様はところどころピックアップして読んだだけなので、3章はいざという時のためにあたためておきたい。


Amazonのレビュー

BLEを使うサービス開発に関わる人必読の1冊, 2015/3/22


BLEをサービスに活用するにはどうすればいいのか?という一貫した視点で、BLEの通信規格とiOSのCoreBluetoothフレームワークの2つの基礎知識をしっかり解説しています。


開発対象がiOSではなくAndroidでも、またアプリやハードの直接の開発者でなくても、BLEを使った何かを考える方には、必読の1冊です。


iOSアプリ開発では、開発方法だけではなく、トラブルに遭遇したときに、なぜそうなるのかありうる原因の逆引きが書かれています。分野をまたぐ開発では、なにかうまくいかない時に、通信を含む全てを知っていないと原因すら思いつけません。一方で、通信規格やSDKがしっかりしているので、開発者が陥りやすいトラブルは数える程度しかありません。筆者の開発実務経験があるから、逆引きを書かれたのだろうと思います。


BLEを使ったいろいろなものを手がけられてきた方々の対談がAppendixとして収録されています。BLEを使ったサービスを考えるときに外せない考え方や原則みたいな、まだ構造化できない不定形の知識がこの対談にまとまっていると思いました。BLEを使うサービス開発は、どうしても形あるハードウェアに目を奪われます。ですが、Appendixと1章を何度か読み返していると、BLEはリモコンじゃないんだな、とか、なぜ1章でサービスという単語が度々使われているのかが、すっとわかる気がします。


IoTという単語が話題になる2015年、"つながる"を強く主張する発表が続くと思います。しかし、IoTの強力な1手段でもあるBLEの本質は、つながることよりも、つなげない使い方や、つながったり切れたりする利用場面を思うことが重要なのだなと、読んでいて思いました。


『iOS×BLE Core Bluetoothプログラミング』の評判まとめ - Togetterまとめ

買えるところ

Amazon

iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 898



リアル書店

下記リンクから、本書の近隣のリアル店舗における在庫の有無が調べられます。


https://takestock.jp/book/4883379736/search/


(新宿紀伊國屋書店での松村さんのツイート)


(2013.3.31追記)電子書籍版

多くのお問い合わせをいただいていた 電子書籍版(PDF)も出ました!!!!達人出版会さんよりご購入いただけます。


iOS×BLE Core Bluetoothプログラミング
堤 修一, 松村 礼央
ソシム
発行日: 2015-03-23
対応フォーマット: PDF


こちらからサンプルが読めます。


ちなみに、ソシムの本書の読者サポートページの「正誤情報」から、該当ページだけ修正PDFがダウンロードできるのですが、こちらも購入検討用サンプルとして見ていただくといいかもしれません。



2009 | 08 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2015 | 01 | 02 | 03 | 04 |