【Swift UI】AdMobのリワード広告の実装方法!FullScreenContentDelegate
この記事からわかること
- Swift UIでリワード広告の実装方法
- AdMobを導入
- 動画視聴で報酬を得られる広告
- RewardedAdやFullScreenContentDelegateの使い方
- RewardedAdクラスのloadメソッドやpresentメソッドの使い方
- リワード広告に1日1回の視聴回数制限を設ける方法
- フリークエンシーキャップとは?
index
[open]
\ アプリをリリースしました /
環境
- Xcode:26.0.1
- iOS:26
- Swift:6
- Google Mobile Ads:12.12.0
- macOS:Tahoe 26.0.1
Swift UIでAdMobを使用したリワード広告の実装方法をまとめて行きたいと思います。Swift6対応済みのコードを紹介していきます。
リワード広告とは?
そもそも「リワード広告」とはアフィリエイト(成功報酬型)広告の1種で何かしらの報酬を付与する代わりに短い動画を視聴してもらう広告形態です。今回はiOSアプリに広告を掲載する方法の1つである「Google AdMob」を活用します。
「Google AdMob」はGoogleが提供しているiOSやAndroidなどのモバイルアプリに広告を設置できるサービスで、バナー広告をはじめリワード広告、インタースティシャル広告の実装も簡単に実装可能になっています。
使用するための注意点とポリシー
リワード広告をアプリに組み込む上では取り扱いに注意が必要です。公式サイトで注意点やポリシーが公開されているので違反しないように設計してください。
重要なところだけまとめておきます。
注意点
- クリックを促すような記述をしない
- 視聴後に価値のある報酬を提供すること
- ランダム報酬の場合は明示する
- ユーザーの同意がある時のみ配信可能にする
- 視聴制限を設けることが推奨
基本的には短い動画広告が配信されることと貰える報酬の明記、そしてちゃんと報酬が与られる動作にすれば問題ありません。
Swift UIでリワード広告を実装する方法
流れ
- AdMobへ登録と広告ユニットの作成
- プロジェクトへAdMobの導入
- AdMob用のファイルを作成
- リワードクラスの作成
- 広告を読み込むメソッドの実装
- 読み込んだ広告を表示するメソッドの実装
- ビューとして呼び出す
今回はSwift UIを使用している場合のリワード広告の実装方法を見ていきます。AdMobが未登録の場合や広告ユニットが未作成、プロジェクトへ未導入の場合は下記記事をご覧ください。
AdMobでは開発途中のテスト実装の際は本番用の広告ユニットIDを使用せずテスト用の広告ユニットIDを使用することを推奨しています。テスト実装の際は以下のIDを然るべき箇所に記述してください。
// テスト用広告ユニットID
ca-app-pub-3940256099942544/1712485313
リワード広告のロードと表示ロジックの実装
広告ユニットの作成とプロジェクトへAdMobの導入が完了したら実際にコードを書いていきます。リワード広告のロードと表示ロジッを持ったサービスクラスを実装します。RewardedAd.loadはasync/awaitが用意されていますが、presentは用意されていなかったのでwithCheckedThrowingContinuationでラップしておきました。
import SwiftUI
import UIKit
import GoogleMobileAds
@MainActor
protocol RewardServiceProtocol {
func loadReward() async throws -> RewardedAd
func showReward(_ ad: RewardedAd) async throws
}
@MainActor
final class RewardService: NSObject, RewardServiceProtocol, FullScreenContentDelegate {
/// 広告を取得
func loadReward() async throws -> RewardedAd {
let request = Request()
request.scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
// 広告ユニットIDを指定
let ad = try await RewardedAd.load(with: "ca-app-pub-3940256099942544/1712485313", request: request)
ad.fullScreenContentDelegate = self
return ad
}
/// 広告を表示
func showReward(_ ad: RewardedAd) async throws {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
guard let rootVC = windowScene?.windows.first?.rootViewController else { return }
try await withCheckedThrowingContinuation { continuation in
ad.present(from: rootVC) {
// 広告視聴完了
continuation.resume()
}
}
}
}
FullScreenContentDelegateは広告表示関連の通知を受け取るデリゲートメソッドが定義されているプロトコルです。今回は特に定義してなかったですが一応準拠させておきました。
中間となるViewModelを実装する
ここは特に特殊なことはしていないです。
@MainActor
final class RewardViewModel: ObservableObject {
@Published var rewardLoaded = false
private var rewardedAd: RewardedAd?
private let rewardService: RewardServiceProtocol
init(rewardService: RewardServiceProtocol = RewardService()) {
self.rewardService = rewardService
}
func loadReward() async {
do {
let ad = try await rewardService.loadReward()
rewardedAd = ad
rewardLoaded = true
} catch {
// リワード読み込み失敗
rewardLoaded = false
}
}
func showReward() async {
// 広告が未読み込みであれば読み込んでから再度表示を試みる
guard let ad = rewardedAd else {
await loadReward()
await showReward()
return
}
do {
try await rewardService.showReward(ad)
rewardLoaded = false
// TODO:報酬付与処理
} catch {
// リワード表示失敗
}
}
}
Swift UIでビューとして呼び出す
作成したクラスを表示したいビューで呼び出していきます。ObservableObjectプロトコルに準拠させているのでインスタンス化するクラスには@StateObjectをつけておきます。
import SwiftUI
struct RewardView: View {
// AdMob reward広告
@StateObject private var viewModel = RewardViewModel()
var body: some View {
Button {
Task {
// 広告配信
await viewModel.showReward()
}
} label: {
Text("広告を視聴する")
}.onAppear {
Task {
await viewModel.loadReward()
}
}.disabled(!reward.rewardLoaded)
}
}
ビューが表示されるタイミングで処理を実行するonAppearの中に広告を読み込むloadRewardメソッドを記述しておきます。広告を表示するshowRewardメソッドはボタンのアクション部分に記述しておきます。
これでボタンをクリック時にリワード広告が再生されるようになります。広告の読み込みが終了していない場合に備えてボタンを非アクティブにするdisabledに読み込みフラグを渡しておきました。
1日1回の視聴回数制限を設ける
リワード広告では視聴回数制限を設けることが推奨されています。今回は「1日に1回の視聴回数制限」を設けていきたいと思います。ここで肝となるのは以下のポイントです。
- @AppStorage:データをアプリが停止しても保持する
- nowTimeメソッド:現在の日付を返す自作メソッド / DateFormatter
- alertモディファイア:通知ポップアップを表示する
@AppStorageはプロパティーラッパの1つでアプリが停止してもデータを保持することができます。ここに最後に視聴した日付を格納しておき、現在の日付と照らし合わせることで何回目の視聴か識別できるようにしています。
おすすめ記事:
まずは上部に必要となるプロパティを定義していきます。
struct RewardView: View {
/// リワード広告視聴回数制限アラート
@State private var isAlertReward:Bool = false
/// 最終視聴日時を保存する
@AppStorage("LastAcquisitionDate") var lastAcquisitionDate = ""
/// 現在の日付を返す
private func nowTime() -> String {
let df = DateFormatter()
df.calendar = Calendar(identifier: .gregorian)
df.locale = Locale(identifier: "ja_JP")
df.timeZone = TimeZone(identifier: "Asia/Tokyo")
df.dateStyle = .short
df.timeStyle = .none
return df.string(from: Date())
}
// 〜〜〜〜〜〜〜〜〜〜
}
あとは日付を比較した結果によって処理を分岐させればOKです。(雑にUIに入れてしまいましたがViewModelに含めるべきです)
if lastAcquisitionDate != nowTime() {
Task {
// 広告配信
await viewModel.showReward()
lastAcquisitionDate = nowTime() // 最終視聴日を格納
}
} else {
isAlertReward = true
}
フリークエンシーキャップ
リワード広告の視聴制限は広告ユニットごとに設定することも可能です。
AdMobから広告ユニットを作成する際に「詳細設定」をクリックし「フリークエンシーキャップ」という項目を有効にすると時間単位の視聴回数制限設けることができます。
しかしこれはあくまで配信されるかされないかなので先ほどのようなUI側で明示的に表示できるように何かしらの機構を作っておくことをおすすめします。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。
私がSwift UI学習に使用した参考書







