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.
using GoogleMobileAds.Ump.Api;
#region UMP(User Messaging Platform)
/// <summary>
/// Privacy(GDPR) 요청
/// </summary>
public void Request_Privacy_GDPR()
{
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,
};
// 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;
}
// 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]
// GDPR 동의 했거나, EU가 아니어도 호출되기 때문에 여기서 초기화 함.
InitGoogleMobileAds();
}
});
}
/// <summary>
/// Privacy(GDPR) Button 활성화 여부 체크
/// (설정 창에 버튼 추가함)
/// </summary>
public bool CheckActivePrivacyButton()
{
bool bActive = false;
// EU인지 여부에 따라 버튼 활성화 체크 필요
#region ConsentInformation.PrivacyOptionsRequirementStatus
bActive = IsPrivacyOptionsRequirement();
#endregion
#region ConsentInformation.ConsentStatus
//bActive = IsConsentForGDPR();
#endregion
return bActive;
}
public bool IsPrivacyOptionsRequirement()
{
// [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;
}
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;
}
return bIsConsentForGDPR;
}
/// <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);
}
#endregion
WARNING:/Users/{UserAccount}/.gradle/caches/transforms-2/files-2.1/ea30c3c071cd48c926311878c13eb08b/jetified-unity-classes.jar: D8: Expected stack map table for method with non-linear control flow.
그래서 아래 위치의 gradle cache 하위 있는 것들을 모두 삭제하고 새로 빌드를 실행해서 잘 돌아가는 것을 확인했다.
I used thepostin the 'EDIT 2' to come up with a decent solution. I don't know if it will work 100% of the time and I would love for someone to correct me if I have chosen a poor solution. This should allow me to run code before the build starts, and if the build fails or succeeds without changing the unity build pipeline.
class CustomBuildPipeline : MonoBehaviour, IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder => 0;
// CALLED BEFORE THE BUILD
public void OnPreprocessBuild(BuildReport report)
{
// Start listening for errors when build starts
Application.logMessageReceived += OnBuildError;
}
// CALLED DURING BUILD TO CHECK FOR ERRORS
private void OnBuildError(string condition, string stacktrace, LogType type)
{
if (type == LogType.Error)
{
// FAILED TO BUILD, STOP LISTENING FOR ERRORS
Application.logMessageReceived -= OnBuildError;
}
}
// CALLED AFTER THE BUILD
public void OnPostprocessBuild(BuildReport report)
{
// IF BUILD FINISHED AND SUCCEEDED, STOP LOOKING FOR ERRORS
Application.logMessageReceived -= OnBuildError;
}
}
With recent Unity versions (2020, 2021 and 2022) Flutter Android builds will take a lot longer, because it also has to compile the IL2CPP code from Unity.
From the Readme:
Android builds takes forever to complete Unity 2022.1.*, remove these lines from unityLibrary/build.gradle filecommandLineArgs.add("--enable-debugger") commandLineArgs.add("--profiler-report") commandLineArgs.add("--profiler-output-file=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_conv.traceevents")
Here is some testing to check how to speed things up.
Or C#EditorUserBuildSettings.il2CppCodeGeneration = UnityEditor.Build.Il2CppCodeGeneration.OptimizeSize;
C++ compiler configuration
InPlayer settings -> Other settings -> configuration, selectDebug.
Or C#PlayerSettings.SetIl2CppCompilerConfiguration(BuildTargetGroup.Android, Il2CppCompilerConfiguration.Debug);
Disable script debugging
Don't bother setting this in the Unity settings, it will be overridden by the build script. Assets/FlutterUnityIntegration/Editor/build.cs In the functionDoBuildAndroid()remove the line enabling script debugging. playerOptions.options = BuildOptions.AllowDebugging; This is the same as removingcommandLineArgs.add("--enable-debugger")from the build.gradle file after an export.
Measuring results
When you run a Flutter build, there are multiple IL2CPP stages that report their duration, with 2 sections taking far longer than all others. We can compare these build durations when using different settings in Unity.
The exact durations here aren't important, as this will be different of every computer and project setup. This is afterflutter cleanand a fresh Unity export. Any subsequent runs will be faster because of caching.
Flutter build apk, with an export from Unity 2021.3.5f1 inandroid/unityLibraryon Windows 10.
Settingarmv7 durationarm64 duration
example project
2m:04s
2m:03s
1 - Code generation (faster builds)
1m:41s
1m:38s
2 - Compiler configuration (debug)
45s
43s
3 - No script debugging
30s
30s
1 + 2
35s
34s
1 + 2 + 3
23s
25s
Conclusion
My advice is to add this to the build script inDoBuildAndroid()for any test or debug builds, remove it for final release builds.