.NET MAUI で作成したアプリをストア更新するとき、「設定値(Preferences)やトークン(SecureStorage)が消えるのでは?」と不安になります。結論としては、同じアプリとして更新される限り通常は消えません。ですが、アプリIDや署名の変更、OSの操作、端末移行などで“消えたように見える”ケースがあります。本記事では Android / iOS それぞれでの保持条件、消えるパターン、そして公開前に実機で確かめる具体手順を整理します。
結論:アプリが同一として扱われる更新なら、Preferences / SecureStorage は基本的に残る
まず押さえるべきポイントはシンプルです。Android / iOS ともに、OS が「同じアプリのアップデート」として認識して上書き更新する限り、アプリのサンドボックス(アプリ専用領域)は維持されるため、Preferences と SecureStorage のデータは通常保持されます。
逆に言うと、OS から別アプリ扱いになったり、ユーザー操作や端末都合でアプリデータが削除されたりすると、保存値は引き継がれません。ここを具体例と一緒に分解していきます。
まず整理:Preferences と SecureStorage は「どこに」「どう」保存されるのか
.NET MAUI の Preferences と SecureStorage は、見た目は同じ「キー・バリュー保存」でも、目的と保存先が異なります。更新時の挙動を理解するために、内部的に何が起きているかをざっくり把握しておくと安心です。
| API | 用途 | 保存先のイメージ | 特徴 | 更新で消える? |
|---|---|---|---|---|
| Preferences | 設定値・フラグ・UI状態など | アプリの設定領域(Android は SharedPreferences 相当、iOS は UserDefaults 相当) | 軽量・高速。暗号化されない前提なので秘密情報には不向き | 同一アプリの更新なら通常は消えない |
| SecureStorage | アクセストークン・パスワード相当・秘密鍵など | OS のセキュア領域(Android は Keystore を利用、iOS は Keychain を利用) | 端末セキュリティと密接。環境変化で読めなくなることがある | 同一アプリの更新なら通常は消えない(ただし例外あり) |
「更新で消えるか?」は、実は“データが物理的に消える”だけでなく、“アプリから読めなくなる”ケースも含めて考える必要があります。特に SecureStorage は、端末の暗号鍵や認証設定の影響で、更新とは無関係に読み出しが失敗することがあります。
基本ルール:アプリID(パッケージ名 / Bundle Identifier)と署名が同じなら消えにくい
更新後もデータを保持したいなら、OS が「同じアプリ」と認識するための識別子と署名を維持することが最重要です。
Android で重要なもの
- パッケージ名(.NET MAUI の
ApplicationId/ マニフェストの package) - 署名証明書(keystore の鍵。Play App Signing を含む)
iOS で重要なもの
- Bundle Identifier(.NET MAUI の
ApplicationId/ Info.plist の識別子) - 署名のチーム(Team ID)と権限(Entitlements)(Keychain のアクセス範囲に関わる)
この「同一性」が保たれていれば、ストアからの更新でも、社内配布の更新でも、原則として Preferences / SecureStorage は維持されます。
「消える」ではなく「見えなくなる」もある:典型パターン早見表
実務では「更新したら消えた!」と言われても、原因が更新そのものではないことが多いです。まずは起きやすい状況を一覧で把握しておきましょう。
| 状況 | Preferences | SecureStorage | よくある原因/補足 |
|---|---|---|---|
| 同じアプリとしてストア更新 | 残る | 残る(基本) | 通常は維持。消えた場合は別要因を疑う |
| アプリをアンインストールしてから再インストール | 消える | 消える/読めないことがある | Android はアプリデータが消去。iOS は Keychain が残ることもあるが保証しない運用が安全 |
| 設定から「ストレージを消去」「データを削除」 | 消える | 消える/読めないことがある | Android のユーザー操作。サポート問い合わせで多い |
| アプリID(パッケージ名 / Bundle Identifier)を変更 | 引き継がれない | 引き継がれない | OS から別アプリ扱い。保存先も別になる |
| 署名鍵(Android の keystore)を変更 | 更新できない/引き継がれない | 更新できない/引き継がれない | 通常は「署名が違うため更新不可」になる。アンインストール→再インストールすると当然データは消える |
| 端末移行・バックアップ復元 | 復元される場合あり | 復元されない/復号できない場合あり | Preferences は復元されても、SecureStorage が読めず再ログインになる、が典型 |
| 端末のロック設定変更/生体認証設定変更 | 影響なし | 読めなくなる場合あり | 暗号鍵が無効化される、または OS がセキュアデータへのアクセスを制限 |
この表だけでも、「更新で消えた」と見える現象の多くが更新以外の要因で起きることがわかります。次の章から、Android / iOS それぞれの落とし穴を具体的に掘り下げます。
Android:Preferences / SecureStorage が消えたり読めなくなったりする主な原因
パッケージ名(ApplicationId)の変更は「別アプリ」扱い
Android はパッケージ名でアプリを識別します。更新後もデータを保持したいなら、公開済みと同じパッケージ名を維持してください。
.NET MAUI では csproj の <ApplicationId> を環境ごとに変えてしまうと、同じ端末上でも別アプリとしてインストールされます。たとえば「デバッグ用に suffix を付けた」などはよくあるパターンです。
<PropertyGroup>
<ApplicationId>com.example.myapp</ApplicationId>
</PropertyGroup>
デバッグ用と本番用を共存させたい意図で ApplicationId を変えるのは有効ですが、その場合は本番データを読めないのが正しい挙動です。「更新したのに消えた」と誤認しやすいので、テスト環境の設計段階で整理しておきましょう。
署名鍵が違うと「更新」できず、インストール自体が失敗する
Android は更新時に署名一致を強く要求します。公開済みアプリと異なる keystore で署名した APK を上書きしようとすると、多くの場合は更新不可(署名不一致)になります。
ここで重要なのは、署名が違うと “更新してデータが消える” のではなく、“更新できない”という点です。もしユーザーやテスターが旧アプリをアンインストールしてから新しい APK を入れ直した場合、結果としてデータは消えますが、原因は「再インストール」です。
Play App Signing を使っている場合の検証の注意点
Google Play の Play App Signing を有効にしている場合、ストアから配信されるアプリは、手元の「アップロード鍵」ではなく Play 側の「アプリ署名鍵」で署名されます。そのため、端末に入っているストア版に対して、ローカルで署名した APK をそのまま上書きしようとしても署名不一致で失敗することがあります。
このケースでは、次のような方法で「更新として扱われるか」「データが残るか」を確認するのが現実的です。
- Play Console の内部テスト/クローズドテストに更新版を上げ、ストア経由でアップデートする
- Play Console の内部アプリ共有(Internal App Sharing)で配布し、同一アプリとして更新されるか確かめる
「ストア版 → 手元ビルドで上書き」という検証は、署名の仕組みによっては成立しない点に注意してください。
ユーザー操作でデータが消える:ストレージ消去・最適化アプリ
Android は設定画面からアプリの「ストレージを消去」「データを削除」ができます。これが実行されると Preferences 相当のデータは削除され、アプリは初回起動状態に戻ります。サポートやQAで「更新したらログインが消えた」と報告される場合、実際はこの操作が原因のことが少なくありません。
また、端末メーカー独自の最適化機能や“クリーナー”系アプリが、まれにアプリデータ削除に近いことをする場合があります。全端末で再現しない不具合として上がってきたら、端末側の設定や常駐アプリの影響も疑ってください。
端末移行・バックアップ復元で SecureStorage が読めなくなることがある
Preferences はバックアップ対象になっている環境だと、端末移行時に値が復元される場合があります。一方、SecureStorage は OS のセキュア領域(暗号鍵)に依存するため、復元されたデータがあっても復号できず、読み出し時に例外が発生したり、null になったりすることがあります。
運用上は、SecureStorage に入れているものは「永続保証の保管庫」ではなく、“安全なキャッシュ”として扱うのが現実的です。読めなければ再ログイン・再発行で復旧できる設計にしておくと、端末移行やOS更新での事故が減ります。
iOS:Preferences / SecureStorage が消えたり読めなくなったりする主な原因
Bundle Identifier を変えると完全に別アプリ扱い
iOS は Bundle Identifier でアプリを識別します。これが変わると別アプリとして扱われ、UserDefaults(Preferences 相当)も Keychain(SecureStorage 相当)も別領域になります。
MAUI でビルド構成ごとに識別子を変えている場合、本番版と検証版でデータ共有できないのは仕様です。特に「TestFlight は本番と同じ」「社内配布は別ID」など、配布経路ごとに識別子が混在すると、検証結果の解釈を誤りやすいので注意してください。
Keychain は更新に強いが、署名チームや権限が変わると読めなくなることがある
SecureStorage は iOS では Keychain を利用します。Keychain は一般に更新に強く、通常のアップデートでは保持されます。ただし、Keychain のアクセス制御はアプリの署名チーム(Team ID)や Entitlementsに影響を受けます。
たとえば次のような変更があると、保存した値が残っていてもアプリから読めず、結果として「消えた」ように見えることがあります。
- 開発者アカウントの変更やアプリ移管などで、署名の Team が変わった
- Keychain Sharing / App Groups など、Keychain のアクセスグループ構成を変更した
- ビルド設定の違いで Entitlements が変わった(本番と検証で権限が揃っていない)
ストア更新では通常ここは揃いますが、社内配布や複数チームでの運用をしていると事故が起きます。「ビルド方法が違うと SecureStorage だけ読めない」症状は、真っ先に Entitlements を疑うのが定石です。
iOS の「Appを取り除く」と「Appを削除」の違いも押さえる
iOS にはストレージ節約のために「Appを取り除く(Offload App)」があります。これはアプリ本体を削除しつつ、書類とデータを保持します。したがって、再インストール後も Preferences 相当が残るケースが多いです。
一方で「Appを削除(Delete App)」はアプリとデータを削除します。これをやると Preferences は消えます。Keychain は挙動が環境で異なることがあるため、運用としては“消えるもの”として設計し、再ログインで復旧できるようにしておくのが安全です。
端末の初期化・バックアップ復元・iCloud 設定で挙動が変わる
iOS でも、端末の初期化やバックアップ復元、iCloud Keychain の有無などで、Keychain の取り扱いが変わることがあります。一般ユーザーの行動範囲を考えると、「SecureStorage が読めない=認証情報が無効になった」と捉えて、再発行フローを用意するのが堅牢です。
更新時に“本当に消えた”のかを切り分けるチェックポイント
問い合わせやQAで迷いやすいのが「データが消えたのか」「読めなくなっただけなのか」「キー名が変わって別物を見ているのか」です。切り分けは次の順番で行うとスムーズです。
- アプリIDが同一か:Android はパッケージ名、iOS は Bundle Identifier を確認
- 更新としてインストールされたか:端末のインストール画面で「更新」と表示されるか、または既存アプリが上書きされたか
- 保存キー名が同じか:コード変更で key が変わっていないか、スコープ(ユーザーID付きキーなど)が変わっていないか
- SecureStorage の例外:読み出しで例外が出ていないか(例外は“消えた”ではなく“読めない”)
- ユーザー操作:ストレージ消去、端末移行、アプリ削除/再インストールが行われていないか
特に SecureStorage は、失敗時に例外が発生することがあります。ログを残しておくと、現場での切り分けが圧倒的に楽になります。
事前に自分で確認する方法:公開前に“更新シナリオ”を実機で再現する
「通常は消えない」と言われても、プロジェクトの設定や配布方法によっては例外が起きます。ストア公開前に、必ず実機で更新シナリオのテストをしておくのがおすすめです。
確認のゴール
- 端末が“更新”として受け付けること(別アプリとして入っていないこと)
- 更新前に保存した Preferences / SecureStorage を、更新後に正しく読み出せること
- SecureStorage が読めない場合に、アプリが落ちずに復旧動作できること
Android の確認手順(代表例)
- 現行版(配布中の版)を端末にインストールする
- アプリを起動し、Preferences と SecureStorage にテスト値を保存する(後述のテスト画面を使うと便利)
- 更新版を用意する(パッケージ名を変えない、かつ端末の既存アプリと同じ署名で入る経路を選ぶ)
- 端末に入れて上書き更新する(ストア更新、テストトラック更新、または署名が揃う場合は手動インストール)
- 更新後に同じ画面で値を読み出し、残っているか・例外が出ないかを確認する
iOS の確認手順(代表例)
- 現行版を端末にインストールする(TestFlight を使うと更新テストがしやすい)
- Preferences / SecureStorage にテスト値を保存する
- 同じ Bundle Identifier でビルド番号を上げた更新版を配布し、端末でアップデートする
- 更新後に値を読み出して確認する
iOS のシミュレータは Keychain 周りの挙動が実機と異なることがあるため、SecureStorage を検証するなら実機が確実です。
検証用のミニ実装:更新前後で値が残るかを一発で確認する
テストのたびにログイン操作をするのは手間なので、検証ビルドにだけ「ストレージ確認画面」を入れておくと便利です。下記は最小限の例です(画面UIは任意)。
using Microsoft.Maui.Storage;
public static class StorageProbe
{
private const string PrefKey = "probe_pref";
private const string SecureKey = "probe_secure";
public static void Save(string value)
{
Preferences.Set(PrefKey, value);
}
public static string LoadPreference()
{
return Preferences.Get(PrefKey, "(not set)");
}
public static async Task SaveSecureAsync(string value)
{
await SecureStorage.SetAsync(SecureKey, value);
}
public static async Task<string> LoadSecureAsync()
{
try
{
return await SecureStorage.GetAsync(SecureKey) ?? "(not set)";
}
catch (Exception ex)
{
// ここでログに ex を出しておくと、原因切り分けが楽になります
return $"(error: {ex.GetType().Name})";
}
}
}
更新前に Save と SaveSecureAsync を呼んで値を入れ、更新後に LoadPreference と LoadSecureAsync を実行して同じ値が出るかを確認します。SecureStorage の読み出し失敗が起きる端末もあるため、必ず try/catch を入れて“落ちない”ことも確認してください。
「消えない」設計だけでは不十分:更新・移行・例外に強い実装の考え方
Preferences は“設定”、SecureStorage は“秘密情報のキャッシュ”として割り切る
Preferences は便利ですが暗号化を前提にしていません。ログイン状態を示すフラグや、テーマ設定、初回チュートリアル完了フラグなど「漏れても致命傷にならない」情報に使うのが基本です。
SecureStorage は秘密情報の保管に向きますが、端末移行やセキュリティ設定変更で読めなくなる可能性があります。したがって、SecureStorage に入れた値だけで業務が止まらないように、再ログイン・再認可・トークン再取得の導線を必ず用意してください。
“キー名の変更”はユーザーから見るとデータ消失と同じ
更新後に「消えた」と言われる原因として、意外に多いのが保存キーの変更です。定数名の整理、プレフィックスの変更、ユーザーIDの付け方変更などで、過去の値を参照しなくなると、保存値が残っていてもアプリからは見えません。
キー名は API ではなく永続データのスキーマだと捉え、変更するなら移行コードを入れる、旧キーも読める期間を設けるなど、データ移行として扱うのが安全です。
SecureStorage 読み出し失敗時の定番対応
SecureStorage が読めないときは、アプリを落とすよりも、次のように“回復可能な状態”に戻すのが一般的です。
- 例外を捕捉してログを記録する
- 必要なら SecureStorage の該当キーを削除し、再ログイン/再認可を促す
- 「セキュア情報が無効になりました。再ログインしてください」などのユーザー向けメッセージを出す
これにより、端末移行やOSの都合で暗号鍵が変わった場合でも、アプリが致命的に壊れずに運用できます。
リリース前チェックリスト:更新でデータを維持するために確認すべき項目
最後に、実務での事故を減らすためのチェックリストをまとめます。リリース前にここを押さえておくと、Preferences / SecureStorage のトラブルが激減します。
| チェック項目 | 確認ポイント | よくある落とし穴 |
|---|---|---|
| アプリID(識別子) | Android:パッケージ名 / iOS:Bundle Identifier が公開版と同じ | Debug/Release で別ID、マルチブランド対応でID変更 |
| 署名 | Android:更新対象と同じ署名で配布される経路か | Play App Signing で手元上書きできない、keystore 紛失 |
| バージョン/ビルド番号 | 更新として配布できるように増加している | 番号が増えておらず配布できない(データ保持以前の問題) |
| キー名互換 | Preferences / SecureStorage のキー名を変更していない | リファクタでキー文字列変更、ユーザーID付け方変更 |
| 例外ハンドリング | SecureStorage が読めない端末でも落ちずに復旧できる | 未処理例外でクラッシュ、無限ループで再保存 |
| 実機更新テスト | 現行版→更新版の上書きで値が残ることを確認 | シミュレータだけで判断、別IDのビルドで検証してしまう |
まとめ:更新で消えない前提+消えても復旧できる前提が最強
Preferences / SecureStorage は、アプリIDと署名が維持される通常のストア更新であれば基本的に保持されます。一方で、別アプリ扱いになる変更、ユーザーによるデータ削除、端末移行やセキュリティ設定変更などで、値が消えたり読めなくなったりします。
本番で困らないためには、「消えないようにする設定管理」と同時に、「万一読めなくても復旧できる設計(再ログイン・再発行、例外ハンドリング)」の両輪が重要です。公開前に実機で更新テストを行い、Preferences / SecureStorage が期待どおりに残ることを必ず確認しておきましょう。

コメント