◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-05-14中級

Android 13 以降で Rork アプリのプッシュ通知が届かない — POST_NOTIFICATIONS 権限の追加手順

Android 13(API 33)以降でプッシュ通知が届かない原因は、POST_NOTIFICATIONS 権限の追加漏れです。Rork 生成コードへの追加手順を Before/After で解説します。

Android55プッシュ通知20権限7POST_NOTIFICATIONSRork585トラブルシューティング85

プッシュ通知の実装が完了したはずなのに、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 production

Android 13 の動作を確認したい場合は、API レベル 33 以上のエミュレーターか、Android 13 以降の実機でテストしてください。古いエミュレーターでは権限ダイアログが表示されず、問題を見落とすことがあります。

動作確認の手順

修正後は以下の順序で確認します。

  1. EAS Build(または npx expo run:android)で新しいビルドをインストール
  2. アプリを初回起動すると「通知を送信しますか?」ダイアログが表示されることを確認
  3. 「許可」を選択後、Expo Push Notification Tool からテスト送信
  4. 通知が届くことを確認

権限が実際に付与されたかどうかは、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_NOTIFICATIONS

2つ目のコマンドで 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)の変更が反映されない場合の対処も参考になります。

実装の参考になれば幸いです。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ 開発ツール2026-10-07
日本語の見出しだけ太字にならない — Android で fontWeight が効かないときの切り分けと直し方
Rork で作ったアプリで、iPhone では太字なのに Android では日本語の見出しが細いままになる症状の切り分け記事です。原因の見分け方、fontFamily を重みごとに分ける直し方、確認用コードを載せています。
⬡ 開発ツール2026-10-15
EXPO_PUBLIC_ の値が、開発では読めて本番だけ undefined になる書き方を、変換結果で見分けます
API の URL が開発中は読めるのに、ビルドした途端に undefined になる。原因は process.env の書き方でした。babel-preset-expo の変換結果を開発・本番で並べ、置き換わる書き方と残ってしまう書き方を表にしました。
⬡ 開発ツール2026-09-21
exit code 0 で止まるビルド — ログを黙らせていた設定と、空ファイルを通した存在チェック
eas build --local が exit code 0 but produced no further output で止まる件と、0 バイトのスタブが埋め込まれず dyld で落ちる件。どちらも原因は出力を減らす設定でした。自分のスクリプトを棚卸しする手順まで書き残します。