update: 更新 ReadMe 文档

deeplink
胡宇飞 2024-03-06 17:43:55 +08:00
parent 6023017cc9
commit fa06ab3f87
8 changed files with 555 additions and 17 deletions

View File

@ -1,5 +1,4 @@
namespace Guru.Editor
{
using UnityEngine;
@ -12,6 +11,9 @@ namespace Guru.Editor
public class AppBuildParam
{
public const string TargetNameAndroid = "Android";
public const string TargetNameIOS = "iOS";
//------------ Basic ----------------
public bool IsBuildRelease; // 是否构建发布包体
public bool IsBuildShowLog; // 是否显示日志
@ -19,6 +21,7 @@ namespace Guru.Editor
public string BuildVersion = ""; // 构建版本号, 填写后会依据此版本设置应用的 Version
public bool AutoSetBuildNumber = true; // 自动设置构建号, 可参考 Guru的SDK 接入说明文档
public bool UseGuruCerts = true; // 是否使用 Guru 的证书打包
public string TargetName = "";
//------------ Android ----------------
public bool IsBuildAAB; // 是否构建 AAB 包体 ( GooglePlay 发布专用 )
public bool IsBuildSymbols = false; // 是否需要构建 Symbols.zip 文件 ( GooglePlay 发布专用 )
@ -38,13 +41,14 @@ namespace Guru.Editor
}
public static AppBuildParam Build(bool isRelease, AppBuilderType builderType = AppBuilderType.Editor, string version = "", bool autoBuildNumber = true, string companyName = "",
bool buildShowLog = false, bool useGuruCerts = true,
public static AppBuildParam Build(bool isRelease, AppBuilderType builderType = AppBuilderType.Editor, string version = "", bool autoBuildNumber = true, string companyName = "",
string targetName = "", bool buildShowLog = false, bool useGuruCerts = true,
bool buildSymbols = false, bool buildAAB = false, bool useMinify = false, int androidTargetVersion = 0, bool debugWithMono = true,
string iOSTargetVersion = "", string iOSTeamId = "")
{
return new AppBuildParam()
{
TargetName = targetName,
IsBuildRelease = isRelease,
IsBuildShowLog = buildShowLog,
BuilderType = builderType,
@ -76,13 +80,15 @@ namespace Guru.Editor
/// <param name="androidTargetVersion"></param>
/// <param name="debugWithMono"></param>
/// <returns></returns>
public static AppBuildParam AndroidParam(bool isRelease, string version = "", bool autoBuildNumber = true, AppBuilderType builderType = AppBuilderType.Editor,
public static AppBuildParam AndroidParam(bool isRelease, string version = "", bool autoBuildNumber = true,
AppBuilderType builderType = AppBuilderType.Editor,
string companyName = "", bool useGuruCerts = true, bool useMinify = false, int androidTargetVersion = 0, bool debugWithMono = true)
{
bool buildAAB = isRelease;
bool buildShowLog = isRelease;
bool buildSymbols = isRelease;
return Build(isRelease, builderType, version, autoBuildNumber,companyName, buildShowLog, useGuruCerts, buildSymbols, buildAAB, useMinify, androidTargetVersion, debugWithMono);
string targetName = TargetNameAndroid;
return Build(isRelease, builderType, version, autoBuildNumber,companyName, targetName, buildShowLog, useGuruCerts, buildSymbols, buildAAB, useMinify, androidTargetVersion, debugWithMono);
}
@ -102,7 +108,8 @@ namespace Guru.Editor
string companyName = "", bool useGuruCerts = true, string iOSTargetVersion = "", string iOSTeamId = "" )
{
bool buildShowLog = isRelease;
return Build(isRelease, builderType, version, autoBuildNumber, companyName, buildShowLog, useGuruCerts, iOSTargetVersion:iOSTargetVersion, iOSTeamId:iOSTeamId);
string targetName = TargetNameIOS;
return Build(isRelease, builderType, version, autoBuildNumber, companyName, targetName, buildShowLog, useGuruCerts, iOSTargetVersion:iOSTargetVersion, iOSTeamId:iOSTeamId);
}
}

View File

@ -21,6 +21,38 @@ namespace Guru.Editor
public static string KeystorePath => Application.dataPath + $"/Plugins/Android/{KeystoreName}";
public static string ProguardName => $"proguard-user.txt";
public static string ProguardPath => Application.dataPath + $"/Plugins/Android/{ProguardName}";
public static string OutputDirName => "BuildOutput";
#region 构建接口
/// <summary>
/// 直接调用 Build 接口
/// </summary>
/// <param name="buildParam"></param>
/// <returns></returns>
public static string Build(AppBuildParam buildParam)
{
string outputPath = string.Empty;
switch (buildParam.TargetName)
{
case AppBuildParam.TargetNameAndroid:
SwitchBuildPlatform(BuildTarget.Android);
outputPath = BuildAndroid(buildParam);
break;
case AppBuildParam.TargetNameIOS:
SwitchBuildPlatform(BuildTarget.iOS);
outputPath = BuildIOS(buildParam);
break;
default:
Debug.Log($"<color=red> Unsupported build target: {buildParam.TargetName}. Skip build...</color>");
break;
}
return outputPath;
}
#endregion
#region 构建 Android 接口
@ -32,7 +64,7 @@ namespace Guru.Editor
public static string BuildAndroid(AppBuildParam buildParam)
{
//切换平台
BuildSwitchPlatform(BuildTarget.Android);
SwitchBuildPlatform(BuildTarget.Android);
//打包通用设置
ChangeBuildPlayerCommonSetting(buildParam, BuildTargetGroup.Android);
@ -77,7 +109,7 @@ namespace Guru.Editor
string version = Application.version;
string extension = buildParam.IsBuildAAB ? ".aab" : ".apk";
if (EditorUserBuildSettings.exportAsGoogleAndroidProject) extension = ""; // 输出工程
string outputDir = Path.GetFullPath($"{Application.dataPath }/../BuildOutput/Android");
string outputDir = Path.GetFullPath($"{Application.dataPath }/../{OutputDirName}/Android");
apkPath = $"{outputDir}/{Application.productName.Replace(" ","_")}_{symbolDefine}_{version}_{buildNumber}{extension}";
if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
@ -136,10 +168,10 @@ namespace Guru.Editor
#region 构建 IOS 接口
public static void BuildIOS(AppBuildParam buildParam)
public static string BuildIOS(AppBuildParam buildParam)
{
//切换平台
BuildSwitchPlatform(BuildTarget.iOS);
SwitchBuildPlatform(BuildTarget.iOS);
//打包通用设置
ChangeBuildPlayerCommonSetting(buildParam, BuildTargetGroup.iOS);
@ -169,26 +201,28 @@ namespace Guru.Editor
}
//打包
string xcodePath = Application.dataPath + "/../../xcode";
if (Directory.Exists(xcodePath))
string outputDir = Path.GetFullPath($"{Application.dataPath }/../{OutputDirName}/Xcode");
if (Directory.Exists(outputDir))
{
Directory.Delete(xcodePath, true);
Directory.Delete(outputDir, true);
}
// 构建后打开路径
try
{
BuildOptions opts = isDebug ? BuildOptions.Development : BuildOptions.None;
BuildPipeline.BuildPlayer(GetBuildScenes(), xcodePath, BuildTarget.iOS, BuildOptions.None);
BuildPipeline.BuildPlayer(GetBuildScenes(), outputDir, BuildTarget.iOS, BuildOptions.None);
if (buildParam.BuilderType == AppBuilderType.Editor)
{
Open(xcodePath);
Open(outputDir);
}
}
catch (Exception e)
{
Debug.LogError(e.Message);
}
return outputDir;
}
#endregion
@ -221,7 +255,7 @@ namespace Guru.Editor
/// 平台切换
/// </summary>
/// <param name="targetPlatform"></param>
private static void BuildSwitchPlatform(BuildTarget targetPlatform)
private static void SwitchBuildPlatform(BuildTarget targetPlatform)
{
if (EditorUserBuildSettings.activeBuildTarget != targetPlatform)
{

View File

@ -0,0 +1,328 @@
namespace Guru.Editor
{
using System.IO;
using UnityEditor;
using UnityEngine;
using System;
public class PgyerAPI
{
public const string Version = "1.0.0";
internal static readonly string DefaultBashPathWin = "C:\\Program Files\\Git\\bin\\bash.exe";
internal static readonly string DefaultBashPathMac = "/bin/bash";
internal static readonly string ShellFile = "pgyer_upload.sh";
private static readonly string GuruAPIKey = "20a3d1106b802abbd84ec687eedf17eb";
private static readonly string PgyerHost = "https://www.pgyer.com";
internal static string WorkingDir => $"{Application.dataPath.Replace("Assets", "Library")}/guru_publish";
public static string GetDownloadUrl(string shortUrl) => $"{PgyerHost}/{shortUrl}";
/// <summary>
/// 发布产品到蒲公英平台
/// </summary>
/// <param name="packagePath"></param>
/// <param name="apiKey"></param>
/// <param name="bashPath"></param>
/// <param name="callback"></param>
public static void PublishToPgyer(string packagePath, string apiKey = "", string bashPath = "",
Action<string> callback = null)
{
if (File.Exists(packagePath))
{
Debug.Log($"=== START PUBLISH APP: {packagePath}");
CheckWorkingDir();
CallPublishShell(packagePath, apiKey, bashPath, callback);
}
}
private static void CheckWorkingDir()
{
if (!Directory.Exists(WorkingDir))
{
Directory.CreateDirectory(WorkingDir);
}
var file = $"{WorkingDir}/{ShellFile}";
if (!File.Exists(file))
{
var from = GetShellPath();
if (File.Exists(from))
{
File.Copy(from, file);
#if UNITY_EDITOR_OSX
RunCmd("chmod", $"+x {file}", workpath: WorkingDir);
#endif
}
else
{
Debug.LogError($"[Publisher] Source shell file not found :{from}");
}
}
}
/// <summary>
/// 获取 CMD 命令路径
/// </summary>
/// <returns></returns>
private static string GetShellPath()
{
var path = "";
var guids = AssetDatabase.FindAssets($"{nameof(PgyerAPI)} t:script");
if (guids.Length > 0)
{
path = Path.Combine(Directory.GetParent(AssetDatabase.GUIDToAssetPath(guids[0])).FullName, ShellFile);
return Path.GetFullPath(path);
}
path = Path.GetFullPath(
$"{Application.dataPath.Replace("Assets", "Packages")}/com.guru.unity.sdk.core/Editor/BuildTool/{ShellFile}");
return path;
}
private static void RunCmd(string cmd, string args, Action<string> callback = null, string workpath = "")
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = cmd;
process.StartInfo.Arguments = args;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
if (!string.IsNullOrEmpty(workpath)) process.StartInfo.WorkingDirectory = workpath;
process.Start();
string log = process.StandardOutput.ReadToEnd();
callback?.Invoke(log);
process.Close();
}
/// <summary>
/// 在 mac 下进行发布
/// </summary>
/// <param name="packagePath"></param>
/// <param name="apiKey"></param>
/// <param name="bashPath"></param>
/// <param name="callback"></param>
private static void CallPublishShell(string packagePath, string apiKey = "", string bashPath = "",
Action<string> callback = null)
{
if (string.IsNullOrEmpty(bashPath))
{
#if UNITY_EDITOR_OSX
bashPath = DefaultBashPathMac;
#elif UNITY_EDITOR_WIN
bashPath = DefaultBashPathWin.Replace("\\", "/");
#endif
}
if (!File.Exists(bashPath))
{
string msg = $"Error: Bash file not found at path: {bashPath}! skip publishing!";
Debug.LogError(msg);
callback?.Invoke(msg);
return;
}
packagePath = packagePath.Replace("\\", "/");
if (string.IsNullOrEmpty(apiKey)) apiKey = GuruAPIKey;
var args = $"-c \"./{ShellFile} -k {apiKey} {packagePath}\"";
// Debug.Log(bashPath);
// Debug.Log(args);
// Debug.Log(WorkingDir);
RunCmd(bashPath, args, callback, WorkingDir);
}
}
/// <summary>
/// Guru 包体上传工具
/// </summary>
public class GuruPublishHelper
{
// Check Env and Exe files
private static string EvnCheck()
{
if (!Directory.Exists(PgyerAPI.WorkingDir))
Directory.CreateDirectory(PgyerAPI.WorkingDir);
// #1 --- read from cached file with available path
string bash_path = "";
var envFile = $"{PgyerAPI.WorkingDir}/.env";
if (File.Exists(envFile))
{
bash_path = File.ReadAllText(envFile);
return bash_path;
}
// #2 --- Try to find bash exe file from default path
bash_path = PgyerAPI.DefaultBashPathMac;
#if UNITY_EDITOR_WIN
bash_path = PgyerAPI.DefaultBashPathWin;
#endif
if (File.Exists(bash_path))
{
bash_path = bash_path.Replace("\\", "/");
File.WriteAllText(envFile, bash_path);
return bash_path;
}
// #3 --- Try to let user select bash exe file from disk
string title = "选择 bash 可执行文件";
string despath = "/bin";
string exts = "*";
#if UNITY_EDITOR_WIN
despath = "C:\\Program Files\\";
title = $"选择 bash 可执行文件, 例如: {despath}\\Git\\bin\\bash.exe";
exts = "exe";
#endif
bash_path = EditorUtility.OpenFilePanel(title, despath, exts);
if (File.Exists(bash_path))
{
File.WriteAllText(envFile, bash_path.Replace("\\", "/"));
}
return bash_path;
}
[MenuItem("Guru/Publish/Android APK...")]
private static void EditorPublishAPK()
{
SelectAndPublish();
}
// [MenuItem("Guru/Publish/Publish Release AAB...")]
// private static void EditorPublishAAB()
// {
// SelectAndPublish("aab");
// }
public static void SelectAndPublish(string extension = "apk", string apiKey = "")
{
string bash_path = EvnCheck();
if (string.IsNullOrEmpty(bash_path))
{
ShowDialog("找不到 Bash 执行文件", $"Bash文件不存在: {bash_path}!");
return;
}
string file = EditorUtility.OpenFilePanel("选择包体", $"~/Downloads", extension);
if (!File.Exists(file))
{
ShowDialog("找不到包体文件", $"包体文件不存在: {file}!");
return;
}
PgyerAPI.PublishToPgyer(file, apiKey, bash_path, OnResponse);
}
/// <summary>
/// Show system dialogs
/// </summary>
/// <param name="title"></param>
/// <param name="body"></param>
/// <param name="callback"></param>
/// <param name="cancelAction"></param>
/// <param name="okName"></param>
/// <param name="cancelName"></param>
private static void ShowDialog(string title, string body, Action callback = null, Action cancelAction = null, string okName= "OK", string cancelName = "")
{
if (EditorUtility.DisplayDialog(title, body, okName, cancelName))
{
callback?.Invoke();
}
else
{
cancelAction?.Invoke();
}
}
/// <summary>
/// On pgyer response callback
/// </summary>
/// <param name="log"></param>
private static void OnResponse(string log)
{
var logPath = $"{PgyerAPI.WorkingDir}/log.txt";
File.WriteAllText(logPath, log);
bool success = log.Contains(ResponseObject.HeadTag);
if (success)
{
var json = log.Substring(log.IndexOf(ResponseObject.HeadTag, StringComparison.Ordinal));
var res = ResponseObject.Parse(json);
if (res != null)
{
ShowDialog($"==== 上传成功 ({PgyerAPI.Version}) ====", $"包体 {res.BuildVersion()} ({res.BuildVersionCode()}) 上传成功!", () =>
{
var url = PgyerAPI.GetDownloadUrl(res.ShortUrl());
Application.OpenURL(url);
});
return;
}
else
{
success = false;
}
}
ShowDialog($"==== 上传失败 ({PgyerAPI.Version}) ====", $"上传文件失败, 查看详细日志: {logPath}", () =>
{
#if UNITY_EDITOR_OSX
EditorUtility.RevealInFinder(PgyerAPI.WorkingDir);
return;
#endif
Application.OpenURL(PgyerAPI.WorkingDir);
});
}
}
[Serializable]
internal class ResponseObject
{
public int code;
public string message;
public PublishData data;
public static readonly string HeadTag = "{\"code\":";
public string BuildVersion() => data?.buildVersion ?? "0.0.0";
public string BuildVersionCode() => data?.buildVersionNo ?? "0";
public string ShortUrl() => data?.buildShortcutUrl ?? "#";
public static bool IsValid(string json)
{
return json.Contains(HeadTag);
}
public static ResponseObject Parse(string json)
{
if (string.IsNullOrEmpty(json)) return null;
if (!IsValid(json)) return null;
return JsonUtility.FromJson<ResponseObject>(json);
}
}
[Serializable]
internal class PublishData
{
public string buildIdentifier;
public string buildQRCodeURL;
public string buildShortcutUrl;
public string buildName;
public string buildVersion;
public string buildVersionNo;
public string buildUpdated;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 615e8fb3101146048570e17d27bfbb9b
timeCreated: 1709605527

147
Editor/BuildTool/pgyer_upload.sh Executable file
View File

@ -0,0 +1,147 @@
#!/bin/bash
#
# 通过shell脚本来实现将本地app文件通过API上传到蒲公英
# https://www.pgyer.com/doc/view/api#fastUploadApp
#
# Display log. 1=enable, 0=disable
LOG_ENABLE=1
printHelp() {
echo "Usage: $0 -k <api_key> [OPTION]... file"
echo "Upload iOS or Android app package file to PGYER."
echo "Example: $0 -k xxxxxxxxxxxxxxx /data/app.ipa"
echo ""
echo "Description:"
echo " -k api_key (required) api key from PGYER"
echo " -t buildInstallType build install type, 1=public, 2=password, 3=invite"
echo " -p buildPassword build password, required if buildInstallType=2"
echo " -d buildUpdateDescription build update description"
echo " -e buildInstallDate build install date, 1=buildInstallStartDate~buildInstallEndDate, 2=forever"
echo " -s buildInstallStartDate build install start date, format: yyyy-MM-dd"
echo " -e buildInstallEndDate build install end date, format: yyyy-MM-dd"
echo " -c buildChannelShortcut build channel shortcut"
echo " -h help show this help"
echo ""
echo "Report bugs to: <https://github.com/PGYER/pgyer_api_example/issues>"
echo "Project home page: <https://github.com/PGYER/pgyer_api_example>"
exit 1
}
while getopts 'k:t:p:d:s:e:c:h' OPT; do
case $OPT in
k) api_key="$OPTARG";;
t) buildInstallType="$OPTARG";;
p) buildPassword="$OPTARG";;
d) buildUpdateDescription="$OPTARG";;
e) buildInstallDate="$OPTARG";;
s) buildInstallStartDate="$OPTARG";;
e) buildInstallEndDate="$OPTARG";;
c) buildChannelShortcut="$OPTARG";;
?) printHelp;;
esac
done
shift $(($OPTIND - 1))
readonly file=$1
# check api_key exists
if [ -z "$api_key" ]; then
echo "api_key is empty"
printHelp
fi
# check file exists
if [ ! -f "$file" ]; then
echo "file not exists"
printHelp
fi
# check ext supported
buildType=${file##*.}
if [ "$buildType" != "ipa" ] && [ "$buildType" != "apk" ]; then
echo "file ext is not supported"
printHelp
fi
# ---------------------------------------------------------------
# functions
# ---------------------------------------------------------------
log() {
[ $LOG_ENABLE -eq 1 ] && echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"
}
logTitle() {
log "-------------------------------- $* --------------------------------"
}
execCommand() {
log "$@"
result=$(eval $@)
}
# ---------------------------------------------------------------
# 获取上传凭证
# ---------------------------------------------------------------
logTitle "获取凭证"
command="curl -s"
[ -n "$api_key" ] && command="${command} --form-string '_api_key=${api_key}'";
[ -n "$buildType" ] && command="${command} --form-string 'buildType=${buildType}'";
[ -n "$buildInstallType" ] && command="${command} --form-string 'buildInstallType=${buildInstallType}'";
[ -n "$buildPassword" ] && command="${command} --form-string 'buildPassword=${buildPassword}'";
[ -n "$buildUpdateDescription" ] && command="${command} --form-string $'buildUpdateDescription=${buildUpdateDescription}'";
[ -n "$buildInstallDate" ] && command="${command} --form-string 'buildInstallDate=${buildInstallDate}'";
[ -n "$buildInstallStartDate" ] && command="${command} --form-string 'buildInstallStartDate=${buildInstallStartDate}'";
[ -n "$buildInstallEndDate" ] && command="${command} --form-string 'buildInstallEndDate=${buildInstallEndDate}'";
[ -n "$buildChannelShortcut" ] && command="${command} --form-string 'buildChannelShortcut=${buildChannelShortcut}'";
command="${command} http://www.pgyer.com/apiv2/app/getCOSToken";
execCommand $command
[[ "${result}" =~ \"endpoint\":\"([\:\_\.\/\\A-Za-z0-9\-]+)\" ]] && endpoint=`echo ${BASH_REMATCH[1]} | sed 's!\\\/!/!g'`
[[ "${result}" =~ \"key\":\"([\.a-z0-9]+)\" ]] && key=`echo ${BASH_REMATCH[1]}`
[[ "${result}" =~ \"signature\":\"([\=\&\_\;A-Za-z0-9\-]+)\" ]] && signature=`echo ${BASH_REMATCH[1]}`
[[ "${result}" =~ \"x-cos-security-token\":\"([\_A-Za-z0-9\-]+)\" ]] && x_cos_security_token=`echo ${BASH_REMATCH[1]}`
if [ -z "$key" ] || [ -z "$signature" ] || [ -z "$x_cos_security_token" ] || [ -z "$endpoint" ]; then
log "get upload token failed"
exit 1
fi
# ---------------------------------------------------------------
# 上传文件
# ---------------------------------------------------------------
logTitle "上传文件"
file_name=${file##*/}
execCommand "curl -s -o /dev/null -w '%{http_code}' \
--form-string 'key=${key}' \
--form-string 'signature=${signature}' \
--form-string 'x-cos-security-token=${x_cos_security_token}' \
--form-string 'x-cos-meta-file-name=${file_name}' \
-F 'file=@${file}' ${endpoint}"
if [ $result -ne 204 ]; then # if http code != 204, upload failed
log "Upload failed"
exit 1
fi
# ---------------------------------------------------------------
# 检查结果
# ---------------------------------------------------------------
logTitle "检查结果"
for i in {1..60}; do
execCommand "curl -s http://www.pgyer.com/apiv2/app/buildInfo?_api_key=${api_key}\&buildKey=${key}"
[[ "${result}" =~ \"code\":([0-9]+) ]] && code=`echo ${BASH_REMATCH[1]}`
if [ $code -eq 0 ]; then
echo $result
break
else
sleep 1
fi
done

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 64be73b7342084dd583da03a6730370d
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,5 +1,17 @@
# Guru SDK Core
**Version 2.2.1**
- 更新 Firebase -> Unity 11.7.0 | FirebaseSDK 10.20.0 (iOS 10.22.0)
- 添加 GooglePlay DMA 合规逻辑 (2024 年 3 月 6 日之前升级即可)
- 广告渠道 Inmobi 升级 双端版本: Android 10.6.3.0 , iOS 10.6.0.0
- 广告渠道 Pubmatic iOS 平台版本指定为 3.2 修复打包报错的问题
- 更新内核的 JsonParser 解析器为 JsonConvert
- fix: 修复配置导出功能解析报错的问题
- fix: 修复 ABTestManager 的解析错误.
- fix: 修复 Tch 打点在不满足 0.01 的情况下补偿的逻辑
- fix: 修复 GuruConsent 在 iOS 上返回 Purpose 乱码的解析问题, 添加了 TCF 映射规则.
**Version 2.1.0**

View File

@ -90,7 +90,7 @@ namespace Guru
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]}");
adjustThirdPartySharing.addGranularOption("google_dma", "ad_user_data", $"{result[3]}"); // From Haoyi's advice we don't give the value so Adjust will still receive the data as a trick.
Adjust.trackThirdPartySharing(adjustThirdPartySharing);
//----------- Guru DMA report ---------------