Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kyash、Widget 作ったってよ

Kyash、Widget 作ったってよ

2022/04/21 (木) に開催されたKyash Tech Talk #3の登壇資料です。

maiyama18

April 21, 2022
Tweet

Other Decks in Technology

Transcript

  1. 2 山口 真生 @maiyama18 • 2019/6 Kyash 入社 as a

    Serverside Engineer • 2020/10 Mobile チームに異動 ◦ iOS 1年半くらい、Android 見習い 自己紹介
  2. 3 • 最近 Kyash の口座残高が見られる Widget をリリース ◦ 便利なのでぜひ試してみてください •

    開発の進め方がイレギュラーだったので紹介したい ◦ 10%ルールで開発 Kyash、Widget 作ったってよ
  3. 4 • 業務時間の10%をプロジェクト外の作業に使える制度 ◦ 詳しくはパネルディスカッションで • 普段の mobile チームでは生産性向上のためのリファクタリングや CI

    改善などをやっている • たまには新しいことやるか...? → Widget は mobile の実装で完結するしよさそう! ◦ iOS / Android で担当を1人ずつつけてプロジェクトの合間にやっていた ▪ 普段 PM がやっているような仕様決めやデザイン・広報の相談なども mobile でやる ◦ Widget みたいなやりたいけど直接数字に結びつくと言いづらいことをできるのはよい 「10%ルール」で開発
  4. 5 • 実際に iOS / Android の Widget を作ってみて大変だったこと ◦

    iOS : @maiyama18 ◦ Android : @dosukoi_android • Widget の開発は今後も継続的にやっていくので、フィードバックいただけるとありがたいです 今日お話しすること
  5. 7 • App Extension。アプリ本体とは別プロセスとして動作 • 表示の更新方法は、アプリから / 定期更新の2種類 ◦ 今回の

    Widget では両方やっている • ホーム画面の View は SwiftUI で書く ◦ View にデータを渡す仕組みはちょっと独特 ◦ View の書き方はアプリと同じなので今日はそれ以外の苦労を話します • 基本的なことに関しては Apple 公式のリソースがわかりやすいです ◦ WidgetKit Document : https://developer.apple.com/documentation/widgetkit/ ◦ Widgets - HIG : https://developer.apple.com/design/human-interface-guidelines/widgets/ ◦ WWDC の Video を Widget で検索 iOS の Widget
  6. 8 Widget に表示するデータの取得 • Widget はアプリとは別プロセスなので、表示するデータを取得する仕組 みも別で作らないといけない • App Groups

    の仕組みを使う ◦ Group を作成してアプリと Widget をそれぞれ入れる ◦ UserDefaults / Keychain を共有できるようになる アプリ Widget Item Item Item Item アプリ / Widget の両方から 参照・更新が可能
  7. 9 App Groups の使い方 • Widget から API リクエストしたくないという観点では A

    にしたい... • ただし、A のやり方だとアプリを開かないと Widget に表示する情報が更新されない • Kyash はアプリを開かずに決済できる(=残高が変化する)ので、アプリを開かないまま決済を何回か すると Widget で表示している残高が古い情報になってしまう。 B でいくことに アプリ Widget 残高 残高取得に成功したら 共有領域に保存 アプリ Widget Token 定期的に API にリクエスト して表示を更新 参照してそのまま表示 Keychain UserDefaults • 具体的にどうやって Widget で表示したいデータ(=残高)を取得する? A. 残高を UserDefaults で共有 B. API Token を Keychain で共有 -> Widget からリクエストして定期更新
  8. 10 API Token の移行 • 移行処理に不具合があるとアプリ本体のログイン状態に影響がある可能性もありめちゃくちゃ不安... ◦ Unit Test を厚めに書く

    ◦ QA チームと相談して移行処理のテストを重点的にやってもらう ◦ 本番テスト:リリース前に TestFlight で配布して社内の有志に使ってもらう • この Token の移行処理が今回の Widget 対応で一番大変だった アプリ Widget Keychain Token • API Token を共有領域に置かないといけない • 当然、現状の Token はアプリの領域に置いてあるため、起動時に 共有領域にいい感じに移動させる処理を書くことに ◦ 処理が複数回走らないようにする ▪ 最悪走っても変なことが起こらないようにする ◦ ログアウト状態 / Token が Expire している状態の考慮
  9. 11 Widget から安全な API のみを使うための依存関係の整理 App UseCase Repository Infra (API

    / Storage) Kyash iOS アプリのアーキテクチャ(超簡略化 ver) Embedded framework Embedded framework Embedded framework
  10. 12 Widget から安全な API のみを使うための依存関係の整理 App UseCase Repository Infra (API

    / Storage) Kyash iOS アプリのアーキテクチャ(超簡略化 ver) Widget • Widget からも API リクエストするのでモデル層はアプリと共有することに • linking against a dylib which is not safe for use in application extensions という warning が出る Embedded framework Embedded framework Embedded framework App Extension
  11. 13 Widget から安全な API のみを使うための依存関係の整理 App UseCase Repository Infra (API

    / Storage) Kyash iOS アプリのアーキテクチャ(超簡略化 ver) Widget Embedded framework Embedded framework Embedded framework App Extension Framework が Extension から安全に使えない! • UIApplication.shared のような Extension から使えない API が 含まれてるかも • Framework 側の Build Settings で、この Framework は Extension からも使える API しか使ってないよというフラグを立ててあげる ◦ Require Only App-Extension-Safe API • ただし、Framework 内で Extension から使うことができない API が 使われているとコンパイルエラーになる
  12. 14 Widget から使えない API を App に移動 App UseCase Repository

    Infra (API / Storage) Kyash iOS アプリのアーキテクチャ(超簡略化 ver) Widget • Framework の古いコード / 依存する SDK に Extension から使えない API が含まれていた • アプリに入っているべきロジックだったので App に移動することで解決 • そこそこ面倒...しかし適切な場所にコードが置かれるようになったということでもあるのでよかった Embedded framework Embedded framework Embedded framework App Extension UIApplication.shared SDK UIApplication.shared
  13. 15 利用者数の計測 • どのくらいのユーザが Widget を使ってくれているのかを追跡できるようにしたい • Widget の表示更新時に Firebase

    Analytics にイベントを送る? ◦ App Extension では FirebaseAnalytics が動かないらしい ◦ https://github.com/firebase/firebase-ios-sdk/issues/2896 • iOS はアプリ foreground 時に追加されている Widget を検知して送ることに
  14. 17 細かいハマりどころ&Tips • 他にも細かい話はあるので Blog などで共有できればと思います ◦ 普通に Run してもデバッガは

    Widget の処理には止まらない。OSLog の Logger で出力した ログを console.app で見るのが効率がよいと感じた ◦ Keychain の値の設定を端末ロック時にも読み取り可にしないとロック中に Widget の自動更 新が走ったときにエラーになる ◦ Widget 側でメモリキャッシュを持つと不整合の元になる • QA / 社内テストでかなりの不具合を検知できた ◦ 普段の機能開発と比べて、後から見ても開発中 / Unit Test では気付きづらいものが多かった ◦ コストはかかったがやってよかった
  15. 18 iOS の Widget を作ってみた感想 • iOS の Widget はモダンで作りやすい

    ◦ Android は事情が違って色々大変という話がこの後あります • 最初に Widget を追加するときは、仕様によってはもろもろの仕組みづくりがちょっと大変かも • 細かいハマりどころがあってリリース前の QA / 社内テストにとても助けられた • 個人の感想:普段から Kyash を使っていて Widget ほしいなと思っていたので自分の生活をよくす る開発ができて楽しかった
  16. 自己紹介 • Naoki Hidaka a.k.a どすこい • Android Engineer /

    Kyash Inc. ◦ 2021年4月入社 Kyash2年生 ◦ Androidは3年目 • Twitter: @dosukoi_android
  17. 26 • AppWidgetProviderのonUpdateでWorkManagerを起動すると無限ループに入ってしま う ◦ https://issuetracker.google.com/issues/115575872?pli=1 ◦ Widgetの定期更新でWorkManagerが起動できない ◦ API叩けなくない?

    無限ループ問題 OS AppWidgetProvider #onUpdate 14時だよ 更新してね WorkManager (oneshot) 起動 onUpdateがキャッチ出来る イベントを投げる
  18. 29 Glance • Jetpack ComposeでWidgetが作れるライブラリ ◦ 2021年のAndroid Dev Summitで発表された ◦

    正しくはComposeをRemoteViewに置き換えてくれる ライブラリ ◦ 後方互換性もあるので過去のOSバージョンでも使える • 今までのRemoteViewは使えるViewに制約があった ◦ ConstraintLayout使えない→古のRelativeLayoutを 使った ◦ GlanceはComposeで書けるのでその辛みがなくなる