プッシュ通知の実装が完了したはずなのに、Android 実機で通知がまったく届かない——そんな報告を受けて頭を抱えた経験のある方は、少なくないと思います。
個人開発でプッシュ通知を扱っていると、iOS では問題なく届くのに Android の新しい端末だけ沈黙する、という場面に何度か出会いました。原因の多くは、Android 13 で追加された通知権限の対応漏れです。
届かない通知は、存在しない通知と同じ。リテンション(継続率)に直結する機能だからこそ、ここは丁寧に潰しておきたいところです。
Android 13(API レベル 33)以降の端末では、通知を表示するために POST_NOTIFICATIONS という新しい権限のリクエストが必要になりました。Rork の AI 生成コードは非常に優秀ですが、この比較的新しい Android の仕様変更に対応しきれていないケースがあります。
Android 13 で何が変わったのか
Android 12 以前では、アプリをインストールするだけで通知の送受信が可能でした。ユーザーが明示的に拒否しない限り、通知は届いていたのです。
Android 13 からは opt-in 方式 に変わりました。アプリが初めて通知を送ろうとする前に、ユーザーに「通知を許可しますか?」というダイアログを表示し、許可を得る必要があります。
Android 12 以前: インストール → 通知が届く(自動許可)
Android 13 以降: インストール → 権限リクエスト → 許可 → 通知が届く
この変更が適用されたのは API 33 以降の端末です。ただし、アプリの targetSdkVersion が 32 以下の場合は一時的に旧挙動となりますが、Google Play の要件(2024年以降は targetSdk 34 以上)を満たすためには、必ず対応が必要になります。
Rork の生成コードでよくある漏れのパターン
Rork が生成するコードは expo-notifications を使って通知機能を実装します。しかし、以下のパターンで権限が漏れていることがあります。
パターン1: requestPermissionsAsync() の呼び出しがない、または iOS 向けの権限チェックのみで Android 向けの対応が抜けている
// ❌ iOS のみ考慮したコード(Android 13+ で通知が届かない)
const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') {
alert('通知の許可が必要です');
return;
}パターン2: app.json の permissions 配列に POST_NOTIFICATIONS が含まれていない
// ❌ app.json に Android 権限の記述がない
{
"expo": {
"android": {
"package": "com.yourapp.app"
}
}
}いずれのケースも、iOS シミュレーターや Android 12 以前の実機でテストしている間は問題が現れないため、見落とされがちです。
app.json への POST_NOTIFICATIONS 権限追加
まず app.json に POST_NOTIFICATIONS 権限を追加します。
// ✅ 正しい app.json(Android 13 対応)
{
"expo": {
"android": {
"package": "com.yourapp.app",
"permissions": [
"android.permission.POST_NOTIFICATIONS",
"android.permission.VIBRATE",
"android.permission.RECEIVE_BOOT_COMPLETED"
]
},
"plugins": [
[
"expo-notifications",
{
"icon": "./assets/notification-icon.png",
"color": "#ffffff"
}
]
]
}
}VIBRATE と RECEIVE_BOOT_COMPLETED は通知の動作に必要な権限です。一緒に追加しておくと安心です。
私自身は、通知や課金のように OS のバージョンで挙動が変わりやすい領域だけは、生成コードをそのまま信じずに一度自分の目で app.json を開いて確認するようにしています。数十秒の手間で、公開後に気づく事故をかなり減らせます。
権限リクエストのコードを修正する
次に、通知権限のリクエスト処理を修正します。Android 13 以降では、expo-notifications の requestPermissionsAsync() が適切にダイアログを表示しますが、バージョンによっては追加の設定が必要です。
// ✅ Android 13+ に対応した権限リクエスト
import * as Notifications from 'expo-notifications';
import { Platform } from 'react-native';
async function registerForPushNotificationsAsync() {
// Android の場合、通知チャンネルを先に作成する
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('default', {
name: 'Default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
// 権限リクエスト(iOS / Android 13+ で共通)
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
console.warn('プッシュ通知の権限が取得できませんでした');
return null;
}
// デバイストークンの取得(SDK 52 以降は projectId が必須)
const token = await Notifications.getExpoPushTokenAsync({
projectId: 'YOUR_EXPO_PROJECT_ID',
});
return token.data;
}重要なのは、まず getPermissionsAsync() で現在の権限状態を確認してから、未決定の場合のみ requestPermissionsAsync() を呼び出す点です。すでに「許可」または「拒否」が決まっているのに何度もダイアログを表示しようとすると、設定済みの状態がそのまま返るだけになります。
EAS Build での注意点
app.json を変更したあとは、必ず EAS Build を再実行する必要があります。権限の設定は AndroidManifest.xml に反映されるものであり、OTA(Over the Air)アップデートでは変更できません。
# 開発用プレビュービルドで動作確認
eas build --platform android --profile preview
# 確認が取れたら本番ビルド
eas build --platform android --profile productionAndroid 13 の動作を確認したい場合は、API レベル 33 以上のエミュレーターか、Android 13 以降の実機でテストしてください。古いエミュレーターでは権限ダイアログが表示されず、問題を見落とすことがあります。
動作確認の手順
修正後は以下の順序で確認します。
- EAS Build(または
npx expo run:android)で新しいビルドをインストール - アプリを初回起動すると「通知を送信しますか?」ダイアログが表示されることを確認
- 「許可」を選択後、Expo Push Notification Tool からテスト送信
- 通知が届くことを確認
権限が実際に付与されたかどうかは、adb でも確認できます。ダイアログの結果を推測せず、OS 側の状態を直接読めるので、原因の切り分けが速くなります。
# 通知権限の付与状態を確認(granted=true なら許可済み)
adb shell dumpsys notification_manager | grep -A1 com.yourapp.app
# パッケージに宣言された権限一覧を確認(POST_NOTIFICATIONS があるか)
adb shell dumpsys package com.yourapp.app | grep POST_NOTIFICATIONS2つ目のコマンドで POST_NOTIFICATIONS が出てこない場合は、app.json の変更がビルドに反映されていないサインです。EAS Build の再実行から見直してください。
もしダイアログが表示されない場合は、端末の「設定」→「アプリ」→ アプリ名 → 「通知」から手動で許可することで動作テスト自体は続行できます。ただし、実際のユーザーが設定画面まで辿り着くことは稀なので、コードの修正は必須です。
Expo SDK バージョンによる追加確認
expo-notifications のバージョンによって API の挙動が多少異なります。Rork が生成するプロジェクトは概ね Expo SDK 50〜55 の範囲ですが、SDK 52 以降では getExpoPushTokenAsync() に projectId が必須になっています。
// SDK 52 以降は projectId が必須(ないとデバッグでは動くが本番で失敗する)
import Constants from 'expo-constants';
const token = await Notifications.getExpoPushTokenAsync({
projectId: Constants.expoConfig?.extra?.eas?.projectId,
});projectId が欠けていると、開発ビルドでは動くのに本番ビルドでトークン取得が失敗する、という紛らわしい症状が出ることがあります。合わせて確認してみてください。
Android の通知権限まわりは、OS のバージョンアップのたびに変化しています。POST_NOTIFICATIONS に限らず、今後も同様の変更が続く可能性があります。Rork の生成コードを信頼しつつも、通知・権限・課金まわりは特に変化が多い領域なので、定期的に公式ドキュメントを参照する習慣をつけておくと安心です。
関連する問題として、Rork アプリのプッシュ通知が届かない原因と解決方法や、EAS Update(OTA)の変更が反映されない場合の対処も参考になります。
実装の参考になれば幸いです。