diff --git a/Editor/BuildTool/AppBuildParam.cs b/Editor/BuildTool/AppBuildParam.cs
index 3a0e7c0..b82d1a7 100644
--- a/Editor/BuildTool/AppBuildParam.cs
+++ b/Editor/BuildTool/AppBuildParam.cs
@@ -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
///
///
///
- 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);
}
}
diff --git a/Editor/BuildTool/AppBuilder.cs b/Editor/BuildTool/AppBuilder.cs
index 67d1ac2..398b7f9 100644
--- a/Editor/BuildTool/AppBuilder.cs
+++ b/Editor/BuildTool/AppBuilder.cs
@@ -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 构建接口
+
+ ///
+ /// 直接调用 Build 接口
+ ///
+ ///
+ ///
+ 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($" Unsupported build target: {buildParam.TargetName}. Skip build...");
+ 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
/// 平台切换
///
///
- private static void BuildSwitchPlatform(BuildTarget targetPlatform)
+ private static void SwitchBuildPlatform(BuildTarget targetPlatform)
{
if (EditorUserBuildSettings.activeBuildTarget != targetPlatform)
{
diff --git a/Editor/BuildTool/GuruPublishHelper.cs b/Editor/BuildTool/GuruPublishHelper.cs
new file mode 100644
index 0000000..22b2ac4
--- /dev/null
+++ b/Editor/BuildTool/GuruPublishHelper.cs
@@ -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}";
+
+ ///
+ /// 发布产品到蒲公英平台
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void PublishToPgyer(string packagePath, string apiKey = "", string bashPath = "",
+ Action 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}");
+ }
+ }
+ }
+
+
+
+ ///
+ /// 获取 CMD 命令路径
+ ///
+ ///
+ 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 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();
+ }
+
+ ///
+ /// 在 mac 下进行发布
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static void CallPublishShell(string packagePath, string apiKey = "", string bashPath = "",
+ Action 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);
+ }
+
+ }
+
+ ///
+ /// Guru 包体上传工具
+ ///
+ 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);
+ }
+
+ ///
+ /// Show system dialogs
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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();
+ }
+ }
+
+ ///
+ /// On pgyer response callback
+ ///
+ ///
+ 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(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;
+ }
+}
\ No newline at end of file
diff --git a/Editor/BuildTool/GuruPublishHelper.cs.meta b/Editor/BuildTool/GuruPublishHelper.cs.meta
new file mode 100644
index 0000000..c1debae
--- /dev/null
+++ b/Editor/BuildTool/GuruPublishHelper.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 615e8fb3101146048570e17d27bfbb9b
+timeCreated: 1709605527
\ No newline at end of file
diff --git a/Editor/BuildTool/pgyer_upload.sh b/Editor/BuildTool/pgyer_upload.sh
new file mode 100755
index 0000000..62c46fa
--- /dev/null
+++ b/Editor/BuildTool/pgyer_upload.sh
@@ -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 [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: "
+ echo "Project home page: "
+ 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
diff --git a/Editor/BuildTool/pgyer_upload.sh.meta b/Editor/BuildTool/pgyer_upload.sh.meta
new file mode 100644
index 0000000..effa92a
--- /dev/null
+++ b/Editor/BuildTool/pgyer_upload.sh.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 64be73b7342084dd583da03a6730370d
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/README.md b/README.md
index e5621ae..456f4ce 100644
--- a/README.md
+++ b/README.md
@@ -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**
diff --git a/Runtime/GuruConsent/Runtime/Script/Consent/GoogleDMAHelper.cs b/Runtime/GuruConsent/Runtime/Script/Consent/GoogleDMAHelper.cs
index 51ab9db..775dbe4 100644
--- a/Runtime/GuruConsent/Runtime/Script/Consent/GoogleDMAHelper.cs
+++ b/Runtime/GuruConsent/Runtime/Script/Consent/GoogleDMAHelper.cs
@@ -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 ---------------