body method
Defines the actual body code. path is passed relative to lib, baseName is the filename, and className is the filename converted to Pascal case.
実際の本体コードを定義します。pathにlibからの相対パス、baseNameにファイル名が渡され、classNameにファイル名をパスカルケースに変換した値が渡されます。
Implementation
@override
String body(String baseName, String className) {
return """
`Firebase Remote Config`は下記のように利用する。
## 概要
$excerpt
条件分岐により、ユーザーセグメント、プラットフォーム、アプリバージョンごとに異なる設定値を配信できます。
## 設定方法
### katana.yamlを使用する場合(推奨)
1. `katana.yaml`に下記の設定を追加。
```yaml
# katana.yaml
# Enable Firebase Remote Config.
# Firebase Remote Configを有効にします。
firebase:
project_id: your-project-id
remote_config:
enable: true # Remote Configを利用する場合false -> trueに変更
```
2. 下記のコマンドを実行して設定を適用。
```bash
katana apply
```
この方法により、自動的に`masamune_model_firebase_remote_config`パッケージがインストールされ、設定が完了します。
3. `lib/main.dart`で`FirebaseRemoteConfigModelAdapter`を設定。
```dart
// lib/main.dart
import 'package:masamune/masamune.dart';
import 'package:masamune_model_firebase_remote_config/masamune_model_firebase_remote_config.dart';
final modelAdapter = FirebaseRemoteConfigModelAdapter(
options: DefaultFirebaseOptions.currentPlatform,
initialValue: {
"feature_enabled": false,
"api_endpoint": "https://api.example.com",
"max_items": 10,
},
minimumFetchInterval: Duration(minutes: 30), // キャッシュ期間
);
void main() {
runMasamuneApp(
appRef: appRef,
modelAdapter: modelAdapter,
(appRef, _) => MasamuneApp(
appRef: appRef,
home: HomePage(),
),
);
}
```
### 手動でパッケージを追加する場合
1. パッケージをプロジェクトに追加。
```bash
flutter pub add masamune_model_firebase_remote_config
```
2. `lib/main.dart`で`FirebaseRemoteConfigModelAdapter`を設定。
```dart
// lib/main.dart
import 'package:masamune/masamune.dart';
import 'package:masamune_model_firebase_remote_config/masamune_model_firebase_remote_config.dart';
final modelAdapter = FirebaseRemoteConfigModelAdapter(
options: DefaultFirebaseOptions.currentPlatform,
initialValue: {
"feature_enabled": false,
"api_endpoint": "https://api.example.com",
"max_items": 10,
},
minimumFetchInterval: Duration(minutes: 30),
);
void main() {
runMasamuneApp(
appRef: appRef,
modelAdapter: modelAdapter,
(appRef, _) => MasamuneApp(
appRef: appRef,
home: HomePage(),
),
);
}
```
## 利用方法
### Remote Config値の取得
Remote Configの値をMasamuneモデルとして読み込みます。
```dart
import 'package:masamune/masamune.dart';
import 'package:masamune_model_firebase_remote_config/masamune_model_firebase_remote_config.dart';
class MyPage extends PageScopedWidget {
@override
Widget build(BuildContext context, PageRef ref) {
// Remote Configをドキュメントとして読み込み
final config = ref.app.model(
FirebaseRemoteConfigModel.document(),
)..load();
return Scaffold(
body: Column(
children: [
// 設定値へのアクセス
Text("Feature: \${config.value.get<bool>("feature_enabled")}"),
Text("Endpoint: \${config.value.get<String>("api_endpoint")}"),
Text("Max Items: \${config.value.get<int>("max_items")}"),
],
),
);
}
}
```
### 条件付き設定値の活用
Remote Configで設定した条件に応じて、異なる値を取得できます。
```dart
// 機能フラグによる機能の有効化
final config = ref.app.model(FirebaseRemoteConfigModel.document())..load();
if (config.value.get<bool>("new_feature_enabled", false)) {
// 新機能を表示
return NewFeatureWidget();
} else {
// 従来の機能を表示
return LegacyFeatureWidget();
}
```
### デフォルト値の設定
`initialValue`でデフォルト値を設定することで、Remote Configが利用できない場合でもアプリが動作します。
```dart
final modelAdapter = FirebaseRemoteConfigModelAdapter(
options: DefaultFirebaseOptions.currentPlatform,
initialValue: {
"welcome_message": "Welcome!",
"api_timeout_seconds": 30,
"max_retry_count": 3,
"feature_flags": {
"dark_mode": false,
"beta_features": false,
},
},
minimumFetchInterval: Duration(hours: 1),
);
```
## Firebase Consoleでの設定
1. Firebase Console → Remote Configを開く
2. パラメータを追加(`initialValue`のキーと一致させる)
3. 条件を設定(オプション):
- プラットフォーム(iOS、Android、Web)
- アプリバージョン
- ユーザープロパティ
- 国/地域
4. 値を設定して公開
### 条件の例
```
条件名: iOS Users
条件: app.platform == 'ios'
api_endpoint: https://ios-api.example.com
条件名: Beta Users
条件: user.beta_tester in ['true']
new_feature_enabled: true
条件名: Version 2.0+
条件: app.version >= '2.0.0'
max_items: 20
```
## 重要な注意事項
### 読み取り専用
Remote Configは**読み取り専用**です。`save()`や`delete()`を呼び出すと`UnsupportedError`がスローされます。
値の更新はFirebase ConsoleまたはRemote Config REST APIを使用してください。
### キャッシュ動作
`minimumFetchInterval`で指定した期間はキャッシュされた値が使用されます。
- 開発時: `Duration.zero`を指定して常に最新値を取得
- 本番環境: `Duration(hours: 12)`など、適切な間隔を設定
```dart
// 開発時
minimumFetchInterval: Duration.zero,
// 本番環境
minimumFetchInterval: Duration(hours: 12),
```
### フェッチとアクティブ化
`load()`を呼び出すたびに、自動的に`fetchAndActivate()`が実行されます。
- フェッチに失敗した場合はキャッシュ値が使用されます
- デフォルト値(`initialValue`)は常に利用可能です
## 実装例: A/Bテスト
```dart
class ProductPage extends PageScopedWidget {
@override
Widget build(BuildContext context, PageRef ref) {
final config = ref.app.model(FirebaseRemoteConfigModel.document())..load();
final buttonColor = config.value.get<String>("button_color", "blue");
return Scaffold(
body: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: buttonColor == "red" ? Colors.red : Colors.blue,
),
child: Text("購入する"),
onPressed: () {
// 購入処理
},
),
),
);
}
}
```
## 実装例: 段階的ロールアウト
新機能を特定のユーザーにのみ公開する場合:
```dart
class HomePage extends PageScopedWidget {
@override
Widget build(BuildContext context, PageRef ref) {
final config = ref.app.model(FirebaseRemoteConfigModel.document())..load();
final rolloutPercentage = config.value.get<int>("new_ui_rollout", 0);
// ユーザーIDのハッシュ値でランダムに振り分け
final userId = ref.app.auth.value?.uid ?? "";
final userHash = userId.hashCode % 100;
if (userHash < rolloutPercentage) {
return NewUIHomePage();
} else {
return OldUIHomePage();
}
}
}
```
## 実装例: メンテナンスモード
アプリ全体をメンテナンスモードにする場合:
```dart
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MasamuneApp(
home: AppScopedWidget(
(context, ref) {
final config = ref.app.model(
FirebaseRemoteConfigModel.document(),
)..load();
if (config.value.get<bool>("maintenance_mode", false)) {
return MaintenancePage(
message: config.value.get<String>(
"maintenance_message",
"現在メンテナンス中です",
),
);
}
return HomePage();
},
),
);
}
}
```
### Tips
- Remote Configは読み取り専用のため、値の更新はFirebase Consoleで行う
- 開発時は`minimumFetchInterval: Duration.zero`で常に最新値を取得
- `initialValue`で必ずデフォルト値を設定し、オフライン時の動作を保証
- A/Bテストや段階的ロールアウトに活用できる
- メンテナンスモードの切り替えに利用すると、アプリの再リリースなしで対応可能
- Firebase Consoleで条件を設定して、プラットフォームやユーザー属性ごとに異なる値を配信
- `fetchAndActivate()`は`load()`時に自動実行されるため、手動で呼び出す必要なし
""";
}