# 通知設計書 59-NOTIFICATION_APPLICATION_PAUSED

## 概要

本ドキュメントは、Godotエンジンにおけるアプリケーションがバックグラウンドに移行した際に発火するNOTIFICATION_APPLICATION_PAUSED通知の設計仕様を定義する。

### 本通知の処理概要

NOTIFICATION_APPLICATION_PAUSEDは、モバイルプラットフォーム（AndroidおよびiOS）においてアプリケーションがフォアグラウンドからバックグラウンドに移行した際に発火するシステム通知である。この通知により、ゲームの一時停止、データの保存、リソースの解放などを実行することができる。

**業務上の目的・背景**：モバイルアプリケーションでは、ユーザーがホームボタンを押したり、電話を受けたりするとアプリケーションがバックグラウンドに移行する。この際に適切にゲーム状態を保存し、リソースを解放することで、バッテリー消費を抑え、OSによる強制終了を防ぐことができる。特にiOSでは、バックグラウンド処理に約5秒の時間制限があるため、迅速な対応が必要である。

**通知の送信タイミング**：アプリケーションがフォアグラウンドからバックグラウンドに移行した時点で発火する。AndroidではonPause()、iOSではapplicationWillResignActive:に相当する。

**通知の受信者**：SceneTreeのルートノードから全ての子ノードに対して`propagate_notification`を通じて伝播される。

**通知内容の概要**：通知値2015を持つ整数通知として送信される。追加のパラメータは含まれない。

**期待されるアクション**：受信者はゲーム状態の保存、オーディオの一時停止、ネットワーク接続の適切な管理、リソースの解放などを実行することが期待される。iOSでは約5秒以内に処理を完了する必要がある。

## 通知種別

エンジン内部通知（Object._notification経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 最高（緊急） |
| リトライ | なし |

### 送信先決定ロジック

SceneTree::_notification()で受信後、get_root()->propagate_notification()を通じてルートノードから全ての子ノードに伝播される。

## 通知テンプレート

### 通知定数定義

| 項目 | 内容 |
|-----|------|
| 定数名 | NOTIFICATION_APPLICATION_PAUSED |
| 値 | 2015 |
| 定義場所 | core/os/main_loop.h（Nodeで再定義） |

### 受信処理例

```gdscript
func _notification(what):
    if what == NOTIFICATION_APPLICATION_PAUSED:
        # アプリ一時停止時の処理（5秒以内に完了すること - iOS）
        _on_app_paused()

func _on_app_paused():
    # ゲームを一時停止
    get_tree().paused = true
    # BGMを一時停止
    $BGMPlayer.stop()
    # ゲームデータを保存
    _save_game_data()
    print("Application paused - moving to background")

func _save_game_data():
    var save_file = FileAccess.open("user://savegame.dat", FileAccess.WRITE)
    if save_file:
        save_file.store_var(game_state)
        save_file.close()
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| なし | 追加パラメータなし | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| OSイベント | Android onPause() | アプリがバックグラウンドに移行 | Androidライフサイクルイベント |
| OSイベント | iOS applicationWillResignActive: | アプリが非アクティブ状態に移行 | iOSアプリケーションデリゲート |
| ユーザー操作 | ホームボタン押下 | ユーザーがホームに移動 | デバイス操作 |
| システムイベント | 電話着信 | 電話アプリが前面に | システム割り込み |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 非モバイルプラットフォーム | Android/iOS以外では発火しない |
| SceneTree未初期化 | ルートノードが存在しない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[アプリがバックグラウンドに移行] --> B{プラットフォーム}
    B -->|Android| C[GodotLib.onPause]
    B -->|iOS| D[AppDelegateService applicationWillResignActive]
    C --> E[MainLoop::notification発火]
    D --> E
    E --> F[SceneTree::_notification]
    F --> G{ルートノード存在?}
    G -->|Yes| H[get_root->propagate_notification]
    H --> I[全ノードへ通知伝播]
    I --> J[一時停止処理実行]
    J --> K{iOS?}
    K -->|Yes| L[5秒タイマー開始]
    L --> M[処理完了またはタイムアウト]
    M --> N[終了]
    K -->|No| N
    G -->|No| N
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（データベースを使用しない内部通知）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ルートノード未存在 | SceneTreeが初期化されていない場合 | 通知をスキップ |
| 保存処理失敗 | ファイルI/Oエラー | ログ出力して継続 |
| タイムアウト（iOS） | 5秒以内に処理が完了しない | OSによる強制終了 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（アプリ一時停止に応じて随時発火）

## セキュリティ考慮事項

- 保存データが適切に暗号化されているか確認すべき
- センシティブなデータはバックグラウンド移行前にクリアを検討

## 備考

- AndroidおよびiOSプラットフォームで実装されている
- NOTIFICATION_APPLICATION_RESUMEDとペアで使用される
- **重要（iOS）**: 約5秒以内に処理を完了しないとOSがアプリを強制終了する可能性がある
- GDExtensionを通じても通知が発火される（core/extension/godot_instance.cpp）
- デスクトッププラットフォームでは代わりにNOTIFICATION_APPLICATION_FOCUS_OUTを使用

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

通知の定数値とその定義場所を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | main_loop.h | `core/os/main_loop.h` | NOTIFICATION_APPLICATION_PAUSED = 2015 の定義（56行目） |
| 1-2 | node.h | `scene/main/node.h` | Nodeクラスでの再定義（495行目） |

**読解のコツ**: MainLoopで定義された通知定数がNodeクラスで再定義されていることを確認する。

#### Step 2: プラットフォーム固有の実装を理解する

Android/iOS固有のライフサイクルイベント処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | java_godot_lib_jni.cpp | `platform/android/java_godot_lib_jni.cpp` | Android JNIからの呼び出し |
| 2-2 | os_apple_embedded.mm | `drivers/apple_embedded/os_apple_embedded.mm` | iOS固有のOS実装 |

**主要処理フロー**:
1. OSからのアプリ一時停止イベント受信
2. MainLoopへの通知発火

#### Step 3: 通知伝播処理を理解する

SceneTreeでの通知処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | scene_tree.cpp | `scene/main/scene_tree.cpp` | _notification()メソッドでのNOTIFICATION_APPLICATION_PAUSED処理（916行目） |

**主要処理フロー**:
1. **916行目**: `case NOTIFICATION_APPLICATION_PAUSED:` - 一時停止ケースの判定
2. **920行目**: `get_root()->propagate_notification(p_notification)` - ルートから全ノードへ伝播

#### Step 4: GDExtension連携を理解する

GDExtensionからの通知発火を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | godot_instance.cpp | `core/extension/godot_instance.cpp` | GDExtension経由の通知発火 |

### プログラム呼び出し階層図

```
OS Application Lifecycle
    │
    ├─ [Android] GodotLib.onPause() (JNI)
    │      │
    │      └─ java_godot_lib_jni.cpp
    │             │
    │             └─ MainLoop::notification(NOTIFICATION_APPLICATION_PAUSED)
    │
    ├─ [iOS] AppDelegateService::applicationWillResignActive
    │      │
    │      └─ os_apple_embedded.mm
    │             │
    │             └─ MainLoop::notification(NOTIFICATION_APPLICATION_PAUSED)
    │             │
    │             └─ [5秒タイマー開始]
    │
    └─ SceneTree::_notification()
           │
           └─ get_root()->propagate_notification()
                  │
                  └─ Node::_notification() [再帰的に伝播]
                         │
                         ├─ ゲーム状態保存
                         │
                         ├─ オーディオ停止
                         │
                         └─ リソース解放
```

### データフロー図

```
[入力]               [処理]                    [出力]

OSアプリ一時    プラットフォーム           MainLoop通知
停止イベント ───▶ ハンドラ      ───▶      発火
                      │
                      ▼
                SceneTree
              _notification()
                      │
                      ▼
              全ノードへ伝播
                      │
                      ├───▶ ゲーム状態保存
                      │
                      ├───▶ オーディオ停止
                      │
                      └───▶ リソース解放
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| main_loop.h | `core/os/main_loop.h` | ソース | 通知定数の定義 |
| main_loop.cpp | `core/os/main_loop.cpp` | ソース | MainLoopの通知バインド |
| node.h | `scene/main/node.h` | ソース | Nodeクラスでの通知定数再定義 |
| scene_tree.cpp | `scene/main/scene_tree.cpp` | ソース | 通知の伝播処理 |
| java_godot_lib_jni.cpp | `platform/android/java_godot_lib_jni.cpp` | ソース | Android JNI実装 |
| os_apple_embedded.mm | `drivers/apple_embedded/os_apple_embedded.mm` | ソース | iOS固有OS実装 |
| godot_instance.cpp | `core/extension/godot_instance.cpp` | ソース | GDExtension連携 |
| MainLoop.xml | `doc/classes/MainLoop.xml` | ドキュメント | 通知の公式ドキュメント（5秒制限記載） |
