可能性が広がるwatchapp開発

74
Oct. 14th, 2015 可能性が広がる Watch App 開発 Retty.Inc Yuta Sakata

Upload: yuta-sakata

Post on 15-Apr-2017

879 views

Category:

Software


6 download

TRANSCRIPT

Page 1: 可能性が広がるWatchApp開発

Oct. 14th, 2015

可能性が広がる Watch App 開発Retty.Inc Yuta Sakata

Page 2: 可能性が広がるWatchApp開発

“Retty” って何?

Page 3: 可能性が広がるWatchApp開発

食を通じて世界中の人々を Happy に

Page 4: 可能性が広がるWatchApp開発

実名制グルメサービス

口コミの精度を重視した実名制

誰かに勧めたいお店 の情報が集まる• • • • • • • • •

行きたくなるお店が見つかる

Page 5: 可能性が広がるWatchApp開発
Page 6: 可能性が広がるWatchApp開発
Page 7: 可能性が広がるWatchApp開発

海外展開

Page 8: 可能性が広がるWatchApp開発

エンジニア募集中 !!!

Page 9: 可能性が広がるWatchApp開発

コンテンツ

Page 10: 可能性が広がるWatchApp開発

コンテンツ

✤ 自己紹介

✤ Retty アプリを Watch OS 2 に対応させた話

✤ Watch OS, 1 と 2 の違い

✤ Watch OS 2 の新機能

✤ 可能性が広がる Watch App 開発

✤ まとめ

Page 11: 可能性が広がるWatchApp開発

自己紹介

Page 12: 可能性が広がるWatchApp開発

酒多 優太

✤ Retty でエンジニアをしている

✤ Android 版の開発をしていたが最近ミドルウェアを始めた

✤ 最近 Watch 向けアプリ開発した

Page 13: 可能性が広がるWatchApp開発

副業: 大学生

在籍期間 5 年 卒業まで 2 年

Page 14: 可能性が広がるWatchApp開発

Retty アプリを Watch OS 2 に対応させた話

Page 15: 可能性が広がるWatchApp開発

7月某日

「 Watch に新しい OS が出るから

対応作業してみない?」

「やるやる~ (棒」

気軽に引き受けた

Page 16: 可能性が広がるWatchApp開発

当初の予定

✤ すでにある WatchKitApp のコードに手を加えて Watch OS 2 で動くようにする

Page 17: 可能性が広がるWatchApp開発

実際やったこと

✤ Objective C で書かれた OS 1 向けのアプリを Swift で1 から書き直し

Page 18: 可能性が広がるWatchApp開発

たくさん躓いた

✤ そもそも Xcode 触ったことない

✤ そもそも Objective C (iPhone 版と旧 Watch 版の開発言語) がわからない

✤ そもそも iPhone に SIM 刺さってない

✤ そもそも開発機のバンドが小さくて装着できない

Page 19: 可能性が広がるWatchApp開発

技術的に躓いたこと

✤ できないビルド

✤ bitcode 問題

✤ ライブラリ問題

✤ ビルド設定

✤ なぜか通らないビルド

✤ なぜか通るビルド

✤ なれないツール

✤ beta のバグ

✤ デバッガを挿すと動かないアプリ

✤ 起動不能になる OS X

✤ 失われたリポジトリ

Page 20: 可能性が広がるWatchApp開発

できないビルド

とりあえず現状のコードでビルドしてみるか~

—できない

Page 21: 可能性が広がるWatchApp開発

Xcode 曰くbitcode の埋め込みを off にするかバイナリで持ってるモジュールに bitcode を含ませるとビルドできるよ

↓off にしたらビルドできた!! 

↓Watch OS 2 App は bitcode 必須 

↓辛い

Page 22: 可能性が広がるWatchApp開発

bitcode って何

✤ LLVM IR を実行形式に埋め込むフォーマット

✤ objC とか -> LLVM IR -> ( bitcode ) -> アセンブリ -> 実行形式

✤ lli コマンドで JIT コンパイラに渡して実行できる

Page 23: 可能性が広がるWatchApp開発

bitcode のメリット

✤ Apple が突然 CPU アーキテクチャを変更したデバイスを売り始めても開発者がそれに対応してビルドし直す必要が無い

✤ 将来 Apple がアプリを最適化してくれるかも

Page 24: 可能性が広がるWatchApp開発

しかし…

✤ 含まれている Framework などがすべて bitcode を含む必要がある

✤ つまりバイナリで配っているライブラリにbitcodeが含まれているかどうかは提供者次第

✤ よってだいたい使えない (開発当時)

Page 25: 可能性が広がるWatchApp開発

ライブラリの壁

✤ CocoaPods で一応 interface に Watch OS 2を設定できるようにはなっていたが…

✤ 旧Watch App で使っていたライブラリまだ対応してない

✤ そのライブラリふんだんに使われてる

Page 26: 可能性が広がるWatchApp開発

ちくしょう !! 全部書きなおしてやる!!!

Page 27: 可能性が広がるWatchApp開発

“Because of the architectural differences between the platforms, sharing code may be more effort and add more

complexity than having two separate apps.”

–WatchOS 2 Transition Guide

Page 28: 可能性が広がるWatchApp開発

リリース前 OS の情報源

✤ 公式のドキュメント

✤ 公式のリファレンス

✤ ベータのリリースノート

✤ Apple Developer Forums✤ NDA の関係でお膝元でやってる系が強い

Page 29: 可能性が広がるWatchApp開発

なんとか発表前に完成させるも……

✤ 延期するリリース

✤ Watch 向けアプリが動かないとリジェクトされる

Page 30: 可能性が広がるWatchApp開発

余談

Page 31: 可能性が広がるWatchApp開発

OS X の突然死

✤ ストレージギリギリで Xcode beta のアップデートを試みたら OS X が起動不能になる

✤ 別のマシンで pull したら Initial commit だけ push されてた

✤ リカバリーモードが生きていたのでかろうじてストレージをマウントしてローカルリポジトリを復元することができた

Page 32: 可能性が広がるWatchApp開発
Page 33: 可能性が広がるWatchApp開発

✤ 出社したら pull

✤ ランチに行く前に push

✤ ティータイムの前に push

✤ 退社前に push

✤ 家で作業したら寝る前に push

Page 34: 可能性が広がるWatchApp開発

Watch OS, 1 と 2 の違い

Page 35: 可能性が広がるWatchApp開発

-公式ドキュメント AppleWatch2TransitionGuide より引用

Page 36: 可能性が広がるWatchApp開発

Watch OS 2 の新機能

Page 37: 可能性が広がるWatchApp開発

大雑把に言うと

✤ 公式 App でしか使えなかった機能が使えるようになった (e.g. センサー類、Taptical Engine)

✤ Watch App Extension がネイティブで動くようになった関係で必要になりそうな機能が追加され、iPhone がなくても大抵のことができるようになった(e.g. Tetherless Wifi、Security)

Page 38: 可能性が広がるWatchApp開発

このうち今回の移植に使ったのは

✤ WatchConnectivity✤ Security✤ CoreLocation

Page 39: 可能性が広がるWatchApp開発

Watch Connectivity

✤ iPhone Watch 間で通信をする仕組み

✤ 対話的メッセージングとバックグラウンド通信がある

Page 40: 可能性が広がるWatchApp開発

Background

OS がいい感じのタイミングで転送してくれる

転送前にキューに入る

転送の種類は次の 3 つ

✤ Application Context✤ User Info✤ File

Page 41: 可能性が広がるWatchApp開発

Application Context

✤ 最新の情報だけほしい時に使う

✤ 以前に送った Context が受け取られる前に別の Context が送られると新しい情報に置き換えられる

✤ 転送できるのは [String : AnyObject] な辞書

✤ Value の型によっては怒られることも

Page 42: 可能性が広がるWatchApp開発

User Info

✤ 送れるのは Application Context と同じ [String : AnyObject] 型

✤ Application Context と違い、以前送った情報が上書きされない

Page 43: 可能性が広がるWatchApp開発

File

✤ NSURL fileURLWithPath で取れるような NSURL と [String : AnyObject]? のメタデータが送れる

Page 44: 可能性が広がるWatchApp開発

Interactive

すぐに転送が始まる

iPhone Watch の間が Reachable でないといけない

NSData や [String : AnyObject] な辞書が送れる

Page 45: 可能性が広がるWatchApp開発

Reachable

✤ Watch App がアクティブであること

✤ iOS App が少なくともバックグラウンドで動作していること

この二点が満たされていると Interactive な転送が行える

WCSession の reachable プロパティで確認できる

Page 46: 可能性が広がるWatchApp開発

通信するまでの流れ

✤ Delegate を実装

✤ サポートされているかを確認

✤ セッションをアクティベート

✤ 通信

Page 47: 可能性が広がるWatchApp開発

import WatchConnectivity import WatchKit

class HogeInterfaceController: WKInterfaceController, WCSessionDelegate { override func willActivate() { super.init() if WCSession.isSupported() { let session = WCSession.defaultSession() session.delegate = self session.activateSession() } } // 受け取りたい転送タイプに対応した // コールバックメソッドを実装する }

Page 48: 可能性が広がるWatchApp開発

✤ 簡単に iPhone と情報がやり取りできる

✤ NSData が扱えるので柔軟性が高い

Page 49: 可能性が広がるWatchApp開発

可能性が広がる Watch App 開発

Page 50: 可能性が広がるWatchApp開発

こんなWatch App はいやだ

Page 51: 可能性が広がるWatchApp開発

✤ 小さい画面で画像を見てもあまり嬉しくない

✤ ましてや文章を読みたくない

✤ ごちゃごちゃとした操作はしたくない

✤ 腕が疲れるので長い時間操作したくない

Page 52: 可能性が広がるWatchApp開発

iPhone でできることは

iPhone でやろう

Page 53: 可能性が広がるWatchApp開発

iPhone でできないことって ?

Page 54: 可能性が広がるWatchApp開発

今回着目した Watch のメリット

✤ 豊富なセンサー類

✤ ちょっとした操作に限った時の圧倒的手軽さ

Page 55: 可能性が広がるWatchApp開発

なにか作ってみる

✤ センサーを試してみる

✤ 家電をコントロールする何かを作ってみる

Page 56: 可能性が広がるWatchApp開発
Page 57: 可能性が広がるWatchApp開発

Lピカ編

Page 58: 可能性が広がるWatchApp開発

普通に LED を光らせるだけだと

Watch と全然関係ないので

ムリヤリ Watchと関連付ける

Page 59: 可能性が広がるWatchApp開発

ゴール

✤ Watch から脈拍をとってきて同じ BPM で LED をピカピカさせる

✤ LED が光る !! 楽しい !!

Page 60: 可能性が広がるWatchApp開発

大体の仕組み

GPIO で出力HTTP 経由で BPM を送る

Page 61: 可能性が広がるWatchApp開発

iPhone 側

func applicationShouldRequestHealthAuthorization(application: UIApplication) { let healthStore = HKHealthStore() let dataTypes = Set([HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!]) healthStore.requestAuthorizationToShareTypes(nil, readTypes: dataTypes, completion: { (result, error) -> Void in }) }

Page 62: 可能性が広がるWatchApp開発

Watch 側

self.healthStore.requestAuthorizationToShareTypes( nil, readTypes: Set([ HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)! ]), completion: {(success, err) -> Void in } )

Page 63: 可能性が広がるWatchApp開発

self.workout = HKWorkoutSession(activityType: HKWorkoutActivityType.Other, locationType: HKWorkoutSessionLocationType.Unknown) self.workout?.delegate = self self.healthStore.startWorkoutSession(self.workout!)

Page 64: 可能性が広がるWatchApp開発

let bpm = samples![0] .description.componentsSeparatedByString(" ")[0] self.bpmLabel.setText(bpm) self.sendHeartRate(Int(bpm)!)

self.healthStore.executeQuery(self.query!)

Page 65: 可能性が広がるWatchApp開発

Raspberry Pi 側from threading import Lock import thread import RPi.GPIO as GPIO import time import SimpleHTTPServer import SocketServer

PORT = 8000 RATE_WRITE_LOCK = Lock() FLAG_WRITE_LOCK = Lock()

global hRate, isRunning hRate = -1 isRunning = False

GPIO.setmode(GPIO.BOARD) GPIO.setup(18, GPIO.OUT)

def pulse():

while True : global isRunning RATE_WRITE_LOCK.acquire() try : if hRate <= 0: isRunning = False break else : sleepTime = 60.0 / hRate finally : RATE_WRITE_LOCK.release() time.sleep(sleepTime - 0.1) GPIO.output(18, GPIO.HIGH) time.sleep(0.1) GPIO.output(18, GPIO.LOW)

Page 66: 可能性が広がるWatchApp開発

class Handler (SimpleHTTPServer.SimpleHTTPRequestHandler): def do_GET(self): global isRunning, hRate hRate = int(self.path.split("/").pop(1)) FLAG_WRITE_LOCK.acquire() try : if not isRunning : isRunning = True thread.start_new_thread(pulse, ()) finally : FLAG_WRITE_LOCK.release()

httpd = SocketServer.TCPServer(("", PORT), Handler)

try : httpd.serve_forever() except KeyboardInterrupt: print "Interrupted"

Page 67: 可能性が広がるWatchApp開発

家電操作編

Page 68: 可能性が広がるWatchApp開発

お蔵入り

Page 69: 可能性が広がるWatchApp開発

✤ 光が弱すぎて全然届かない

✤ 届いても認識されないことがよくある

✤ コードを保存するときに工夫が必要そう

Page 70: 可能性が広がるWatchApp開発

ゴール

✤ お布団の中からテレビを消したり

✤ 自室で作業中にリモコンに手を伸ばさずにエアコンを操作したり

✤ 帰宅した時には暖房が効いてる状態にできるようにしたり

こんな感じのことを手首からちょちょいとできるようにしたい

Page 71: 可能性が広がるWatchApp開発

大体の仕組み

リモコンから信号を受け取って記録する

HTTP で受け取ったコマンドに応じて信号を出力する

Page 72: 可能性が広がるWatchApp開発

まとめ

Page 73: 可能性が広がるWatchApp開発

✤ push だけはサボってはいけない

✤ iOS エンジニアがハードルを感じないようによく考え

て作られている

✤ 俗にいう IoT 関連のプロダクトでは活躍しそう

(完成しなかったけど HomeKitとかあるし…)

✤ 野良 Developer にはビジネス的においしくない

✤ おもちゃとしてとても優秀

Page 74: 可能性が広がるWatchApp開発

おわり