「電卓メモ」開発秘話 — 深夜のバグ調査とPlay Console迷宮の記録

先日、Androidアプリ「電卓メモ」の技術的な実装解説記事を公開しました。今回はその裏側で実際に起きた、地味だけれど印象に残っている開発エピソードをいくつか振り返ってみます。きれいにまとまった技術記事だけでは伝わらない、個人開発の「詰まった瞬間」の記録です。

行と行の間に、なぜか空行が挟まる

ストア掲載用にきれいなスクリーンショットを撮ろうとした時のことです。サンプルデータを表示させると、なぜか各行の間に空白行が1つずつ挟まっていることに気づきました。見た目の問題かと思い最初は軽く見ていたのですが、調べれば調べるほど根が深い不具合でした。

adb shell経由のcatでDBファイルを取得しようとすると中身が壊れる、という別の落とし穴にもハマりつつ、exec-outで直接バイナリを吸い出してsqlite3で覗いてみると、同じ並び順の値を持つ行が重複して挿入されていることが分かりました。原因は、初期サンプルデータを1行ずつ順番にINSERTしている最中に、Roomの監視用Flowが投入途中の中間状態で何度も再発火し、「末尾に常に空行を確保する」という別のロジックがその未完成な状態に反応して、勝手に空行を足してしまっていたことでした。

この手の「複数回に分けてDBに書き込む処理の途中経過が、監視側にそのまま漏れてしまう」というパターンは、行の分割・結合など他の操作でも起こり得ることに気づき、まとめてトランザクションで囲むことで解決しました。1つの表示崩れをきっかけに、実は複数箇所に潜んでいた同種のバグを一網打尽にできた回でした。

「消したはずのバナー」が消えてくれない

公開直前になって、「しばらくバックアップしていません」というリマインドバナーが、起動直後に一瞬だけ表示されてすぐ消える、という報告がありました。閉じるボタンを押した覚えもないのに、です。

最初は「設定の読み込みが終わる前は判定を保留する」ガードを入れて解決したつもりでした。ところが同じような現象が、今度は別の場所(メモ0件時の案内文、合計金額バッジ)でも見つかり、「これは1箇所ずつ直す話ではなく、構造的な問題では」と疑い始めました。

実機のlogcatに直接ログを仕込んで状態遷移を追ったところ、「設定値」と「設定の読み込みが完了したかどうかのフラグ」を、別々のStateFlowとしてComposeから購読していたことが原因だと分かりました。この2つは本来、常にセットで正しい状態のはずなのに、Compose側の独立した2つの購読が同時に更新されるとは限らず、「読み込み完了フラグだけが先に更新され、肝心の値はまだ古いまま」という一瞬のちぐはぐな状態が生まれていたのです。

値とフラグを1つのStateFlowにまとめて、常に同時に更新されるようにしたところ、この種のちらつきはぴたりと止まりました。「別々に管理していた2つの状態は、実は分けてはいけなかった」という、地味だけれど記憶に残る学びでした。

スクリーンショットを自分で壊した日

ストア掲載用のスクリーンショットにキャッチコピーを入れたいと思い、画像の上にキャプション帯を重ねて合成しました。ところがその合成済み画像を、バックアップも取らずに元のスクリーンショットへそのまま上書き保存してしまい、無地のオリジナルを完全に失ってしまいました。

幸い、作業用の一時フォルダを漁ってみると、過去のセッションで生成した中間ファイルがいくつか残っていました。ファイルサイズをバイト単位で突き合わせてみたところ、5枚中3枚は完全に一致するものが見つかり、事なきを得ました。残る2枚は、実機に残っていたサンプルデータのタブを使って撮り直すことになったのですが、その端末には自分の実際のゲームスコアの記録(友人の名前入り)も残っていたため、「絶対に触ってはいけないデータ」を横目に見ながらの慎重な作業になりました。

この一件以来、「画像を加工する前には、まず無加工のオリジナルを別フォルダに退避してから作業する」というルールを徹底するようになりました。当たり前のことですが、痛い目を見るまで徹底できていなかった典型例です。

キャプション帯、比率オーバーで差し戻し

復旧した画像に、今度は「画像の上に重ねるのではなく、上に継ぎ足す形にしてほしい」というリクエストをもらい、キャンバス自体を縦に拡張する形で作り直しました。見た目は良くなったのですが、いざPlay Consoleにアップロードすると「アスペクト比が16:9〜9:16の範囲内である必要があります」というエラーで弾かれてしまいました。

継ぎ足した分だけ画像が縦長になりすぎていたのが原因でした。実機の画面そのものの比率(1080×2340)はぎりぎり許容範囲内だったのに、キャプション帯を継ぎ足した分だけ範囲外にはみ出してしまっていたのです。結局、キャンバスサイズは変えずに「実際の画面の中で、宣伝上重要でない部分(ステータスバーやタブ行)にキャプションを重ねる」という、最初に一度却下されたはずのアプローチに戻ることになりました。デザインの好みと、ストアの技術的な制約の両方を満たす落としどころを探る、行ったり来たりの調整でした。

Play Consoleの「予期しないエラー」の正体

広告非表示の買い切りアイテムをPlay Consoleに登録しようとすると、「1回限りのアイテムを追加するには、請求権限をAPKに追加する必要があります」という案内が出ました。コード側はすでに課金ライブラリを組み込み済みで、ビルドしたAPKにもきちんと権限が含まれていることを確認していたので、最初は意味が分かりませんでした。

よく考えてみると、Play Console側はローカルで作ったビルドファイルの中身までは見ておらず、実際にストアへアップロードした実績のあるビルドを見て判定している、ということに思い至りました。つまり「コードは正しいのに、まだ一度もアップロードしていない」ことが原因だったのです。オープンテストトラックにAABをアップロードしたところ、あっさりブロックが解除されました。

その後も商品登録の保存時に、コード違いの汎用エラー(77480CEE、6CE45F73…)が何度も出ましたが、これも結局「実際にアップロード・公開submitまで完了していなかった」ことが根っこの原因でした。加えて、商品ID欄と購入オプションID欄とで使える文字種のルール(アンダースコア可否・ハイフン可否)が逆だったことにも振り回され、一度提案した内容を自分で訂正する場面もありました。Play Console特有の「見えている画面の情報だけでは原因が分からない」壁に、何度もぶつかった開発でした。

公開前日に届いた最終通告

すでに主要な作業が一段落したと思っていた矢先、Play Consoleから「対応期限:8月31日」というメッセージが届きました。ターゲットAPIレベルの引き上げと、課金ライブラリのバージョンアップを、明日までに終わらせないとアップデートが否認されるという通知です。

幸い、この2点はすでにコード側で対応済みだったのですが、肝心の「対応済みビルドを実際に公開する」ところまでは終わっていませんでした。急いでビルドし直し、署名を検証し、テストを一通り流し直したところ——ここで思わぬ副産物がありました。テストを全部流したことで、今回のアップデートとは無関係な、以前から存在していた計算バグ(半角の掛け算記号を数式として認識できていない)が偶然見つかったのです。締め切りに追われて焦っていたタイミングで、無関係な既存バグまで拾ってしまうというのは、個人開発ならではの巡り合わせだったかもしれません。

振り返って

今回まとめたエピソードに共通しているのは、どれも「表面的な症状」と「本当の原因」がずれていたことです。空行の混入は見た目の問題に見えて実は競合状態、バナーのちらつきは表示ロジックの問題に見えて実は状態管理の設計、Play Consoleのエラーはコードの不備に見えて実は「まだ公開していない」だけ——という具合です。一つひとつは地味な調査の積み重ねですが、個人開発では立ち止まって代わりに調べてくれる人がいない分、こうした「なぜ?」を最後まで追いかける経験そのものが、一番の財産になった気がします。











この記事も含めて、自分はAIに指示しただけなんだけどね・・。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA