iOS では問題なくきれいに表示されているアプリアイコンが、Android の通知バーだけ「白い四角」や「ぼやけたシルエット」になってしまう。Rork や Expo で作ったアプリを実機に入れた瞬間、最初につまずきやすいのがこの問題です。
私自身、複数のアプリを Rork で公開してきた中で、この通知アイコン問題には何度も時間を取られました。「画像も置いた、設定も書いた、なのに白い四角のまま」という状態は、原因が複数の層にまたがっているために起きています。そもそもなぜ Android では白い四角になるのか、どんなアイコンを用意すればよいのか、そして「直したつもりなのに反映されない」ときに見直すべきポイントまでを実例とともに整理しました。
なぜ Android の通知アイコンは白い四角になるのか
Android 5.0(Lollipop)以降、ステータスバーや通知バーに表示される small icon は、Google のデザインガイドラインで「白一色のシルエット+透過背景」と決められています。フルカラーのアプリアイコンをそのまま渡すと、システムが「アルファチャネル以外をすべて白で塗りつぶす」処理を行うため、結果として真っ白な塗りつぶしの四角だけが残るのです。
つまり、これは Rork や Expo のバグではなく、Android OS の仕様です。iOS の通知はカラーアイコンをそのまま使えるため、iOS だけでテストしているとこの問題に気づけません。Rork のプレビューや TestFlight ばかり見ていると、Android の実機で初めて気づくケースが多いはずです。
用意すべきアイコンの正しい仕様
通知用 small icon に必要な要件は次の通りです。
- 完全に透過された PNG(背景は alpha = 0)
- 形状部分は白(#FFFFFF)一色で塗る(半透明・グレーは不可)
- 最低 96×96 px、推奨 256×256 px(密度別に作る場合は mdpi 24px、xxxhdpi 96px が目安)
- 余白を上下左右に 12〜15% ほど確保(システム側でクリップされるため、ぎりぎりまで描かない)
ここで一番重要なのは「色の情報を全部捨てる」ということです。Photoshop や Figma でアプリアイコンの色付き版から作る場合、レイヤーをそのまま白に塗り直すのではなく、シルエットを抽出した上で塗り潰し直す方が安全です。グラデーションや影を残すと、アンチエイリアスのグレー部分が透明扱いされてしまい、輪郭がボヤけます。
Expo(Rork のベース)での設定方法
Rork で生成されるアプリは Expo SDK ベースです。app.json または app.config.js の Android セクションに、通知アイコンを明示的に指定します。
{
"expo": {
"android": {
"package": "com.example.myapp",
"icon": "./assets/icon.png",
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"notification": {
"icon": "./assets/notification-icon.png",
"color": "#FF6B6B",
"androidMode": "default"
}
}
}ポイントは、expo.android.icon と expo.notification.icon は別物だということです。前者はランチャーやアプリ一覧に出るアプリアイコン、後者がステータスバーに表示される small icon です。両方を同じカラフルなアイコンで指定してしまっていることが、「設定したのに直らない」ケースの代表的な原因です。
expo.notification.color は、通知背景に乗る色(Android 5.0 以降のアクセントカラー)です。アプリのブランドカラーを指定すると、白いシルエットの背景がその色で塗られます。指定しないと OS が灰色を使うため、地味な見た目になります。
expo-notifications ライブラリを使ってローカル通知やプッシュ通知を送る場合も、上記の expo.notification.icon がそのまま反映されます。ライブラリ側で個別にアイコンを指定する必要はありません。
「ちゃんと設定したのに反映されない」ときに疑う5つのポイント
設定を直したつもりでも反映されないことはよくあります。原因はだいたい以下のどれかです。
1. ビルドキャッシュが残っている
app.json を変更しただけでは、既存の APK / AAB に埋め込まれたリソースは更新されません。Expo の場合は EAS Build を新しく走らせ、端末側のアプリも一度アンインストールしてから入れ直してください。OTA Update では native リソースは更新されません。
2. PNG のアルファチャネルが正しく抜けていない
「透明背景にしたつもり」が、実は白背景の PNG だったというケースは非常に多いです。Photoshop で「背景レイヤー」のまま保存した、PNG-8 で書き出した、JPEG を PNG にリネームしただけ、などが原因になります。Preview.app(Mac)や pngcheck コマンドで tRNS チャンクの有無を確認するのが確実です。
# pngcheck で透明度情報を確認
pngcheck -v assets/notification-icon.png
# 出力に "tRNS" や "alpha channel" が含まれていれば OK3. アイコン画像のパスが間違っている
./assets/notification-icon.png のように相対パスで書きますが、Rork のプロジェクト構成によっては assets フォルダがプロジェクトルート直下にないことがあります。app.json のあるディレクトリからの相対パスで解決される点に注意してください。ビルドログに Icon not found の警告が出ていないか確認します。
4. Android のシステム側でアイコンキャッシュが残っている
エミュレータや実機で同じアプリを何度もインストールしていると、システム側に古いリソースがキャッシュされていることがあります。アンインストール → 再起動 → インストールの順で試すと解消します。私は新しいアイコンをテストするときは、必ず端末の再起動を挟むようにしています。
5. プッシュ通知ペイロード側で別のアイコンを指定している
FCM のペイロードに notification.icon フィールドを直接書いていると、app.json の設定より優先されます。Cloudflare Workers や Firebase Functions から送る場合は、サーバー側のコードで余計なアイコン指定をしていないか確認してください。基本は app.json 側に集約するのが管理しやすくなります。
透過アイコンを Figma や Photoshop で作るときのコツ
アイコンを毎回手作業で作るのは面倒です。私はテンプレートを 1 つ用意して使い回しています。
Figma の場合は 256×256 px のフレームを作り、シェイプをすべて白の単色で配置します。グラデーションや影は使わず、ベタ塗りのシルエットだけにします。書き出し時に「Background」を Transparent にして PNG で書き出せば、そのまま使える透明白アイコンが得られます。
Photoshop なら、元のアプリアイコンのレイヤーから「選択範囲を読み込む」→「白で塗りつぶし」→「背景レイヤーを削除」の流れで、シルエット版を作れます。「ファイル → 書き出し → クイック書き出し(PNG)」で書き出す際、必ず「透明部分を保持」にチェックが入っているか確認してください。
複雑なロゴの場合は、シルエットだけでは識別性が落ちることがあります。その場合は 1〜2 個の特徴的な要素だけに絞ってデザインし直すのが現実的です。文字を入れる場合も、細い線は通知バーの小さなサイズで潰れて見えなくなるため、太めのウェイトを選んでください。
関連して、アプリアイコン全般のキャッシュ問題でつまずいたときは、Rork で作ったアプリのアイコンを更新したのに反映されない問題の解決法 も合わせて確認すると役立ちます。プッシュ通知そのものが届かない場合は、Rork のプッシュ通知が届かないときの原因切り分けガイド を先に見ると効率的です。OneSignal を使っている場合の総合的な実装手順は、Rork × OneSignal でプッシュ通知を実装する完全ガイド にまとめてあります。
実機で通知を確認する手順
開発中は、実際に通知を発火させて表示を確認するのが一番確実です。Expo Go ではなく、EAS Build で生成した dev client や preview build を Android 実機にインストールしてテストしてください。Expo Go 経由のテストでは、Expo Go 側のアイコンが表示されてしまうため、自分のアプリのアイコンが正しく出るかを確認できません。
ローカル通知を一発で発火させるテストコードは次のようになります。
import * as Notifications from 'expo-notifications';
// 5秒後にローカル通知を表示してアイコンを確認するテスト用関数
export async function fireTestNotification() {
await Notifications.scheduleNotificationAsync({
content: {
title: 'アイコン確認テスト',
body: 'ステータスバーのアイコンが白いシルエットになっていれば成功です',
},
trigger: { seconds: 5 },
});
}このコードを開発中の画面のボタンに紐付けて、5秒以内にホーム画面に戻ってステータスバーを確認します。期待する出力は「白いシルエットのアイコン+通知タイトル+本文」がステータスバーと通知ドロワーの両方に表示されることです。もし白い四角が出るなら、PNG のアルファチャネルか app.json のパス指定を再度疑ってください。
設定変更が確実に反映されているかどうかは、APK を解凍して res/drawable-*/notification_icon.png が含まれているかでも確認できます。unzip -p app.apk | file - のように展開して画像を取り出し、目視と pngcheck の両方でチェックすると安心です。
全体を振り返って — 次にやること
通知アイコン問題は、Android の仕様を一度理解してしまえば、二度と詰まらないテーマです。今日からできる一歩としては、現在進行形のプロジェクトで app.json の expo.notification.icon が指定されているかをまず確認してみてください。指定がないか、フルカラーのアプリアイコンと同じファイルを指定している場合は、上で説明した透過白アイコンを別途用意するだけで解決します。
新規アプリを作るときは、最初の段階でアプリアイコンと通知アイコンを 1 セットで用意するワークフローを習慣化すると、後からのリビルドや再申請の手間が減ります。Android のデザインガイドラインは細かい点で更新されることがあるため、年に 1 回程度、Material Design の通知アイコンガイドを見直すのもおすすめです。