概要
リワード広告は、ユーザーが広告を最後まで視聴すると報酬を受け取れるフルスクリーン広告です。ゲーム内アイテムや追加コンテンツなどの報酬を提供する際に使用します。主な特徴
- 画面全体を覆うフルスクリーン広告
- 動画広告対応
- 報酬イベントコールバック提供
- 報酬タイプと数量情報の伝達
- ロードと表示を分離した柔軟なタイミング制御
開発環境ではテストユニットIDを使用してください:
PUBLIC_TEST_UNIT_ID_REWARDEDAdropRewardedAd
コンストラクタ
コピー
AdropRewardedAd({
required String unitId,
AdropRewardedListener? listener,
})
| パラメータ | タイプ | 必須 | 説明 |
|---|---|---|---|
unitId | String | Y | Ad Controlコンソールで作成したユニットID |
listener | AdropRewardedListener | N | 広告イベントリスナー |
プロパティ
| プロパティ | タイプ | 説明 |
|---|---|---|
isLoaded | bool | 広告のロード完了状態 |
unitId | String | 広告ユニットID |
creativeId | String | クリエイティブID |
txId | String | トランザクションID |
campaignId | String | キャンペーンID |
destinationURL | String | 遷移先URL |
メソッド
| メソッド | 戻り値 | 説明 |
|---|---|---|
load() | Future<void> | 広告をロードします |
show() | Future<void> | 広告を画面に表示します |
dispose() | Future<void> | リソースを解放します |
基本的な使い方
コピー
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';
class RewardedExample extends StatefulWidget {
const RewardedExample({super.key});
@override
State<RewardedExample> createState() => _RewardedExampleState();
}
class _RewardedExampleState extends State<RewardedExample> {
bool isLoaded = false;
AdropRewardedAd? rewardedAd;
@override
void initState() {
super.initState();
_createRewardedAd();
}
void _createRewardedAd() {
rewardedAd = AdropRewardedAd(
unitId: 'YOUR_UNIT_ID',
listener: AdropRewardedListener(
onAdReceived: (ad) {
debugPrint('リワード広告ロード成功: ${ad.creativeId}');
setState(() {
isLoaded = true;
});
},
onAdFailedToReceive: (ad, errorCode) {
debugPrint('リワード広告ロード失敗: $errorCode');
},
onAdClicked: (ad) {
debugPrint('リワード広告クリック');
},
onAdDidPresentFullScreen: (ad) {
debugPrint('リワード広告表示');
},
onAdDidDismissFullScreen: (ad) {
debugPrint('リワード広告閉じる');
},
onAdFailedToShowFullScreen: (ad, errorCode) {
debugPrint('リワード広告表示失敗: $errorCode');
},
onAdEarnRewardHandler: (ad, type, amount) {
debugPrint('報酬獲得: タイプ=$type, 数量=$amount');
_giveReward(type, amount);
},
),
);
}
void _giveReward(int type, int amount) {
// 報酬付与ロジックを実装
// 例:コイン、アイテム、追加ライフなど
}
void loadAd() {
rewardedAd?.load();
}
void showAd() {
if (isLoaded) {
rewardedAd?.show();
}
}
@override
void dispose() {
rewardedAd?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('リワード広告サンプル')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: loadAd,
child: const Text('広告をロード'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: isLoaded ? showAd : null,
child: const Text('広告を見て報酬を受け取る'),
),
],
),
),
);
}
}
AdropRewardedListener
リワード広告イベントを処理するリスナーです。コールバック関数
コピー
AdropRewardedListener(
onAdReceived: (AdropAd ad) {
// 広告ロード成功
},
onAdClicked: (AdropAd ad) {
// 広告クリック
},
onAdImpression: (AdropAd ad) {
// 広告表示
},
onAdWillPresentFullScreen: (AdropAd ad) {
// 広告表示直前(iOS専用)
},
onAdDidPresentFullScreen: (AdropAd ad) {
// 広告表示完了
},
onAdWillDismissFullScreen: (AdropAd ad) {
// 広告閉じる直前(iOS専用)
},
onAdDidDismissFullScreen: (AdropAd ad) {
// 広告閉じる完了
},
onAdFailedToReceive: (AdropAd ad, AdropErrorCode errorCode) {
// 広告ロード失敗
},
onAdFailedToShowFullScreen: (AdropAd ad, AdropErrorCode errorCode) {
// 広告表示失敗
},
onAdEarnRewardHandler: (AdropAd ad, int type, int amount) {
// 報酬獲得
},
)
コールバック説明
| コールバック | 説明 |
|---|---|
onAdReceived | 広告ロード成功時に呼び出し |
onAdClicked | 広告クリック時に呼び出し |
onAdImpression | 広告表示時に呼び出し |
onAdWillPresentFullScreen | 広告表示直前に呼び出し(iOS専用) |
onAdDidPresentFullScreen | 広告表示後に呼び出し |
onAdWillDismissFullScreen | 広告閉じる直前に呼び出し(iOS専用) |
onAdDidDismissFullScreen | 広告閉じた後に呼び出し |
onAdFailedToReceive | 広告ロード失敗時に呼び出し |
onAdFailedToShowFullScreen | 広告表示失敗時に呼び出し |
onAdEarnRewardHandler | 報酬獲得時に呼び出し |
報酬処理
報酬コールバック
onAdEarnRewardHandlerコールバックで報酬情報を受け取り処理します。
コピー
onAdEarnRewardHandler: (ad, type, amount) {
debugPrint('報酬獲得: タイプ=$type, 数量=$amount');
// 報酬タイプに応じた処理
switch (type) {
case 1:
// コイン報酬
_addCoins(amount);
break;
case 2:
// アイテム報酬
_addItem(amount);
break;
default:
// デフォルト報酬
_giveDefaultReward(amount);
}
}
報酬付与タイミング
報酬は必ず
onAdEarnRewardHandlerコールバックで付与してください。広告が完全に視聴される前に閉じられた場合、このコールバックは呼び出されません。コピー
class RewardManager {
bool _rewardEarned = false;
void setupRewardedAd() {
rewardedAd = AdropRewardedAd(
unitId: 'YOUR_UNIT_ID',
listener: AdropRewardedListener(
onAdEarnRewardHandler: (ad, type, amount) {
// 報酬フラグ設定
_rewardEarned = true;
},
onAdDidDismissFullScreen: (ad) {
// 広告閉じた後に報酬付与確認
if (_rewardEarned) {
_giveReward();
_rewardEarned = false;
}
},
),
);
}
}
広告の再作成
リワード広告は一回限りです。一度表示された広告は再表示できないため、新しい広告をロードするにはインスタンスを再作成する必要があります。コピー
class _RewardedState extends State<RewardedWidget> {
bool isLoaded = false;
bool isShown = false;
AdropRewardedAd? rewardedAd;
@override
void initState() {
super.initState();
_createRewardedAd();
}
void _createRewardedAd() {
rewardedAd?.dispose();
rewardedAd = AdropRewardedAd(
unitId: 'YOUR_UNIT_ID',
listener: AdropRewardedListener(
onAdReceived: (ad) {
setState(() {
isLoaded = true;
});
},
onAdDidPresentFullScreen: (ad) {
setState(() {
isShown = true;
});
},
onAdEarnRewardHandler: (ad, type, amount) {
_giveReward(type, amount);
},
onAdDidDismissFullScreen: (ad) {
// 広告閉じた後に新しい広告を準備
_createRewardedAd();
rewardedAd?.load();
},
),
);
setState(() {
isLoaded = false;
isShown = false;
});
}
@override
void dispose() {
rewardedAd?.dispose();
super.dispose();
}
}
エラー処理
コピー
class _RewardedState extends State<RewardedWidget> {
bool isLoaded = false;
AdropErrorCode? errorCode;
AdropRewardedAd? rewardedAd;
void _createRewardedAd() {
rewardedAd = AdropRewardedAd(
unitId: 'YOUR_UNIT_ID',
listener: AdropRewardedListener(
onAdReceived: (ad) {
setState(() {
isLoaded = true;
errorCode = null;
});
},
onAdFailedToReceive: (ad, error) {
setState(() {
isLoaded = false;
errorCode = error;
});
_handleError(error);
},
onAdFailedToShowFullScreen: (ad, error) {
setState(() {
errorCode = error;
});
_handleError(error);
},
),
);
}
void _handleError(AdropErrorCode error) {
switch (error) {
case AdropErrorCode.network:
debugPrint('ネットワークエラーが発生しました。');
break;
case AdropErrorCode.adNoFill:
debugPrint('表示する広告がありません。');
break;
case AdropErrorCode.adShown:
debugPrint('すでに表示された広告です。');
break;
default:
debugPrint('エラー発生: ${error.code}');
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: rewardedAd?.load,
child: const Text('広告をロード'),
),
ElevatedButton(
onPressed: isLoaded ? rewardedAd?.show : null,
child: const Text('広告を見て報酬を受け取る'),
),
if (errorCode != null)
Text(
'エラー: ${errorCode?.code}',
style: const TextStyle(color: Colors.red),
),
],
);
}
}
ベストプラクティス
1. 事前ロード
ユーザーが報酬を要求した時にすぐに広告を表示できるよう事前にロードします。コピー
class GameScreen extends StatefulWidget {
@override
State<GameScreen> createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
AdropRewardedAd? rewardedAd;
bool isAdReady = false;
@override
void initState() {
super.initState();
_preloadAd();
}
void _preloadAd() {
rewardedAd = AdropRewardedAd(
unitId: 'YOUR_UNIT_ID',
listener: AdropRewardedListener(
onAdReceived: (ad) {
setState(() {
isAdReady = true;
});
},
onAdEarnRewardHandler: (ad, type, amount) {
_giveReward(type, amount);
},
onAdDidDismissFullScreen: (ad) {
// 次の広告を事前ロード
_preloadAd();
},
),
);
rewardedAd?.load();
}
void showRewardedAd() {
if (isAdReady) {
rewardedAd?.show();
setState(() {
isAdReady = false;
});
}
}
@override
void dispose() {
rewardedAd?.dispose();
super.dispose();
}
}
2. ユーザーへの報酬案内
広告視聴前に受け取れる報酬を明確に案内します。コピー
void showRewardDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('報酬を受け取る'),
content: const Text('広告を視聴すると100コインを受け取れます!'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('キャンセル'),
),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
showRewardedAd();
},
child: const Text('広告を見る'),
),
],
),
);
}
3. 広告の準備状態表示
広告が準備できた時のみ報酬ボタンを有効にします。コピー
Widget buildRewardButton() {
return ElevatedButton.icon(
onPressed: isAdReady ? showRewardedAd : null,
icon: const Icon(Icons.play_circle_outline),
label: Text(isAdReady ? '広告を見て報酬を受け取る' : '広告ロード中...'),
style: ElevatedButton.styleFrom(
backgroundColor: isAdReady ? Colors.green : Colors.grey,
),
);
}
4. 報酬付与の信頼性
報酬付与はサーバーで検証することをお勧めします。コピー
onAdEarnRewardHandler: (ad, type, amount) async {
try {
// サーバーに報酬付与をリクエスト
await _api.grantReward(
userId: currentUserId,
transactionId: ad.txId,
rewardType: type,
amount: amount,
);
// ローカル状態を更新
_updateLocalBalance(amount);
} catch (e) {
debugPrint('報酬付与失敗: $e');
// リトライまたはエラー処理
}
}
5. リソース管理
使用しない広告インスタンスは必ず解放してください。コピー
@override
void dispose() {
rewardedAd?.dispose();
super.dispose();
}
完全なサンプル
コピー
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';
class RewardedAdPage extends StatefulWidget {
const RewardedAdPage({super.key});
@override
State<RewardedAdPage> createState() => _RewardedAdPageState();
}
class _RewardedAdPageState extends State<RewardedAdPage> {
bool isLoaded = false;
bool isLoading = false;
bool isShown = false;
int coins = 0;
AdropErrorCode? errorCode;
AdropRewardedAd? rewardedAd;
@override
void initState() {
super.initState();
_createRewardedAd();
}
void _createRewardedAd() {
rewardedAd?.dispose();
rewardedAd = AdropRewardedAd(
unitId: 'PUBLIC_TEST_UNIT_ID_REWARDED', // テストユニットID
listener: AdropRewardedListener(
onAdReceived: (ad) {
debugPrint('広告ロード成功');
debugPrint('クリエイティブID: ${ad.creativeId}');
debugPrint('キャンペーンID: ${ad.campaignId}');
setState(() {
isLoaded = true;
isLoading = false;
errorCode = null;
});
},
onAdClicked: (ad) {
debugPrint('広告クリック: ${ad.destinationURL}');
},
onAdImpression: (ad) {
debugPrint('広告表示: ${ad.creativeId}');
},
onAdWillPresentFullScreen: (ad) {
debugPrint('広告表示予定');
},
onAdDidPresentFullScreen: (ad) {
debugPrint('広告表示完了');
setState(() {
isShown = true;
});
},
onAdWillDismissFullScreen: (ad) {
debugPrint('広告閉じる予定');
},
onAdDidDismissFullScreen: (ad) {
debugPrint('広告閉じる完了');
// 新しい広告を準備
_createRewardedAd();
},
onAdFailedToReceive: (ad, error) {
debugPrint('広告ロード失敗: $error');
setState(() {
isLoaded = false;
isLoading = false;
errorCode = error;
});
},
onAdFailedToShowFullScreen: (ad, error) {
debugPrint('広告表示失敗: $error');
setState(() {
errorCode = error;
});
},
onAdEarnRewardHandler: (ad, type, amount) {
debugPrint('報酬獲得: タイプ=$type, 数量=$amount');
setState(() {
coins += amount;
});
_showRewardNotification(amount);
},
),
);
setState(() {
isLoaded = false;
isShown = false;
errorCode = null;
});
}
void loadAd() {
setState(() {
isLoading = true;
errorCode = null;
});
rewardedAd?.load();
}
void showAd() {
if (isLoaded) {
rewardedAd?.show();
}
}
void _showRewardNotification(int amount) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('$amountコインを獲得しました!'),
backgroundColor: Colors.green,
duration: const Duration(seconds: 2),
),
);
}
@override
void dispose() {
rewardedAd?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('リワード広告サンプル'),
),
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// コイン表示
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.amber.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.monetization_on, color: Colors.amber),
const SizedBox(width: 8),
Text(
'$coinsコイン',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
],
),
),
const SizedBox(height: 32),
// ロードボタン
ElevatedButton(
onPressed: isLoading ? null : loadAd,
child: Text(isLoading ? 'ロード中...' : '広告をロード'),
),
const SizedBox(height: 16),
// 表示ボタン
ElevatedButton.icon(
onPressed: isLoaded ? showAd : null,
icon: const Icon(Icons.play_circle_outline),
label: const Text('広告を見て報酬を受け取る'),
style: ElevatedButton.styleFrom(
backgroundColor: isLoaded ? Colors.green : Colors.grey,
),
),
const SizedBox(height: 16),
// リセットボタン
TextButton(
onPressed: (isShown || errorCode != null)
? () => _createRewardedAd()
: null,
child: const Text('リセット'),
),
const SizedBox(height: 24),
// 状態表示
Text('ロード済み: ${isLoaded ? "はい" : "いいえ"}'),
Text('表示済み: ${isShown ? "はい" : "いいえ"}'),
// エラー表示
if (errorCode != null) ...[
const SizedBox(height: 16),
Text(
'エラー: ${errorCode?.code}',
style: const TextStyle(color: Colors.red),
),
],
],
),
),
),
);
}
}