update: 升级 GuruConsent Android 实现和构建管线
							parent
							
								
									1eef3d618c
								
							
						
					
					
						commit
						a5cfdd4df6
					
				|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: d8070d73e560497f8869d5159003789e | ||||
| timeCreated: 1708513964 | ||||
|  | @ -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 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: ecc9ca95286d4da49f2a482f65d865dd | ||||
| timeCreated: 1708513986 | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -1,5 +1,5 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 7b835e3950e934b5eaa8d02c24aa5a18 | ||||
| guid: 3bec370c02c6448298433a674a4a6b2b | ||||
| PluginImporter: | ||||
|   externalObjects: {} | ||||
|   serializedVersion: 2 | ||||
|  | @ -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, | ||||
|             }); | ||||
|              | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 161e0f9feb4045f29c908a6aa52074c9 | ||||
| timeCreated: 1708514026 | ||||
|  | @ -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 | ||||
|          | ||||
|          | ||||
|          | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ namespace Guru | |||
|     public interface IConsentAgent | ||||
|     { | ||||
|         void Init(string objectName, string callbackName); | ||||
|          | ||||
|         void RequestGDPR(string deviceId = "", int debugGeography = -1); | ||||
|         string GetDMAValue(); | ||||
|     } | ||||
| } | ||||
|  | @ -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 ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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 ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue