[GoogleMobileAds] Unity-Google-UMP-Check[GDPR/IDFA(ATT)]
Untiy 2021.3.42f1
GoogleMobileAds 9.1.0
----
[추가] 2024-08-22
GoogleMobileAds의 UMP로 GDPR과 IDFA(ATT)를 유기적으로 처리는 가능한데,
GoogleMobileAds의 IDFA(ATT)를 사용하면 안이쁜 '무료 이용'어쩌고 팝업이 한 번 뜬다.
이 부분을 없애기 위해서 ATT를 GoogleMobileAds의 IDFA를 Off 하고, Unity Package인 'iOS 14 Advertising Support'를 사용하도록 변경했다.
[참고] https://docs.unity3d.com/Packages/com.unity.ads.ios-support@1.0/manual/index.html
변경한 소스는 아래 소스에 갱신하고, 관련해서 CurrentGDPR.cs도 추가했다.
로직 순서는 대충 아래와 같다.
[순서] 애드몹(GoogleMobileAds) 초기화 -> CurrentGDPR 초기화 -> ATT(IDFA) 초기화
// GoogleMobileAds
yield return new WaitUntil(() => true == blueasa.GoogleMobileAdsManagerSGT.Exists);
yield return null;
SGT.Ads.Initialize();
yield return new WaitUntil(() => true == SGT.Ads.Initialized);
Debug.LogWarning("[GoogleMobileAds] 초기화 완료");
yield return null;
// GDPR 관련 동의 상태 Load[blueasa / 2024-03-21]
CurrentGDPR.InitData();
Debug.LogWarning("[CurrentGDPR] 초기화 완료");
yield return null;
// ATT(IDFA) 동의 체크
SGT.Ads.RequestAuthorizationTracking();
Debug.LogWarning("[ATT] 동의 체크 완료");
yield return null;
순서만 참조하면 될 듯 한데, 간단히 설명하자면 아래와 같다.
1) GoogleMobileAds를 초기화하면서 GDPR 동의 내부에서 진행.
2) CurrentGDPR 초기화해서 GDPR 관련 데이터 Load
3) Load 한 CurrentGDPR 데이터 참조해서 ATT 요청할지 판단 및 실행(RequestAuthorizationTracking)
추가적으로, GDPR 동의했어도, ATT 거부를 했다면,
설정창 등에 보여주던 GDPR 동의상태 변경을 위한 버튼을 띄우면 안된다고 한다.
(Apple 검수 넣었다가 해당 이슈로 리젝 당함)
그래서 IsAuthorizationTracking() 함수를 이용해서 ATT 거부 상태면, GDPR 설정 버튼이 안뜨도록 해뒀다.
참고하자.
----------------------------------------------------------------
2024년 1월 16일까지(참조:https://support.google.com/admob/answer/14189727?hl=ko) Admob을 사용하려면 유저에게 GDPR 동의를 받으라고 하는 것 같다.
그래서 Google에서 관련 SDK를 내놓은게 UMP(User Messaging Platform) SDK다.
----
Unity GoogleMobileAds에 UMP 적용하기 위해 찾아보니 누군가가 github에 정리해 놨길래 가져와서 적당히(?) 개조해서 내 GoogleMobileAdsManager에 추가 했다.
[Unity-Google-UMP-Check] https://github.com/TheBossaaa/Unity-Google-UMP-Check
기본적으로 위 소스만 적용하고 폰에서 실행해보면 아래와 같은 에러가 나온다.
[Error Code] GoogleMobileAds.Ump.Api.FormError
해당 에러는 GoogleMobileAds Dashboard에서 GDPR 관련 설정이 안돼 있어서 나오는 에러이다.
아래 Admob UMP Docs에서는 딱히 GoogleMobileAds Dashboard 관련 설정을 설명 안해놔서 모르고 넘어갈 수 있다.
Dashboard에 설정을 하자.
[FormError 관련 참조] https://github.com/googleads/googleads-mobile-unity/issues/2780
※ 추가적으로 Admob UMP Docs에 보면 Runtime에 GDPR 변경을 위한 버튼을 구현하는 샘플이 보인다.
법적으로 Runtime에 GDPR 변경을 해줘야 되는거면 버튼도 별도로 추가해줘야 될 것 같다.
[참조] https://github.com/googleads/googleads-mobile-unity/issues/2780
[GDPR 테스트]
GDPR 테스트 관련 소스가 들어있는데, Test Device Hashed Id를 넣으라고 돼있고, 실행해보면 Logcat에 뜬다고 돼 있는데 안떠서 찾아보니 아래와 같은 내용이 있다.
(난 현재 테스트 폰이 API 30이 안돼서 Test Device Hashed Id는 안넣어도 되는 것 같다.)
I also struggled with the same problem. The reason NOT_REQUIRED is always returned is that the test device ID has not been registered. DebugGeography does not apply to non-test devices. In my case, even if it is a basic Android emulator, I had to register the test device ID to resolve this issue. Your emulator's device ID is displayed in logcat as follows when ConsentInformation.requestConsentInfoUpdate is called.
Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("xxxxxxxxx") to set this as a debug device.
EDIT: I did more tests. It requires a test device ID since Android API 30. Until API 29, it is not necessary to specify the test device ID. I'm not sure if this is only for my development environment.
[참조] https://stackoverflow.com/questions/68529268/ump-consentstatus-always-notrequired-when-testing
[GoogleMobileAdsManager에 추가된 GDPR/IDFA(ATT) 관련 UMP 소스]
using GoogleMobileAds.Ump.Api;
#region UMP(User Messaging Platform)
/// <summary>
/// Privacy(GDPR) 요청
/// Ensures that privacy and consent information is up to date.
/// </summary>
public void InitializeGoogleMobileAdsConsent()
{
// Test GDPR
//GDPRDebugger();
RequestConsentInfo();
}
///Summary
///Request Consent Information
///Warning: Ads can be preloaded by the Google Mobile Ads SDK or mediation partner SDKs
///upon calling MobileAds.Initialize(). If you need to obtain consent from users in the European Economic Area (EEA), set any request-specific flags, such as tagForChildDirectedTreatment or tag_for_under_age_of_consent, or otherwise take action before loading ads.
///Ensure you do this before initializing the Google Mobile Ads SDK.
///Summary
void RequestConsentInfo()
{
Debug.Log("[UMP] RequestConsentInfo()");
// Set tag for under age of consent.
// Here false means users are not under age of consent.
ConsentRequestParameters request = new ConsentRequestParameters
{
TagForUnderAgeOfConsent = false,
//ConsentDebugSettings = new ConsentDebugSettings
//{
// // For debugging consent settings by geography.
// DebugGeography = DebugGeography.Disabled,
// // https://developers.google.com/admob/unity/test-ads
// TestDeviceHashedIds = TestDeviceIds,
//}
};
// Check the current consent information status.
ConsentInformation.Update(request, OnConsentInfoUpdated);
}
void OnConsentInfoUpdated(FormError consentError)
{
if (consentError != null)
{
// Handle the error.
UnityEngine.Debug.LogErrorFormat("[UMP][OnConsentInfoUpdated] {0}", consentError);
// UMP 동의 Error 시에도 초기화 진행[blueasa / 2024-03-15]
InitializeGoogleMobileAds();
return;
}
else
{
UnityEngine.Debug.LogFormat("Google Mobile Ads consent updated: {0}", ConsentInformation.ConsentStatus);
}
// If the error is null, the consent information state was updated.
// You are now ready to check if a form is available.
ConsentForm.LoadAndShowConsentFormIfRequired((FormError formError) =>
{
if (formError != null)
{
// Consent gathering failed.
UnityEngine.Debug.LogErrorFormat("[UMP][LoadAndShowConsentFormIfRequired] {0}", consentError);
// UMP 동의 Error 시에도 초기화 진행[blueasa / 2024-03-15]
InitializeGoogleMobileAds();
return;
}
// Consent has been gathered.
if (ConsentInformation.CanRequestAds())
{
// UMP 동의 이후 GoogleMobileAds 초기화[blueasa / 2023-12-14]
InitializeGoogleMobileAds();
}
});
}
/// <summary>
/// Privacy(GDPR) Button 활성화 여부 체크
/// (설정 창에 버튼 추가함)
/// </summary>
public bool CheckActivePrivacyButton()
{
bool bActive = false;
// EU인지 여부에 따라 버튼 활성화 체크 필요
#region ConsentInformation.PrivacyOptionsRequirementStatus && AuthorizationTrackingStatus
bActive = IsPrivacyOptionsRequirement() && IsAuthorizationTracking(); // Privacy && ATT 동의 체크
//bActive = IsPrivacyOptionsRequirement(); // Privacy만 체크
#endregion
#region ConsentInformation.ConsentStatus
//bActive = IsConsentForGDPR();
#endregion
return bActive;
}
/// <summary>
/// 개인정보 보호 옵션을 표시해야 하는지 여부
/// </summary>
/// <returns></returns>
public bool IsPrivacyOptionsRequirement()
{
#if UNITY_EDITOR
// [에디터] 무조건 비활성화 처리[blueasa / 2024-02-27]
return false;
#endif
// [PrivacyOptionsRequirementStatus enum 참조]
// https://developers.google.com/admob/unity/reference/namespace/google-mobile-ads/ump/api#namespace_google_mobile_ads_1_1_ump_1_1_api_1a60f41ef4f7e14d5ae1fb5f23b7e0244b
//public enum PrivacyOptionsRequirementStatus
//{
// Unknown,
// NotRequired,
// Required
//}
bool bIsPrivacyOptionsRequirement = false;
// 개인정보 보호 옵션을 표시해야 하는지 여부
switch (ConsentInformation.PrivacyOptionsRequirementStatus)
{
// 개인정보 보호 옵션이 표시되어야 함.
case PrivacyOptionsRequirementStatus.Required:
bIsPrivacyOptionsRequirement = true;
break;
// 개인정보 보호 옵션은 표시할 필요가 없음.
case PrivacyOptionsRequirementStatus.NotRequired:
bIsPrivacyOptionsRequirement = false;
break;
// 개인 정보 보호 옵션 요구 사항 상태를 알 수 없음.
case PrivacyOptionsRequirementStatus.Unknown:
bIsPrivacyOptionsRequirement = false;
break;
default:
bIsPrivacyOptionsRequirement = false;
break;
}
Debug.LogWarningFormat("[PrivacyOptionsRequirementStatus] {0}", ConsentInformation.PrivacyOptionsRequirementStatus);
return bIsPrivacyOptionsRequirement;
}
public bool IsConsentForGDPR()
{
// [ConsentStatus enum 참조]
// https://developers.google.com/admob/unity/reference/namespace/google-mobile-ads/ump/api#namespace_google_mobile_ads_1_1_ump_1_1_api_1aa83ad2ecf6f2a08c584b60cef06f5133
//ConsentStatus
//{
// Unknown = 0, // Unknown consent status.
// NotRequired = 1, // Consent not required.
// Required = 2, // User consent required but not yet obtained.
// Obtained = 3 // User consent obtained, personalized vs non-personalized undefined.
//}
bool bIsConsentForGDPR = false;
switch (ConsentInformation.ConsentStatus)
{
case ConsentStatus.Unknown: // 동의 상태를 알 수 없습니다.
case ConsentStatus.Required: // 사용자 동의가 필요하지만 아직 획득되지 않았습니다.
case ConsentStatus.NotRequired: // 동의가 필요하지 않습니다.
bIsConsentForGDPR = false;
break;
case ConsentStatus.Obtained: // 사용자 동의 획득, 개인화 및 비개인화 정의되지 않음.
bIsConsentForGDPR = true;
break;
}
Debug.LogWarningFormat("[ConsentStatus] {0}", ConsentInformation.ConsentStatus);
return bIsConsentForGDPR;
}
bool HasConsentFor(string strKey)
{
// Example value: "1111111111"
string strPurpose = ApplicationPreferences.GetString(strKey);
// Purposes are zero-indexed. Index 0 contains information about Purpose 1.
if (!string.IsNullOrEmpty(strPurpose))
{
char cOneString = strPurpose[0];
bool bHasConsentForOne = (cOneString == '1');
return bHasConsentForOne;
}
return false;
}
/// <summary>
/// Consent For GDPR
/// </summary>
/// <returns></returns>
public bool HasConsentForPurpose()
{
return HasConsentFor("IABTCF_PurposeConsents");
//// Example value: "1111111111"
//string purposeConsents = ApplicationPreferences.GetString("IABTCF_PurposeConsents");
//// Purposes are zero-indexed. Index 0 contains information about Purpose 1.
//if (!string.IsNullOrEmpty(purposeConsents))
//{
// char purposeOneString = purposeConsents[0];
// bool hasConsentForPurposeOne = (purposeOneString == '1');
// return hasConsentForPurposeOne;
//}
//return false;
}
/// <summary>
/// Consent For Ads Personalization
/// https://stackoverflow.com/questions/69307205/mandatory-consent-for-admob-user-messaging-platform
/// </summary>
/// <returns></returns>
public bool HasConsentForVendor()
{
return HasConsentFor("IABTCF_VendorConsents");
//// Example value: "1111111111"
//string vendorConsents = ApplicationPreferences.GetString("IABTCF_VendorConsents");
//// Purposes are zero-indexed. Index 0 contains information about Purpose 1.
//if (!string.IsNullOrEmpty(vendorConsents))
//{
// char purposeOneString = vendorConsents[0];
// bool hasConsentForVendorOne = (purposeOneString == '1');
// return hasConsentForVendorOne;
//}
//return false;
}
/// <summary>
/// Privacy(GDPR) Button 클릭해서 GDPR 동의 창 띄우기
/// </summary>
public void OnClickPrivacyButton()
{
UpdatePrivacyButton();
}
void PrivacyButton()
{
//// Enable the privacy settings button.
//if (_privacyButton != null)
//{
// _privacyButton.onClick.AddListener(UpdatePrivacyButton);
// // Disable the privacy settings button by default.
// _privacyButton.interactable = false;
//}
}
private void UpdatePrivacyButton()
{
// Logic for updating privacy options
ShowPrivacyOptionsForm(); // You might want to call your method to show the privacy options form here
Debug.LogFormat("[UMP][UpdatePrivacyButton] Privacy button clicked!");
}
/// <summary>
/// Shows the privacy options form to the user.
/// </summary>
public void ShowPrivacyOptionsForm()
{
Debug.Log("[UMP] Showing privacy options form.");
// PrivacyOptionsForm 무조건 팝업으로 변경[blueasa / 2023-12-14]
ConsentForm.ShowPrivacyOptionsForm((FormError showError) =>
//ConsentForm.LoadAndShowConsentFormIfRequired((FormError showError) =>
{
if (showError != null)
{
Debug.LogErrorFormat("[UMP][LoadAndShowConsentFormIfRequired] Error showing privacy options form with error: {0}", showError.Message);
}
else
{
// 버튼 상태 갱신(필요하면)
// Enable the privacy settings button.
//if (_privacyButton != null)
//{
// _privacyButton.interactable =
// ConsentInformation.PrivacyOptionsRequirementStatus ==
// PrivacyOptionsRequirementStatus.Required;
//}
}
});
}
void GDPRDebugger()
{
Debug.Log("[UMP] GDPRDebugger()");
///Summary
///Use this for debugging
///
// Define the test device ID for debugging
string testDeviceHashedId = "0B030C0B27FA3A0A7FCF5766D3BBBA1A"; // Replace with your actual test device ID
// Create debug settings for consent testing
var debugSettings = new ConsentDebugSettings
{
TestDeviceHashedIds = new List<string>
{
testDeviceHashedId
}
};
// Set the debug geography for testing in the EEA
debugSettings.DebugGeography = DebugGeography.EEA;
Debug.Log("[UMP] GDPRDebugger Set : DebugGeography.EEA");
// Set tag for under the age of consent.
// Here false means users are not under the age of consent.
ConsentRequestParameters request = new ConsentRequestParameters
{
TagForUnderAgeOfConsent = false,
ConsentDebugSettings = debugSettings,
};
// Check the current consent information status.
ConsentInformation.Update(request, OnConsentInfoUpdated);
}
/// <summary>
/// Request ATT(IDFA)
/// [Package] iOS 14 Advertising Support v1.0.0
/// </summary>
public void RequestAuthorizationTracking()
{
#if UNITY_IOS
Debug.Log("Unity iOS Support: Requesting iOS App Tracking Transparency native dialog.");
var status = Unity.Advertisement.IosSupport.ATTrackingStatusBinding.GetAuthorizationTrackingStatus();
Debug.LogWarningFormat("[RequestAuthorizationTracking-AuthorizationTrackingStatus] {0}", status);
// 결정되지 않은 상태일 때만 체크 및 요청
if (status == Unity.Advertisement.IosSupport.ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED)
{
bool bNeedRequest = false;
if (false == CurrentGDPR.IsGDPR())
{
// [Non EEA] ATT 동의 요청
bNeedRequest = true;
}
else
{
// [EEA]
if (true == CurrentGDPR.IsPurposeConsents())
{
// [GDPR 동의] ATT 동의 요청
bNeedRequest = true;
}
else
{
// [GDPR 비동의] ATT 동의 체크가 필요없음
bNeedRequest = false;
}
}
// ATT 동의 요청 필요
if (true == bNeedRequest)
{
Unity.Advertisement.IosSupport.ATTrackingStatusBinding.RequestAuthorizationTracking();
}
}
#else
Debug.LogWarning("Unity iOS Support: Tried to request iOS App Tracking Transparency native dialog, " +
"but the current platform is not iOS.");
#endif
}
/// <summary>
/// ATT 동의 여부
/// </summary>
/// <returns>동의 여부</returns>
public bool IsAuthorizationTracking()
{
#if UNITY_IOS
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
var status = Unity.Advertisement.IosSupport.ATTrackingStatusBinding.GetAuthorizationTrackingStatus();
Debug.LogWarningFormat("[AuthorizationTrackingStatus] {0}", status);
switch(status)
{
case Unity.Advertisement.IosSupport.ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED: // 결정되지 않음
case Unity.Advertisement.IosSupport.ATTrackingStatusBinding.AuthorizationTrackingStatus.RESTRICTED: // 액세스 권한이 제한된 상태
case Unity.Advertisement.IosSupport.ATTrackingStatusBinding.AuthorizationTrackingStatus.DENIED: // 거부됨
return false;
case Unity.Advertisement.IosSupport.ATTrackingStatusBinding.AuthorizationTrackingStatus.AUTHORIZED: // 동의함
return true;
}
}
#endif
return false;
}
#endregion
[CurrentGDPR.cs]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using GoogleMobileAds.Api;
public static class CurrentGDPR
{
private static bool _isGdprOn;
private static string _purposeConsent, _vendorConsent, _vendorLi, _purposeLi, _partnerConsent;
static CurrentGDPR()
{
// 원하는 시점에 Init하도록 변경[blueasa / 2024-03-21]
//InitData();
}
public static void InitData()
{
int gdprNum = 0;
// IABTCF_* 관련 항목 설명
// [참조] https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details
// GoogleMobileAds 8.7.0에서 ApplicationPreferences 추가됨
// [참고] https://stackoverflow.com/questions/77838024/admob-gdpr-ump-issue-empty-iab-tcf-strings-on-android-after-user-consent
// [참고] https://developers.google.com/admob/android/privacy/gdpr?hl=ko
gdprNum = ApplicationPreferences.GetInt("IABTCF_gdprApplies");
_purposeConsent = ApplicationPreferences.GetString("IABTCF_PurposeConsents");
_vendorConsent = ApplicationPreferences.GetString("IABTCF_VendorConsents");
_vendorLi = ApplicationPreferences.GetString("IABTCF_VendorLegitimateInterests");
_purposeLi = ApplicationPreferences.GetString("IABTCF_PurposeLegitimateInterests");
_partnerConsent = ApplicationPreferences.GetString("IABTCF_AddtlConsent");
#region GoogleMobileAds 8.6.0 이전 버전
//#if UNITY_EDITOR // 에디터에서는 자바 호출이 에러나서 에외처리
// gdprNum = 1;
// _purposeConsent = "0000000000";
// _vendorConsent = "0000000000";
// _vendorLi = "";
// _purposeLi = "";
// _partnerConsent = "";
//#elif UNITY_ANDROID
// AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
// AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
// AndroidJavaClass preferenceManagerClass = new AndroidJavaClass("android.preference.PreferenceManager");
// AndroidJavaObject sharedPreferences =
// preferenceManagerClass.CallStatic<AndroidJavaObject>("getDefaultSharedPreferences", currentActivity);
// gdprNum = sharedPreferences.Call<int>("getInt", "IABTCF_gdprApplies", 0);
// _purposeConsent = sharedPreferences.Call<string>("getString", "IABTCF_PurposeConsents", "");
// _vendorConsent = sharedPreferences.Call<string>("getString", "IABTCF_VendorConsents", "");
// _vendorLi = sharedPreferences.Call<string>("getString", "IABTCF_VendorLegitimateInterests", "");
// _purposeLi = sharedPreferences.Call<string>("getString", "IABTCF_PurposeLegitimateInterests", "");
// _partnerConsent = sharedPreferences.Call<string>("getString", "IABTCF_AddtlConsent", "");
//#elif UNITY_IOS
// gdprNum = PlayerPrefs.GetInt("IABTCF_gdprApplies", 0);
// _purposeConsent = PlayerPrefs.GetString("IABTCF_PurposeConsents", "");
// _vendorConsent = PlayerPrefs.GetString("IABTCF_VendorConsents", "");
// _vendorLi = PlayerPrefs.GetString("IABTCF_VendorLegitimateInterests", "");
// _purposeLi = PlayerPrefs.GetString("IABTCF_PurposeLegitimateInterests", "");
// _partnerConsent = PlayerPrefs.GetString("IABTCF_AddtlConsent", "");
//#endif
#endregion
// 0 이면 아예 GDPR 대상이 아님. 1이어야 GDPR
if (gdprNum == 1)
_isGdprOn = true;
else
_isGdprOn = false;
Debug.Log("GDPR을 띄우는가? " + _isGdprOn);
Debug.Log("광고에 필요한 권한 동의: " + _purposeConsent);
Debug.Log("광고에 필요한 적법관심(광고 개인화?) 동의: " + _vendorConsent);
Debug.Log("구글에 동의처리가 되어있는가?: " + _vendorLi);
Debug.Log("구글에 적법관심(광고 개인화?) 처리 여부: " + _purposeLi);
Debug.Log("파트너 네트워크 여부: " + _partnerConsent);
}
/// <summary>
/// GDPR을 띄워야 할 유저인지(EEA = 유럽 + 영국) 리턴
/// </summary>
/// <returns>EEA 여부</returns>
public static bool IsGDPR()
{
return _isGdprOn;
}
/// <summary>
/// 광고에 필요한 권한 동의 여부
/// </summary>
/// <returns>동의 여부</returns>
public static bool IsPurposeConsents()
{
// Example value:
// 동의 : "1111111111"
// 비동의 : "0"
if (true == string.IsNullOrEmpty(_purposeConsent))
{
return false;
}
Debug.LogFormat("[IsPurposeConsents] {0}", HasAttribute(_purposeConsent, 1));
// Purposes are zero-indexed. Index 0 contains information about Purpose 1.
// _purposeConsent[0]에 1(동의)이 있는지 체크
return HasAttribute(_purposeConsent, 1);
}
/// <summary>
/// 광고에 필요한 적법관심(광고 개인화?) 동의 여부
/// </summary>
/// <returns>동의 여부</returns>
public static bool IsVendorConsents()
{
if (true == string.IsNullOrEmpty(_vendorConsent))
{
return false;
}
// _vendorConsent[0]에 1(동의)이 있는지 체크
return HasAttribute(_vendorConsent, 1);
}
// 광고가 보여지는지 여부 리턴
public static bool CanAdShow()
{
int googleId = 755;
bool hasGoogleVendorConsent = HasAttribute(_vendorConsent, googleId);
bool hasGoogleVendorLi = HasAttribute(_vendorLi, googleId);
// 광고 가능 - 비개인화 광고
// return HasConsentFor(new List<int> { 1 }, _purposeConsent, hasGoogleVendorConsent)
// && HasConsentOrLegitimateInterestFor(new List<int> { 2, 7, 9, 10 },
// _purposeConsent, _purposeLi, hasGoogleVendorConsent, hasGoogleVendorLi);
// 광고 가능 - 제한적인 광고 - 1에 대한 권한이 없어도 됨 ㅇㅇ
return HasConsentOrLegitimateInterestFor(new List<int> { 2, 7, 9, 10 },
_purposeConsent, _purposeLi, hasGoogleVendorConsent, hasGoogleVendorLi);
}
// 개인화 광고가 보여지는지 여부 리턴
public static bool CanShowPersonalizedAds()
{
int googleId = 755;
bool hasGoogleVendorConsent = HasAttribute(_vendorConsent, googleId);
bool hasGoogleVendorLi = HasAttribute(_vendorLi, googleId);
return HasConsentFor(new List<int> { 1, 3, 4 }, _purposeConsent, hasGoogleVendorConsent)
&& HasConsentOrLegitimateInterestFor(new List<int> { 2, 7, 9, 10 },
_purposeConsent, _purposeLi, hasGoogleVendorConsent, hasGoogleVendorLi);
}
public static bool IsPartnerConsent(string partnerID) // 파트너 권한 있는지 확인
{
return _partnerConsent.Contains(partnerID);
}
// 이진 문자열의 "index" 위치에 "1"이 있는지 확인합니다(1 기반).
private static bool HasAttribute(string input, int index)
{
// null 예외처리[blueasa / 2024-03-21]
if(true == string.IsNullOrEmpty(input) || (input.Length <= index))
return false;
return (input[index - 1] == '1');
}
// 목적 목록에 대한 동의가 주어졌는지 확인합니다.
private static bool HasConsentFor(List<int> purposes, string purposeConsent, bool hasVendorConsent)
{
return purposes.All(p => HasAttribute(purposeConsent, p)) && hasVendorConsent;
}
// 목적 목록에 대한 공급자의 동의 또는 정당한 이익이 있는지 확인합니다.
private static bool HasConsentOrLegitimateInterestFor(List<int> purposes, string purposeConsent, string purposeLI, bool hasVendorConsent, bool hasVendorLI)
{
return purposes.All(p =>
(HasAttribute(purposeLI, p) && hasVendorLI) ||
(HasAttribute(purposeConsent, p) && hasVendorConsent));
}
}
[참조] https://docs.adxcorp.kr/appendix/ump-user-messaging-platform
[사용자 메시지 플랫폼(UMP) Doc] https://developers.google.com/admob/unity/privacy?hl=ko
[GoogleMobileAds.Ump.Api Doc] https://developers.google.com/admob/unity/reference/namespace/google-mobile-ads/ump/api
[GitHub/Sample] https://github.com/googleads/googleads-mobile-unity
'Unity3D > Ad' 카테고리의 다른 글
[GoogleMoblieAds] GDPR/Ads Personalization 동의 여부 확인 방법 (0) | 2024.02.23 |
---|---|
[펌] GDPR에 대해 알아보자 (Feat 애드몹) (0) | 2024.02.23 |
[Error] Build iOS failed: Undefined symbols for architecture arm64: "_GADURequestInterstitial" (2) | 2021.05.26 |
[링크] Very Simple Ads Monetization & Mediation (0) | 2018.01.08 |
[링크] [Unity3D] Google AdMob 연동하기 (0) | 2018.01.08 |