LoginSignup
9
15

More than 3 years have passed since last update.

Apple watchでジャイロと加速度を取得する

Last updated at Posted at 2019-02-21

前提

  • watchOS 4.3.2
  • Xcode 10.1
  • iPhone 12.1.2
  • Apple Watch series 1

初版のApple watchが出た頃にジャイロの値を取ろうとしたが失敗した(APIは存在するが必ず固定値が返っていた)件の再チャレンジです。

watchOS 3 で「アレ」は本当にできるようになったのか?によれば、watchOS 3以降ではジャイロの値が取れるようになっているらしいです。

tl;dr

実装

WatchOS1の頃触ってから久しぶりにWatch Appの開発だったので、そもそもの作り方や考え方からやりなおします。

基本的なApple watchアプリの作り方

記事はだいぶ昔ですが内容は今でも通用します。
その他、だいたい「アレ」の記事の通りですが、躓いたポイントをメモしておきます。

ハンドラのエラーの型が違う

CMDeviceMotionHandlerの第2引数の型はErrorです
時代も移り変わり、Objective-Cの遺産とも言えるNSErrorは使わなくなったみたいです。

GyroscopeInterfaceController

    override func willActivate() {
        super.willActivate()

        let handler: CMDeviceMotionHandler = {(motion: CMDeviceMotion?, error: Error?) -> Void in
            self.rotLabelX.setText(String(format: "%.2f", motion!.rotationRate.x))
            self.rotLabelY.setText(String(format: "%.2f", motion!.rotationRate.y))
            self.rotLabelZ.setText(String(format: "%.2f", motion!.rotationRate.z))
        }

        if motionManager.isDeviceMotionAvailable {
            motionManager.startDeviceMotionUpdates(to: OperationQueue.current!, withHandler: handler)
        }
        else
        {
            rotLabelX.setText("not available gyro")
            rotLabelY.setText("not available gyro")
            rotLabelZ.setText("not available gyro")
        }

    }

詳しくはこちら → モーションセンサーの値が取得できない

githubのコードは直ってたので、プロはこんなところでは躓かないと思いますが、一応。

ビルドバージョンが高すぎて実行時にコケる

Deployment Targetをちゃんと4.3にしているのに、5系でビルドされてるからApple watchにインストールできないよと怒られる。

よく見るとExtensionだった。

スクリーンショット 2019-02-21 13.52.45.png

ちゃんとWatch Appのターゲットを適切な値にしましょう。

スクリーンショット 2019-02-21 15.10.12.png

クラスが足りなくて実行時にコケる

Watchアプリを作ってる人からしたら常識なのかもしれませんが、GyroscopeInterfaceController.swiftという新しいInterfaceControllerクラスを作ったのに、Extensionに追加してなくてコケました。

スクリーンショット 2019-02-21 15.19.49.png

ErrorLog

2019-02-21 15:18:09.519384+0900 WatchKitApp Extension[678:3114357] [default] -[SPRemoteInterface createViewController:className:properties:contextID:info:gestureDescriptions:clientIdentifier:]:3418: Couldn't instantiate class _TtC21WatchKitApp_Extension28GyroscopeInterfaceController
2019-02-21 15:18:09.521782+0900 WatchKitApp Extension[678:3114357] [default] -[SPRemoteInterface createViewController:className:properties:contextID:info:gestureDescriptions:clientIdentifier:]:3419: Critical failure. Simulating crash: Condition failed:"NO". Couldn't instantiate class _TtC21WatchKitApp_Extension28GyroscopeInterfaceController
(lldb) 

解決するには、自分で作ったクラスをExtensionのCompile Sourcesに追加します。

スクリーンショット 2019-02-21 15.16.30.png

クラスが足りなくて実行時にコケる 2

実は上記だけではだめで、storyboardのCustom classのロード元をextensionにしないといけません。

スクリーンショット 2019-02-21 15.31.52.png

このModuleが非Extensionだと、同じように実行時にクラスが足りないと言ってコケます。

上のようにExtentionのCompile Sourcesに新しいInterfaceControllerを追加すると、ここでExtentionが選択できるので、そちらを選びましょう。

スクリーンショット 2019-02-21 15.38.05.png

これで動きます。たぶん。

ていうかExtensionって何…

そもそもApple watch AppというのはiPhoneアプリのおまけのようなもので、処理はほとんどせずに、iPhoneアプリのViewとなることが想定されています。
その関係性を前提として、Apple watchから見たiPhoneの方(自分がViewであって、実処理をする側)の方をExtensionという、みたいです。

https://noumenon-th.net/webstrategy/2014/12/11/watchkit/

...というのが初期の思想だったみたいですが、watch自体の性能もだんだん上がってきているためか、現在の相関図ではwatch側にExtensionが存在してますね。

The Watch app bundle contains your app’s storyboards, while the WatchKit extension contains your app’s code and additional resources

いずれにせよ、Watch Appのstoryboardは表示のため、Extensionは実処理のためという考え方であって、アプリケーションのコードはExtensionに含まれるべきだということみたいです。
ゆえに、storyboardに紐づくソースは、Watch App側とExtension側でcompileされるよう設定すべきということですね。

謝辞

9
15
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
9
15