update: 升级 GuruConsent Android 实现和构建管线

deeplink
胡宇飞 2024-02-22 16:28:58 +08:00
parent 1eef3d618c
commit a5cfdd4df6
13 changed files with 290 additions and 27 deletions

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d8070d73e560497f8869d5159003789e
timeCreated: 1708513964

View File

@ -0,0 +1,130 @@
using System.Xml;
using UnityEngine;
namespace Guru.Editor
{
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;
public class PostBuild_DMA
{
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget target, string buildPath)
{
string dir = "";
// TODO: add your code here
if (target == BuildTarget.Android)
{
dir = $"{buildPath}/src/main";
OnSetAndroidManifest(dir);
}
else if (target == BuildTarget.iOS)
{
}
}
#region Android Inject
/*--------------------------------------------------------------------------------
*
*
* AndroidManifest
* <meta-data android:name="google_analytics_default_allow_analytics_storage" android:value="true" />
* <meta-data android:name="google_analytics_default_allow_ad_storage" android:value="true" />
* <meta-data android:name="google_analytics_default_allow_ad_user_data" android:value="true" />
* <meta-data android:name="google_analytics_default_allow_ad_personalization_signals" android:value="true" />
*
*
--------------------------------------------------------------------------------*/
/// <summary>
/// 修复 AndroidManifest.xml
/// </summary>
/// <param name="dir"></param>
private static void OnSetAndroidManifest(string dir)
{
var filePath = Path.Combine(dir, "AndroidManifest.xml");
// 预注入 Key
string[] dma_keys = new string[]
{
"google_analytics_default_allow_analytics_storage",
"google_analytics_default_allow_ad_storage",
"google_analytics_default_allow_ad_user_data",
"google_analytics_default_allow_ad_personalization_signals"
};
int[] flags = new int[] { 0, 0, 0, 0 };
string defaultValue = "true"; // 日后可能会进行修改
if (File.Exists(filePath))
{
var xmlStr = File.ReadAllText(filePath);
var doc = new XmlDocument();
doc.LoadXml(xmlStr);
var root = doc.SelectSingleNode("manifest") as XmlElement;
if (root == null) return;
if (root.SelectSingleNode("application") is XmlElement app)
{
var namespace_uri = root.GetAttribute("xmlns:android");
var list = app.SelectNodes("meta-data");
// 刷新已有属性
foreach (XmlElement item in list)
{
for(int i = 0; i < dma_keys.Length; i++)
{
if (item.HasAttributes && item.GetAttribute("android:name") == dma_keys[i])
{
item.SetAttribute("value", namespace_uri, defaultValue);
flags[i] = 1;
}
}
}
// 补全缺失属性
for (int i = 0; i < flags.Length; i++)
{
if (flags[i] == 0)
{
var node = doc.CreateElement("meta-data");
node.SetAttribute("name", namespace_uri,dma_keys[i]);
node.SetAttribute("value", namespace_uri, defaultValue);
app.AppendChild(node);
}
}
doc.Save(filePath);
}
}
else
{
Debug.LogError($"[Post] can't find AndroidManifest.xml at {filePath}");
}
}
public static void Test_AndroidManifestInject()
{
OnSetAndroidManifest($"{Application.dataPath}/Plugins/Android");
}
#endregion
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ecc9ca95286d4da49f2a482f65d865dd
timeCreated: 1708513986

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7b835e3950e934b5eaa8d02c24aa5a18
guid: 3bec370c02c6448298433a674a4a6b2b
PluginImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,66 @@
namespace Guru
{
using System.Collections.Generic;
using Firebase.Analytics;
using com.adjust.sdk;
using UnityEngine;
/// <summary>
/// DMA 助手
/// </summary>
public class GoogleDMAHelper
{
/// <summary>
/// 设置 DMA 状态值
/// </summary>
/// <param name="value"></param>
public static void SetDMAStatus(string value)
{
if (string.IsNullOrEmpty(value))
{
// 非 EEA 国家不需要设置和上报 DMA
Debug.Log($"{GuruConsent.Tag} --- GoogleDMAHelper:: User is not at EEA countries");
return;
}
bool granted = false;
if(value.Length >= 4) granted = (value[0] == '1' && value[2] == '1' && value[3] == '1'); // 1,3,4 位需同时为 1 才算授权
// 根据授权填写状态值
string result = granted? "1111" : "0000";
Debug.Log($"{GuruConsent.Tag} --- GoogleDMAHelper::SetDMAStatus - status:{value} result: {result}");
//---------- Firebase 上报打点 --------------
Dictionary<ConsentType, ConsentStatus> consentSettings = new Dictionary<ConsentType, ConsentStatus>()
{
{ ConsentType.AdStorage, result[0] == '1' ? ConsentStatus.Granted : ConsentStatus.Denied },
{ ConsentType.AnalyticsStorage, result[1] == '1' ? ConsentStatus.Granted : ConsentStatus.Denied },
{ ConsentType.AdPersonalization, result[2] == '1' ? ConsentStatus.Granted : ConsentStatus.Denied },
{ ConsentType.AdUserData, result[3] == '1' ? ConsentStatus.Granted : ConsentStatus.Denied },
};
FirebaseAnalytics.SetConsent(consentSettings);
//---------- Adjust 上报打点 --------------
AdjustThirdPartySharing adjustThirdPartySharing = new AdjustThirdPartySharing(null);
adjustThirdPartySharing.addGranularOption("google_dma", "eea", "1");
adjustThirdPartySharing.addGranularOption("google_dma", "ad_personalization", $"{result[2]}");
adjustThirdPartySharing.addGranularOption("google_dma", "ad_user_data", $"{result[3]}");
Adjust.trackThirdPartySharing(adjustThirdPartySharing);
//----------- 中台打点 ---------------
Guru.Analytics.LogEvent("dma_gg", new Dictionary<string, dynamic>()
{
{"purpose", value},
{"result", result}
}, new Analytics.EventSetting()
{
EnableFirebaseAnalytics = true,
EnableFacebookAnalytics = true,
});
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 161e0f9feb4045f29c908a6aa52074c9
timeCreated: 1708514026

View File

@ -11,8 +11,8 @@ namespace Guru
public class GuruConsent
{
// Guru Consent Version
public static string Version = "1.0.3";
public static string Version = "1.0.5";
public static string Tag = "[GuruConsent]";
#region 公用接口
@ -46,6 +46,8 @@ namespace Guru
/// <param name="debugGeography"></param>
public static void StartConsent(Action<int> onComplete = null, string deviceId = "", int debugGeography = -1 )
{
Debug.Log($"{Tag} --- GuruConsent::StartConsent - deviceId: {deviceId} debugGeography: {debugGeography}");
onCompleteHandler = onComplete;
// 初始化SDK对象
GuruSDKCallback.AddCallback(OnSDKCallback);
@ -59,11 +61,15 @@ namespace Guru
/// <summary>
/// 获取SDK回调
/// </summary>
/// <param name="data"></param>
/// <param name="msg"></param>
private static void OnSDKCallback(string msg)
{
Debug.Log($"[U3D] msg: \n{msg}");
//-------- Fetch DMA status and report -----------
var dma = Agent?.GetDMAValue() ?? "";
GoogleDMAHelper.SetDMAStatus(dma);
//------- message send to unity ----------
Debug.Log($"{Tag} get callback msg:\n{msg}");
var jo = JsonMapper.ToObject(msg);
if (jo != null && jo.ContainsKey("action")
&& jo["action"].ToString() == "gdpr")
@ -73,16 +79,25 @@ namespace Guru
var data = JsonMapper.ToObject<ConsentStatus>(json);
if (data != null)
{
Debug.Log($"[GDPR] == status: {data.status} msg: {data.msg}");
Debug.Log($"{Tag} --- status: {data.status} msg: {data.msg}");
onCompleteHandler?.Invoke(data.status);
}
}
else
{
Debug.Log("[Unity] Parse callback Error");
Debug.Log($"{Tag} Parse callback Error");
}
}
/// <summary>
/// 上报异常
/// </summary>
/// <param name="ex"></param>
public static void LogException(Exception ex)
{
Analytics.LogCrashlytics(ex);
}
#endregion
#region 常量定义
@ -123,8 +138,6 @@ namespace Guru
#endregion
}

View File

@ -3,7 +3,7 @@ namespace Guru
public interface IConsentAgent
{
void Init(string objectName, string callbackName);
void RequestGDPR(string deviceId = "", int debugGeography = -1);
string GetDMAValue();
}
}

View File

@ -1,40 +1,65 @@
namespace Guru
{
using System;
using UnityEngine;
public class ConsentAgentAndroid: IConsentAgent
{
private static readonly string ConsentAndroidClassName = "com.guru.unity.consent.Consent";
private string _objName;
private string _callbackName;
#if UNITY_ANDROID
private AndroidJavaClass _javaConsentClass;
private bool _initSuccess = false;
#endif
public void Init(string objectName, string callbackName)
{
_objName = objectName;
_callbackName = callbackName;
#if UNITY_ANDROID
_initSuccess = false;
try
{
_javaConsentClass = new AndroidJavaClass(ConsentAndroidClassName);
if (_javaConsentClass != null)
{
_initSuccess = true;
// 绑定Unity回调物体
_javaConsentClass.CallStatic("initSDK", _objName, _callbackName);
}
}
catch (Exception e)
{
GuruConsent.LogException(e);
}
#endif
}
public void RequestGDPR(string deviceId = "", int debugGeography = -1)
{
#if UNITY_ANDROID
// 初始化Android SDK
using (var jc = new AndroidJavaClass("com.guru.unity.consent.Consent"))
{
// 绑定Unity回调物体
jc.CallStatic("initSDK", _objName, _callbackName);
// request gdpr
jc.CallStatic("requestGDPR", deviceId, debugGeography);
}
if (!_initSuccess) return;
// request funding choices
_javaConsentClass.CallStatic("requestGDPR", deviceId, debugGeography);
#endif
}
/// <summary>
/// 获取 DMA 字段
/// </summary>
/// <returns></returns>
public string GetDMAValue()
{
#if UNITY_ANDROID
if (!_initSuccess) return "";
return _javaConsentClass.CallStatic<string>("getDMAValue");
#endif
return "";
}
}
}

View File

@ -41,5 +41,18 @@ namespace Guru
unityRequestGDPR(deviceId, debugGeography);
#endif
}
/// <summary>
/// 获取 DMA 字段
/// </summary>
/// <returns></returns>
public string GetDMAValue()
{
#if UNITY_IOS
//TODO: ios return raw value
#endif
return "";
}
}
}

View File

@ -13,8 +13,6 @@ namespace Guru
public static string DebugMessage { get; set; } = "You have already obtained the consent.";
private static readonly string callbackMsgFmt = @"{""action"":""gdpr"", ""data"": {""status"":$0, ""msg"":""$1"" }}";
#region 接口实现
@ -44,6 +42,15 @@ namespace Guru
}
#endif
}
/// <summary>
/// 获取 DMA 字段
/// </summary>
/// <returns></returns>
public string GetDMAValue()
{
return "";
}
#endregion