Open17

HealthKitから定期的に歩数や睡眠や体重などのデータを取得する実装の作業ログ

satomilkysatomilky

さて、まずは、体重からやる(私が個人的に今、一番ほしいので。)

取得周りは、初回インポート時の実装はちゃんとできてるので、あまり問題ない。
データの取り扱いのクセや形成が結構必要なこともわかってる。

今回の追加実装で、気になってるのは

  • アプリを開く度、前回取得分は除いて差分だけ取得できるのか?
  • ヘルスキットからデータを一回取得→その後、こちらのアプリの入力インタフェースでデータ編集→その後、また同日データでヘルスキット上のデータに更新があった場合、どう対処すべきか?(どっちを採用する?ってのは、UX最悪なので絶対やりたくない。できるだけ決めうちにしたい)

ぐらいかな。(一旦、子どもとお風呂入るので離脱)

satomilkysatomilky


アプリを開く度、前回取得分はのぞいて差分だけ取得できるかどうか?はできるし変更してたとしても対処できそうかも。

ただ、

ヘルスキットからデータを一回取得→その後、こちらのアプリの入力インタフェースでデータ編集→その後、また同日データでヘルスキット上のデータに更新があった場合、どう対処すべきか?(どっちを採用する?ってのは、UX最悪なので絶対やりたくない。できるだけ決めうちにしたい)

これに結局、ちゃんと対処しなきゃだな。
各デイリーのデータに対して、HealthKitからの自動取得データかアプリからの手入力かどうかのフラグを何らかの形で持たせるしかないか。

どうやって持たせよう。。ぬううう。

satomilkysatomilky

わからん。Swift詳細をちゃんと読み返して、設計方針固めねばかもしれん。

それか、もしくは、データがnil(空)の時にだけ、読み取る。と言う感じで一回限りの読み取りにしようか。。そうすれば、少なくとも、データの競合は起きないよね。

そして、万が一再取得したい場合は、ユーザーの任意のタイミングで、更新ボタンを押させるみたいな感じにしよ。
うん。その方が良さそう。完全に自動化させるの厳しそうだものなぁ。

明日、UXフロー考えるか。と言うわけで寝る。

satomilkysatomilky

おはよう。

今日はまず、他のアプリの動きを見てみるテスト。

Floは、アプリ側で編集加えても、必ず最新のHealthKitデータをとりに行っちゃってるな。
HealthKitデータって、他の連携アプリの変な実装の仕方でゴミみたいなデータが溜まってる時もあるからちょっと信用してもいいんだろうかとは思う。
(というか私のかつてのアプリが実装を下手こいてゴミみたいなデータを溜めてしまっていたのである。)。

Floは、アプリ側で編集加えても、必ず最新のHealthKitデータをとりに行っちゃってるな。

多分、これ。あれだ、必ず最新の値を読み取ってるだけだ。
HealthKitデータ読み取り -> 手入力 -> HealthKitデータ読み取り
をしてるのも、それぞれのタイムスタンプみて、どちらが最新かどうかをチェックしてるだけっぽい。
そしてHealthKitからデータが削除されても何も更新が起きない。

むむむ。これでいいのか??確かに基本的には無駄な確認がなくて良いとは思うけど、ユーザーの意図しないデータ取得になってる気がする。あんまりよくないのでは。。

satomilkysatomilky

うーん。私のデータはタイムスタンプないのよなぁ。。(時差とか考慮すると、色々ズレそうな感じがするので。Stringデータに一旦置き換えてる)だから最新がそもそも判定できない。

やはり、HealthKitの更新処理は

  1. 値がnilの項目だけ、その時点での最新のデータを取得し置き換え
  2. 各項目に再取得のボタンを置き、任意更新させる。
    にしよう。

「入力項目ごとにHealthKit読み込みonly項目を設定してしまって、その設定がONになっている場合は、
むしろアプリから入力インターフェースを消す」みたいな挙動にしようとしたけど、没にする。
ON/OFF切り替えた時には、どこまでの期間のデータをどう処理する?みたいなことを考えなきゃいけない気がして面倒そう。

あとは、BBT入力促進のタイマーがあるから、その時間だけはBBTのインポートはしない。みたいにしなくちゃかもな。もしくは入力インターフェースが表示されてる場合は、インポート処理は発動しない。にすればいいか。そっちの方がシンプルそうだし、ユーザーの行動の実態としても問題なさそう。

よし、実装の方針は定まったので、朝ごはん。

satomilkysatomilky

さて、再開。11時まで。

今回の仕様変更で対応しなきゃいけないところのメモ。
外部データ連携周りは失敗するとマジでやばいので。。

これまでは、インポートはインストール直後しか実行タイミングがなかった。
それで、アプリ入力 -> HealthKit に writeする処理がメインだった。
ので、アプリ上で一旦データを消して再入力。みたいなことをする場合には、
データがもう一つHealthKit側に貯まることのないように、HealthKit側のデータを一旦削除する必要があった。
今まではほとんど一方通行で、オンボーディングが済んでしまえば、基本は全てアプリ入力前提だったから、全ての項目に関して、Dailylogのデータを刷新する感じにしてたけど、これをやったらまずそう。

やはり、現時点での情報ソースが

  • 手入力
  • ヘルスキットからのインポート
  • なし

みたいな判別をさせる必要があるかもしれん。。

が、それだと、マイグレーションが必要になるぅぅ。
んーーやだなー。

けど、いずれは通る道か。(結局、項目増やすしな)

satomilkysatomilky

いや、キーチェーン使ったらあかんやろ。アプリ消した場合、もう一回全部インポートしなきゃいけないだろうなのに、差分しか拾ってこれなくなるやんけ。

参考
https://qiita.com/sachiko-kame/items/261d42c57207e4b7002a

んーーー。じゃあ、しょうがない。SwiftDataに入れるか。

端末ごとのプロパティ系は、UserDefaultsに集約したかったんだけどな。。

satomilkysatomilky

結局実態が、UserDefaultsで、面倒なの変わらなかったポイ

satomilkysatomilky

仕事落ち着いたので戻ってきて実装再開して、
結局、こんなふうにした。

HealthKitServiceの型が構造体じゃなくてclassじゃないと、このanchorに代入できなかったので、HealthKitServiceの型も変えてる

satomilkysatomilky

でも、この方法だと、タイプごとにアンカー発行しちゃう感じかね。

タイプ代入して、アンカー更新しまくると破綻するな。んー。

typeを配列で渡して、一度に複数種類、持ってこれる感じかな?

(めっちゃ便利だけど、だとしたらどうやってるんだろ。すごいな。)

一旦仕事に戻る(案外早く終わりそうだ。よかった。)

satomilkysatomilky

ログ残せてないけど、作業は終了してる。
色々解決はしたので、またまとめてどこかでやったことログ書く。