Rundevlog

小さい会社のしがないエンジニアのブログ

2025.6.29

CapacitorとAmplifyの相性が悪いことから仕組みを根本から理解すべきと思った話

3年前の話で技術的な問題は解決されているかもしれないので、技術的な共有というより、教訓の共有みたいな話。

Vueでモバイルアプリを開発するための技術選定

Vue.js3でモバイルアプリを開発するというプロジェクトがあった。社内でモバイルアプリに関する知識がそこまでない中でスピーディーな開発をするために、Web開発技術でモバイルアプリを開発しようという目論見からVue.jsとフロントエンドをモバイルアプリにビルドするプラグインCapacitorを使用するという組み合わせで開発は行われた。

https://capacitorjs.jp

更にサーバーサイドの構築を楽にするためにサーバーレスな構成にして、サーバーサイドとフロントエンドの統合を容易にするという考えの元、Amplify UIを採用した。

発生した問題-ログイン状態を維持できない-

しかし、このCapacitorとAmplifyの相性が悪かった。

因みに言うとこのプロジェクトは炎上した。まあ、当時2年目の僕は勿論先輩もサーバレスやモバイルアプリの開発はおろか、Vue.jsも触ったことないのでそれは炎上するという当たり前の話。スピーディーな開発とは裏腹に、バグだらけのプロダクトが、僕らの技術のキャッチアップとともに徐々に品質が上がっていった。

炎上は今回の本題ではない。問題はCapacitorとAmplifyの相性の悪さ。

Amplify UIでは<amplify-authenticator>タグを呼び出してちょこまかすれば、ログイン画面が構築され、ログイン有無を確認してくれる。有効なログイン状態でなければ、Auth.currentSession()を呼び出すことでリフレッシュトークンを使用して再度ログイントークンの取得が可能になる。

この実装によってCognitoの設定さえ変更すればログインから何日間か経っても継続してログイン状態が保たれる。

https://qiita.com/k_hoso/items/19bb0a7fc53834c1a50e

https://zenn.dev/akkie1030/articles/aws-amplify-vue3-auth

ただ、Capacitorでビルドしたモバイルアプリだとこのログイントークンの再取得ができず、1日過ぎると再度ログイン画面が表示されてしまう。AWSのサポートにも実装面で相談しながら進めたが最終的な回答としては「AmplifyをCapacitorはサポートしておりません」。

という訳でこのプロジェクトはこの問題を解決できないまま幕を閉じた。

後から振り返ったり調査してみた結果

この苦い経験から当初は、「技術的な組み合わせはやっぱり王道を行かないと」と考えていた。やっぱりクロスプラットフォームなモバイルであればFlutterやReactNativeを選択して、少なくともAWSが機能を保証してくれることが大事だと思っていた。普及率が高い技術であれば、参考記事なんていっぱいあるので打ち手はもう少し見つかったのではないかと考えた。

そういえば、当時先輩はなぜVueではなくReactを選ばなかったのだろうかというのは、未だに疑問が残る。

でも、数年経ってこの経験を振り返った時にそういった枝葉の問題が本質的な解決ではない気がしてきた。

Amplify UIにおけるログインの仕組み

Amplify UIを使用してログイン画面を実装した際、トークンはそれぞれブラウザ上のLocalStorageに保存される。LocalStorage内のログイントークンやリフレッシュトークンを使用して認証情報を管理、更新している。

CapacitorとLocalStorage

それではCapacitorで開発するモバイルアプリはどうなのか。

CapacitorはモバイルのOSに備えられているWebViewという仕組みを使用してフロントエンドのソースコードをOSのWebブラウザエンジンで表示してモバイルアプリとして動作できるようにしている。つまり、モバイル上で動作しているように見せて、モバイル上のWebブラウザ上で動作している仕組みである。

なので、CapacitorでビルドしたモバイルアプリはOS標準のブラウザのLocalStorageを使用していることになる。

という訳で諸々調べていると、どうやらCapacitorで開発したアプリはLocalStorageは使用できないということがCapacitorの公式ドキュメントに明記されている。

なぜLocalStorageやIndexedDBを使うことができないのでしょうか?

Capacitorアプリは主にWebビューまたはブラウザで実行されるため、Capacitor開発者はストレージ用のWeb APIを使用できます。ただし、これらのAPIには留意すべき大きな注意点があります。

ローカルストレージは、ユーザーIDのような少量の一時的なデータに使用できますが、「transient_」と見なされる必要があります。つまり、アプリはデータが最終的に失われることを予期する必要があるのです。これは、デバイスの空き容量が少なくなると、OS が Web View からローカル ストレージを再要求するためです。同じことが少なくとも iOS の IndexedDB にも言えます(Android では、IndexedDB を persisted としてマークするために persisted storage API が利用可能です)。ブラウザで データストレージの退避ポリシー の詳細を読む。

https://capacitorjs.jp/docs/guides/storage

なんか日本語だとイマイチなので、原文も。

Why can’t I just use LocalStorage or IndexedDB?

Since Capacitor apps run primarily in a web view or browser, Web APIs for storage are available to Capacitor developers. However, there are some major caveats to keep in mind with these APIs.

Local Storage can be used for small amounts of temporary data, such as a user id, but must be considered transient, meaning your app needs to expect that the data will be lost eventually. This is because the OS will reclaim local storage from Web Views if a device is running low on space. The same can be said for IndexedDB at least on iOS (on Android, the persisted storage API is available to mark IndexedDB as persisted). Read more on data storage eviction policies in the browser.

https://capacitorjs.com/docs/guides/storage

題名に書いてあるようにLocalStorageは使用できないらしい。理由を読むと使えないというより不測に削除される可能性があるからということ。

また、別のコミュニティサイトでもCapacitorはLocalStorageを使用できないのでSQLiteを使用しているとの投稿がある。

https://forum.ionicframework.com/t/cordova-capacitor-localstorage-missing/187519/8

とまあ、総じてCapacitorとAmplify UIの相性の悪さは正体は、CapacitorとLocalStorageの相性の悪さの可能性が高いようだ。

考えられる打ち手(後の祭りだけど)

そう考えるといろいろな打ち手が考えられる。

一つ目は上述の通り、その技術の組み合わせを変更すること。

二つ目はログイン機能の一部もしくは全部をAmplify UIを使用せずに自作すること。

例えば、Amplifyと言えども、内部ではCognitoを使用しているので、リフレッシュトークンはSQLiteに保存して、ログイントークンの更新の際はCognitoSDKを使用して、実装するというのはできそうだ。ログイン機能が働いていることを考えているので、ログイントークンの一次的な保存はできているので、取得したトークンは、LocalStorageに保存すればいい。LocalStorageを使用しないようなログイン処理を自作するというのも一つ。

https://qiita.com/fkooo/items/660cab0090a80861155b

まあ、全ては後の祭りなんだけど、もう少しだけ。どの打ち手を打つかはフェーズによって異なる。開発前の技術検証の時点でこの問題を知れたなら、選定技術を変える選択を取ることができる。開発が進んでしまい、後戻りできない(事前に調べとけという声が聞こえてくる)Amplifyを使用しないでSDKで実装する手を打って解決するしかない。

この件は、Vue.jsやAmplifyの使い方みたいな枝葉の知識だけでは解決できない問題であった。ログイン機能の問題を分解してみると、フロントエンド、Webブラウザの仕組み、Amplifyの仕組みを理解していれば、もう少し何かできたのではないかと思う。

個人的にはより土台となる知識を大切にしたいなと思えた一件であった。