AdMobの GDPR対応(iOS)

AdMobを使用した iOSアプリで GDPRに対応した同意フォームを表示するサンプルを作成しました。

主に公式ドキュメントの情報を参考にしています。

サンプルダウンロード

導入準備

1. 広告技術プロバイダの選択

AdMobの管理画面にログインし、「ブロックの管理」→「EU ユーザーの同意」画面を開きます。

次に『広告技術プロバイダの選択』から『広告技術プロバイダのカスタム グループ』を選択します(この設定の反映には、自分の場合は1時間ほど要しました。反映されるまで同意フォームの読み込みエラーが発生しますので、気長に待ちましょう)。

また、『同意取得の設定』にある『サイト運営者 ID』も後に使用するので控えておきます。

2. CocoaPodsから SDKをインストール

Podfileに「pod ‘PersonalizedAdConsent’」の一行を追加し、SDKをインストールします。

実装

同意フォームの表示

EU圏内であれば同意フォームを表示し、従来通りのパーソナライズされた広告を表示するか、非パーソナライズされた広告を表示するかの設定を保持し、その設定によって広告のリクエストを分岐します。

ViewController.h

1
2
3
4
5
6
7
#import <UIKit/UIKit.h>
#import <PersonalizedAdConsent/PersonalizedAdConsent.h>
#import "Common.h"

@interface ViewController : UIViewController

@end

ViewController.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

NSString *const ADMOB_PUB_ID       = @"Your AdMob Publisher ID"; // AdMobのパブリッシャーID
NSString *const PRIVACY_POLICY_URL = @"Your Privacy Policy URL"; // プライバシーポリシーURL
BOOL      const PAC_DEBUG_MODE     = YES; // デバッグモード

#pragma mark -

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 広告のパーソナライズ設定
    [self initPersonalizedAdsSetting];
}

#pragma mark - Personalized Ads

// 広告のパーソナライズ設定
- (void)initPersonalizedAdsSetting
{
    // デバッグ用
    if (PAC_DEBUG_MODE) {
        // 実機の識別子をコンソール表示
        NSLog(@"Advertising ID: %@", ASIdentifierManager.sharedManager.advertisingIdentifier.UUIDString);

        // 上記で出力した実機の識別子を入力(シミュレータで確認する場合は不要)
        PACConsentInformation.sharedInstance.debugIdentifiers = @[@"Advertising ID"];

        // ユーザー地域をEU圏内に指定
        PACConsentInformation.sharedInstance.debugGeography = PACDebugGeographyEEA;

        // ユーザー地域をEU圏外に指定
        //PACConsentInformation.sharedInstance.debugGeography = PACDebugGeographyNotEEA;
    }

    // 広告のパーソナライズ設定初期化
    [[Common sharedManager] initPersonalizedAdsSetting];

    // ユーザー情報をリクエスト
    [PACConsentInformation.sharedInstance
     requestConsentInfoUpdateForPublisherIdentifiers:@[ADMOB_PUB_ID]
     completionHandler:^(NSError *_Nullable error) {
         if (error) {
             // エラー
             NSLog(@"Error -> requestConsentInfoUpdate: %@", error);
         } else {
             if ([PACConsentInformation sharedInstance].isRequestLocationInEEAOrUnknown) {
                 // EU圏内もしくは不明であればステータスをチェックする
                 NSUInteger const status = PACConsentInformation.sharedInstance.consentStatus;
                 switch (status) {
                     case PACConsentStatusPersonalized:
                     case PACConsentStatusNonPersonalized:
                         // TODO: 既に同意フォームから設定を保存済みなので、保存済みのパーソナライズ設定の広告を表示


                         break;
                     case PACConsentStatusUnknown:
                     default:
                         // 同意情報をユーザーから取得する必要があるので同意フォームを表示する
                         [self showConsentForm];

                         break;
                 }
             } else {
                 // TODO: EU圏外であれば従来通りパーソナライズされた広告を表示

             }
         }
     }];
}

// 同意フォームの表示
- (void)showConsentForm
{
    // プライバシーポリシーURLを指定し同意フォーム初期化
    NSURL *privacyURL = [NSURL URLWithString:PRIVACY_POLICY_URL];
    PACConsentForm *form = [[PACConsentForm alloc] initWithApplicationPrivacyPolicyURL:privacyURL];

    // パーソナライズ広告の同意ボタンの有無
    form.shouldOfferPersonalizedAds = YES;

    // パーソナライズされていない広告の同意ボタンの有無
    form.shouldOfferNonPersonalizedAds = YES;

    // 有料アプリへの誘導ボタンの有無
    form.shouldOfferAdFree = NO;

    // 同意フォームの読み込み
    [form loadWithCompletionHandler:^(NSError *_Nullable error) {
        if (error) {
            // ロードエラー
            NSLog(@"Error -> loadWithCompletionHandler: %@", error);
        } else {
            // ロード成功
            [form presentFromViewController:self
                          dismissCompletion:^(NSError *_Nullable error, BOOL userPrefersAdFree) {
                              if (error) {
                                  // エラー
                                  NSLog(@"Error -> presentFromViewController: %@", error);
                              } else {
                                  // ユーザーが同意フォームのどれを選択したかによって処理を分岐
                                  //PACConsentStatus *status = PACConsentInformation.sharedInstance.consentStatus; // 左記では型指定の警告が発生
                                  NSUInteger const status = PACConsentInformation.sharedInstance.consentStatus;

                                  switch (status) {
                                      case PACConsentStatusPersonalized:
                                          // パーソナライズ広告を表示するよう設定
                                          [[Common sharedManager] setPersonalizedAdsSetting:YES];

                                          // TODO: 広告の読み込み


                                          break;
                                      case PACConsentStatusNonPersonalized:
                                          // パーソナライズされていない広告を表示するよう設定
                                          [[Common sharedManager] setPersonalizedAdsSetting:NO];

                                          // TODO: 広告の読み込み


                                          break;
                                      case PACConsentStatusUnknown:
                                      default:
                                          // 同意が得られなかった場合の処理(通常は何もしない)

                                          break;
                                  }
                              }
                          }];
        }
    }];
}

@end

広告のパーソナライズ設定の保持

広告のパーソナライズ設定をユーザーデフォルトに保持します。

Common.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import <UIKit/UIKit.h>
#import <PersonalizedAdConsent/PersonalizedAdConsent.h>

#define UD_PERSONALIZED_ADS_KEY @"UD_PERSONALIZED_ADS_KEY"

@interface Common : UIView {
    NSUserDefaults *userDefaults;
    BOOL           usePersonalizedAds;
}

#pragma mark - property
@property (nonatomic, retain) NSUserDefaults *userDefaults;
@property (nonatomic, assign) BOOL           usePersonalizedAds;

#pragma mark - public method
+ (Common *)sharedManager;
- (void)setPersonalizedAdsSetting:(BOOL)usePersonalizedAds;
- (BOOL)isRequestLocationInEEAOrUnknown;
- (void)initPersonalizedAdsSetting;

@end

Common.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#import "Common.h"

@implementation Common

@synthesize userDefaults;
@synthesize usePersonalizedAds;

#pragma mark - Shared Manager

static Common *_sharedInstance = nil;

+ (Common *)sharedManager
{
    if (!_sharedInstance) {
        _sharedInstance = [[Common alloc] init];
    }

    return _sharedInstance;
}

#pragma mark - Personalized Ads

// 広告のパーソナライズ設定初期化
- (void)initPersonalizedAdsSetting
{
    // ユーザーデフォルト初期化
    NSMutableDictionary *personalizedAdsDefaults = [[NSMutableDictionary alloc] init];
    [personalizedAdsDefaults setValue:@YES forKey:UD_PERSONALIZED_ADS_KEY];
    [Common sharedManager].userDefaults = [NSUserDefaults standardUserDefaults];
    [[Common sharedManager].userDefaults registerDefaults:personalizedAdsDefaults];

    // 広告のパーソナライズ設定をユーザーデフォルトから保持
    [Common sharedManager].usePersonalizedAds = [[Common sharedManager].userDefaults boolForKey:UD_PERSONALIZED_ADS_KEY];
}

// 広告のパーソナライズ設定保持
- (void)setPersonalizedAdsSetting:(BOOL)usePersonalizedAds
{
    // 広告のパーソナライズ設定保持
    [Common sharedManager].usePersonalizedAds = usePersonalizedAds;

    // ユーザーデフォルト更新
    [[Common sharedManager].userDefaults setBool:[Common sharedManager].usePersonalizedAds forKey:UD_PERSONALIZED_ADS_KEY];
    [[Common sharedManager].userDefaults synchronize];
}

// ユーザー地域がEEAまたは不明であるか取得
- (BOOL)isRequestLocationInEEAOrUnknown
{
    return [PACConsentInformation sharedInstance].isRequestLocationInEEAOrUnknown;
}

@end

非パーソナライズ広告のリクエスト

非パーソナライズ広告を表示する場合は、下記のように広告のリクエスト時にパラメータを渡します。

1
2
3
4
5
6
GADRequest *request = [GADRequest request];
if (![Common sharedManager].usePersonalizedAds) {
    GADExtras *extras = [[GADExtras alloc] init];
    extras.additionalParameters = @{@"npa": @"1"};
    [request registerAdNetworkExtras:extras];
}

以上が導入から実装までの大まかな流れになります。

EU圏内からのアプリ使用で、同意フォームを表示する場合はまだ広告を表示しないようにし、選択された内容によって従来通りのパーソナライズされた広告か、非パーソナライズされた広告を読み込むのが良いと思います。

また、アプリのどこかに同意フォームを再表示できるメニューやボタンを用意し、ユーザーがいつでも設定を変更できる必要があります。

大雑把な情報ではありますが、少しでもお役に立てば幸いです。

iPhoneアプリ「リラックス・ヒーリング」アップデート(3.0.0)

ヒーリング音楽や睡眠に効果的なサウンドを聴いてリラックスできる iPhoneアプリ「リラックス・ヒーリング」をアップデートいたしました。

今回のアップデートでは、デザイン(色合い)を大幅に改訂し、ミュージックのオフタイマー機能やミュージックコントロール機能の追加などを行いました。よりリラックスできる優しい配色を心掛け、快適にご利用いただけるよう配慮いたしました。

下記よりアプリをダウンロードできますので、是非ご利用ください。

このアプリについて

α波発生に効果的なヒーリング音楽、雨音や森の中の小鳥のさえずりなどのサウンドを聴きながら、リラックスして深い眠りに就くことができます。

ストレスの軽減や寝付きが悪い時の対策、そして心身の疲れに効果があります。

ホワイトノイズも収録していますので、仕事や勉強に打ち込む時の作業用BGMにもお薦めです。

ミュージック画面

5曲のヒーリング音楽を収録しています。全曲連続で再生したり、一曲リピートさせることもできます。現在、約1時間分のヒーリング音楽を収録しています。

バックグラウンド再生もサポートしていますので、他のアプリを操作しながらでも音楽をお楽しみいただけます。

サウンド画面

雨音などの環境音は11種収録しています。設定した時間が来ると徐々に音量を下げながら停止しますので、睡眠の妨げにはなりません。

眠る前に、例えば小川のせせらぎなどを流したまま、リラックスした頃に知らず知らずと心地良い睡眠に入ることができます。

アラーム画面

目覚まし機能も搭載しており、5種類のアラーム音から選んで使用できます。音楽やサウンドを流したままアラームを設定しても、起床時刻と同時に停止するので安心です。

設定画面

設定画面では、ミュージック/サウンド/アラームの音量変更や、ミュージックのリピート設定と再生時間設定、サウンドの再生時間設定などが行えます。

収録内容

ヒーリング音楽

ヒーリング音楽は下記の5曲を収録しています(4曲目と5曲目は、アプリ内から購入いただくと聴く事ができます)。

  1. ストレス解消ヒーリング音楽(α波)[10:25]
  2. 神秘的なヒーリング音楽 [16:51]
  3. 快適な眠りを誘う癒しの音楽(α波)[15:31]
  4. 体に優しい癒しの音楽(有料) [06:34]
  5. さざなみヒーリング音楽(有料) [09:47]

サウンド

サウンドは下記の11項目を全て無料でお聞きいただけます。

  1. 雨音と川のせせらぎ
  2. 夕立の雨音
  3. 雰囲気に満ちた豪雨の音
  4. 雨とカエルの鳴き声
  5. ルイジアナの雨音
  6. 鳥の鳴き声
  7. 雪解け水の音
  8. 波の音
  9. ホワイトノイズ
  10. 森林浴
  11. フクロウの鳴き声

アラーム音

アラーム音は下記から好きな音を選択できます。

  1. アナログ目覚まし時計
  2. デジタル目覚まし時計
  3. 目覚ましベル
  4. ビープ音
  5. 警報音

主な機能

  • ヒーリングミュージック再生機能(5曲)
  • ヒーリングミュージックのオールプレイ機能
  • 雨音や環境音の再生機能(11サウンド)
  • 目覚まし機能(5種のアラーム音を搭載)

価格

  • 無料(App内購入あり)

対応言語

  • 日本語
  • 英語

Facebook公式ページ

iPhone/Androidアプリ「浮世絵壁紙 - 美しい日本画ギャラリー」アップデート

「浮世絵壁紙 - 美しい日本画ギャラリー」iPhone/Android版をアップデートいたしました。

今回のアップデートでは、新たに12名の作者別カテゴリを追加し、デザインのブラッシュアップを行いました。多くの方々により長くお楽しみいただけるよう、今後も定期的に更新を続けて参ります。

下記よりアプリをダウンロードできますので、是非ご利用ください。

新たに追加したカテゴリ

作者別

  • 歌川国政
  • 歌川房種
  • 歌川国利
  • 歌川芳豊
  • 笠松紫浪
  • 吉田博
  • 伊東深水
  • 小原古邨
  • 長谷川貞信(三代)
  • 鳥居言人
  • 名取春仙
  • 山本昇雲

価格

  • 無料

対応言語

  • 日本語
  • 英語
  • ロシア語
  • フランス語
  • イタリア語
  • タイ語(Android版のみ)
  • 繁体中国語

著作権表記

浮世絵は著作権フリー(著作権切れ)の作品のみを選別し、iPhone/Android用の壁紙、または作品集として一枚ずつ丹念に加工・修復しています。

公式Facebookページ

関連記事

About

廣川政樹 (@dolice_apps)

デザインエンジニア 廣川政樹の開発ブログ。Objective-Cや Javaなど iPhone/Androidアプリ開発に関する技術情報を掲載しています。

iPhone apps

  • リラックス・ヒーリング(無料)
  • 望みが叶う!引き寄せの法則アプリ(無料)
  • ミステリー - 怖い話や不思議な体験、都市伝説まとめ
  • 浮世絵壁紙 - 美しい日本画ギャラリー(無料)
  • 綺麗な壁紙HD iPhone 7/7 Plus/SE & iPod対応(無料)
  • クールな壁紙HD iPhone 7/7 Plus/SE & iPod対応(無料)

Android apps

  • 浮世絵壁紙 - 美しい日本画ギャラリー
  • 綺麗な高画質壁紙

Objective-C Classes

Tag Cloud

ActionScript(9) ActionScript3(7) Ad(5) Adfurikun(2) AdMob(10) Android(11) Animation(17) AppDelegate(3) ARC(1) ArrayList(1) AVAudioPlayer(4) AVAudioSession(1) AVFoundation(3) Banner(2) Bitmap(1) Camera(4) CGAffineTransform(4) CGBlendMode(2) CGContextRef(1) CGImageRef(1) Classes(44) CLLocationManager(1) ConnectivityManager(1) ContentResolver(1) CoreLocation(2) Delegate(3) Device(7) Display(1) DisplayMetrics(1) Download(105) Facebook(6) Foundation(72) Framework(2) Google Analytics(1) Handler(1) iAd(6) ImageView(1) In-AppPurchase(1) iOS(12) iOS 7(15) iOS 7.1(3) iOS 8(1) iPad(7) iPhone(24) iPhone 6(4) Java(7) JavaScript(2) LINE(4) Localize(1) Magazine(1) MediaStore(1) MFComposeViewController(1) Nend(1) NetworkInfo(1) NSArray(23) NSCalendar(3) NSData(2) NSDate(7) NSDateComponents(2) NSDateFormatter(2) NSDictionary(12) NSEnumerator(1) NSIndexSet(1) NSInteger(6) NSMutableArray(17) NSMutableDictionary(5) NSMutableOrderedSet(7) NSMutableString(4) NSMutableURLRequest(1) NSNotificationCenter(1) NSNumber(1) NSObject(1) NSOrderedSet(7) NSRange(2) NSSelectorFromString(1) NSSet(6) NSString(19) NSTimer(4) NSTimeZone(1) NSURL(7) NSURLConnection(1) NSURLRequest(2) NSUserDefaults(7) NSXMLParser(2) Objective-C(223) PHP(1) Products(17) QuartzCore(3) RSS(2) Runnable(1) Sample(51) Screensaver(9) SDK(2) ShareCompat(1) Social(10) StoreKit(1) Twitter(6) UIAccelerometer(3) UIActionSheet(1) UIActivityIndicator(1) UIActivityIndicatorView(3) UIActivityViewController(1) UIAlertView(5) UIApplication(7) UIButton(4) UIColor(3) UIDatePicker(5) UIDevice(6) UIDeviceOrientation(1) UIEvent(6) UIImage(15) UIImagePickerController(4) UIImageView(12) UIKit(58) UILabel(7) UINavigationBar(4) UINavigationItem(1) UIPasteboard(4) UIScreen(1) UIScrollBar(1) UIScrollView(1) UISlider(3) UIStoryboardSegue(3) UISwitch(1) UITabBar(3) UITableView(4) UITextField(2) UIView(11) UIViewAnimationTransition(1) UIViewController(4) UIWebView(5) Uncategorized(1) WindowManager(1) Xcode(48) Xcode 5(8) Xcode 5.1(2)