[M] new call back

[wip]
This commit is contained in:
2025-12-03 11:11:56 +08:00
parent 9d6b5ae895
commit 8cc0a67f03
16 changed files with 4028 additions and 308 deletions

View File

@@ -0,0 +1,210 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace tysdk
{
/// <summary>
/// 线程安全的异步Callback管理器
/// 解决原有callback系统的线程安全、内存泄漏和超时问题
/// </summary>
public class TYSDKCallbackManager : IDisposable
{
private static readonly Lazy<TYSDKCallbackManager> _instance =
new Lazy<TYSDKCallbackManager>(() => new TYSDKCallbackManager());
public static TYSDKCallbackManager Instance => _instance.Value;
private readonly ConcurrentDictionary<string, CallbackEntry> _callbacks = new();
private readonly object _lock = new();
private bool _disposed = false;
private TYSDKCallbackManager() { }
/// <summary>
/// 注册一个callback并返回Task
/// </summary>
/// <typeparam name="T">Callback数据类型</typeparam>
/// <param name="callbackType">Callback类型标识</param>
/// <param name="timeout">超时时间默认15 sec</param>
/// <returns>Task用于等待callback结果</returns>
public Task<T> RegisterCallback<T>(TimeSpan? timeout = null) where T : class
{
if (_disposed)
throw new ObjectDisposedException(nameof(TYSDKCallbackManager));
var callbackId = typeof(T).Name;
if (_callbacks.TryGetValue(callbackId, out var entry))
{
UnityEngine.Debug.Log($"[TYSDKCallbackManager] Registered callback exists {callbackId}");
return entry.Task as Task<T>;
}
var tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
var actualTimeout = timeout ?? TimeSpan.FromSeconds(15);
var cts = new CancellationTokenSource(actualTimeout);
entry = new CallbackEntry<T>
{
TaskCompletionSource = tcs,
CancellationTokenSource = cts,
};
// 注册到字典
_callbacks[callbackId] = entry;
// 设置超时取消
cts.Token.Register(() =>
{
if (tcs.TrySetCanceled())
{
UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] Callback {callbackId} timed out after {actualTimeout.TotalSeconds}s");
}
_callbacks.TryRemove(callbackId, out _);
});
UnityEngine.Debug.Log($"[TYSDKCallbackManager] Registered callback {callbackId}");
return tcs.Task;
}
/// <summary>
/// 触发callback
/// </summary>
/// <typeparam name="T">Callback数据类型</typeparam>
/// <param name="callbackType">Callback类型标识</param>
/// <param name="callbackData">Callback数据</param>
/// <returns>是否成功触发callback</returns>
public bool TryTriggerCallback<T>(T callbackData) where T : class
{
if (_disposed || callbackData == null)
return false;
var key = typeof(T).Name;
if (!_callbacks.TryGetValue(key, out var entry))
{
UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] No pending callback found for type: {key}");
return false;
}
if (entry == null)
{
_callbacks.TryRemove(key, out _);
return false;
}
if (entry.Task.IsCompleted)
{
entry.CancellationTokenSource?.Cancel();
_callbacks.TryRemove(key, out _);
return false;
}
var actualEntry = entry as CallbackEntry<T>;
if (actualEntry == null)
{
UnityEngine.Debug.LogError($"[TYSDKCallbackManager] Callback type mismatch: Expected {typeof(T).Name}, but got {entry.GetType().Name}");
entry.CancellationTokenSource?.Cancel();
return false;
}
try
{
// 尝试设置结果
if (actualEntry.TaskCompletionSource.TrySetResult(callbackData))
{
actualEntry.CancellationTokenSource?.Cancel();
UnityEngine.Debug.Log($"[TYSDKCallbackManager] Successfully triggered callback {key}");
return true;
}
}
catch (Exception ex)
{
UnityEngine.Debug.LogError($"[TYSDKCallbackManager] Error triggering callback {key}: {ex.Message}\n{ex.StackTrace}");
actualEntry.TaskCompletionSource.TrySetException(ex);
actualEntry.CancellationTokenSource?.Cancel();
return false;
}
return false;
}
/// <summary>
/// 取消指定类型的所有callback
/// </summary>
/// <param name="callbackType">Callback类型</param>
/// <param name="reason">取消原因</param>
public void CancelCallbacks<T>()
{
var key = typeof(T).Name;
if (!_callbacks.TryGetValue(key, out var entryToRemove))
{
UnityEngine.Debug.LogWarning($"[TYSDKCallbackManager] No pending callback found for type: {key}");
return;
}
entryToRemove.Cancel();
}
public int GetCallbackNum()
{
return _callbacks?.Count ?? 0;
}
public void Dispose()
{
if (_disposed) return;
lock (_lock)
{
if (_disposed) return;
_disposed = true;
// 取消所有pending callbacks
foreach (var entry in _callbacks.Values)
{
try
{
if (!entry.Task.IsCompleted)
{
entry.Cancel();
}
}
catch
{
// 忽略取消时的异常
}
entry.CancellationTokenSource?.Dispose();
}
_callbacks.Clear();
UnityEngine.Debug.Log("[TYSDKCallbackManager] Disposed");
}
}
private abstract class CallbackEntry
{
public CancellationTokenSource CancellationTokenSource { get; set; } = null!;
public abstract Task Task { get; }
public abstract void Cancel();
}
private class CallbackEntry<T> : CallbackEntry where T : class
{
public TaskCompletionSource<T> TaskCompletionSource { get; set; } = null!;
public override Task Task => TaskCompletionSource.Task;
public override void Cancel()
{
TaskCompletionSource.TrySetCanceled();
CancellationTokenSource?.Cancel();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 292a655e788d84d34aac4f83c57706ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -19,7 +19,7 @@ namespace tysdk
public string jwtToken;
public string strUserId => userId.ToString();
public HashSet<EAccoutType> linkedAccout = new HashSet<EAccoutType>();
public EAccoutType channel {get; set;}
public EAccoutType channel { get; set; }
public string userName;
public string avatar;
@@ -40,7 +40,7 @@ namespace tysdk
{"ios13", EAccoutType.Apple}
};
private static EAccoutType ConvertAccoutType(string accountType)
private static EAccoutType ConvertAccoutType(string accountType)
{
if (accoutTypeMap.ContainsKey(accountType))
{
@@ -81,12 +81,12 @@ namespace tysdk
linkedAccout = jInfo["linkedAccout"].ToString().Split(',').Select(x => ConvertAccoutType(x)).ToHashSet()
};
if(jInfo.TryGetValue("userName", out var userName))
if (jInfo.TryGetValue("userName", out var userName))
{
accountInfo.userName = (string) userName;
accountInfo.userName = (string)userName;
}
if(jInfo.TryGetValue("avatar", out var avatar))
if (jInfo.TryGetValue("avatar", out var avatar))
{
accountInfo.avatar = (string)avatar;
}
@@ -103,8 +103,6 @@ namespace tysdk
private static AccountInfo _accountInfo;
public static AccountInfo TYAccountInfo => _accountInfo;
private static IDictionary<string, Action<ITYSdkCallback>> callbacks = new Dictionary<string, Action<ITYSdkCallback>>();
private static TYSdkFacade _instance;
public static TYSdkFacade Instance
{
@@ -118,7 +116,6 @@ namespace tysdk
return _instance;
}
}
public void Init()
{
#if UNITY_ANDROID
@@ -144,7 +141,7 @@ namespace tysdk
public void Logout()
{
UnityEngine.Debug.Log("Logout");
if(_accountInfo != null)
if (_accountInfo != null)
{
UnityBridgeFunc.UnityLogOutByChannel(_accountInfo.channel);
}
@@ -157,7 +154,7 @@ namespace tysdk
{
#if UNITY_EDITOR
await Task.Yield();
var deviceId = UnityEngine.Device.SystemInfo.deviceUniqueIdentifier.Split('-')[0].Substring(0,8);
var deviceId = UnityEngine.Device.SystemInfo.deviceUniqueIdentifier.Split('-')[0].Substring(0, 8);
var userId = (int)ulong.Parse(deviceId, System.Globalization.NumberStyles.HexNumber);
@@ -174,44 +171,53 @@ namespace tysdk
#elif UNITY_ANDROID || UNITY_IOS
var taskSource = new TaskCompletionSource<LoginInfo>();
callbacks.Add("LoginResult", (ITYSdkCallback callback) =>
{
taskSource.SetResult((LoginInfo)callback);
});
var task = TYSDKCallbackManager.Instance.RegisterCallback<LoginInfo>(TimeSpan.FromSeconds(30));
UnityBridgeFunc.UnityLogin(accoutType);
var loginInfo = await taskSource.Task;
if(loginInfo.isSuccess)
try
{
_accountInfo.channel = accoutType;
_accountInfo.AddLinkedAccount(accoutType);
_accountInfo.Save();
var loginInfo = await task;
if(loginInfo.isSuccess)
{
_accountInfo.channel = accoutType;
_accountInfo.AddLinkedAccount(accoutType);
_accountInfo.Save();
}
return loginInfo;
}
catch(Exception e)
{
Debug.LogWarning($"[TYSdkFacade] Login failed: {e}");
return new LoginInfo(){isSuccess = false};
}
return loginInfo;
#endif
}
public async Task<LoginInfo> LoginByToken()
{
var accoutInfo = AccountInfo.GetSavedAccoutInfo();
if(accoutInfo == null) return new LoginInfo();
if (accoutInfo == null) return new LoginInfo();
var taskSource = new TaskCompletionSource<LoginInfo>();
callbacks.Add("LoginResult", (ITYSdkCallback callback) =>
{
taskSource.SetResult((LoginInfo)callback);
});
var task = TYSDKCallbackManager.Instance.RegisterCallback<LoginInfo>(TimeSpan.FromSeconds(30));
UnityBridgeFunc.UnityLoginByTokenFun(accoutInfo.token);
var loginInfo = await taskSource.Task;
if(loginInfo.isSuccess)
try
{
_accountInfo.Save();
var loginInfo = await task;
if (loginInfo.isSuccess)
{
_accountInfo.Save();
}
return loginInfo;
}
catch (Exception e)
{
Debug.LogWarning($"[TYSdkFacade] Login by token failed: {e}");
return new LoginInfo() { isSuccess = false };
}
return loginInfo;
}
public void LoginResult(string json)
@@ -231,7 +237,7 @@ namespace tysdk
var jwtToken = (string)loginData["jwttoken"];
var savedInfo = AccountInfo.GetSavedAccoutInfo();
if(savedInfo == null || savedInfo.userId != userId)
if (savedInfo == null || savedInfo.userId != userId)
{
_accountInfo = new AccountInfo()
{
@@ -254,11 +260,7 @@ namespace tysdk
SetUserInfo();
}
if (callbacks.TryGetValue("LoginResult", out var action))
{
action.Invoke(result);
callbacks.Remove("LoginResult");
}
TYSDKCallbackManager.Instance.TryTriggerCallback(result);
}
private void SetUserInfo()
@@ -269,42 +271,43 @@ namespace tysdk
UnityBridgeFunc.SetGaUserInfo(strUserId);
}
#if UNITY_EDITOR
public async Task<bool> LinkAccount(EAccoutType accoutType)
{
await Task.Delay(300);
return true;
}
#elif UNITY_IOS
public async Task<bool> LinkAccount(EAccoutType accoutType)
#elif UNITY_IOS || UNITY_ANDROID
public async Task<bool> LinkAccount(EAccoutType accoutType)
{
if (_accountInfo == null) return false;
if( _accountInfo.linkedAccout.Contains(accoutType)) return true;
var taskSource = new TaskCompletionSource<LinkResult>();
callbacks.Add("LinkAccoutResult", (ITYSdkCallback callback) =>
{
taskSource.SetResult((LinkResult)callback);
});
if (_accountInfo.linkedAccout.Contains(accoutType)) return true;
var task = TYSDKCallbackManager.Instance.RegisterCallback<LinkResult>();
UnityBridgeFunc.LinkAccount(accoutType);
var result = await taskSource.Task;
if (result.isSuccess)
try
{
if(_accountInfo == null)
_accountInfo = AccountInfo.GetSavedAccoutInfo();
if(_accountInfo != null)
var result = await task;
if (result.isSuccess)
{
_accountInfo.AddLinkedAccount(accoutType);
_accountInfo.Save();
}
}
if (_accountInfo == null)
_accountInfo = AccountInfo.GetSavedAccoutInfo();
return result.isSuccess;
if (_accountInfo != null)
{
_accountInfo.AddLinkedAccount(accoutType);
_accountInfo.Save();
}
}
return result.isSuccess;
}
catch (Exception e)
{
Debug.LogWarning($"[TYSdkFacade] Link account failed: {e}");
return false;
}
}
public void LinkAccoutResult(string codestr)
@@ -314,44 +317,8 @@ namespace tysdk
isSuccess = codestr == "1"
};
if (callbacks.TryGetValue("LinkAccoutResult", out var action))
{
action.Invoke(result);
callbacks.Remove("LinkAccoutResult");
}
TYSDKCallbackManager.Instance.TryTriggerCallback(result);
}
#elif UNITY_ANDROID
public async Task<bool> LinkAccount(EAccoutType accoutType)
{
if (_accountInfo == null) return false;
if( _accountInfo.linkedAccout.Contains(accoutType)) return true;
var taskSource = new TaskCompletionSource<LoginInfo>();
callbacks.Add("LoginResult", (ITYSdkCallback callback) =>
{
taskSource.SetResult((LoginInfo)callback);
});
UnityBridgeFunc.LinkAccount(accoutType);
var result = await taskSource.Task;
if (result.isSuccess)
{
if(_accountInfo == null)
_accountInfo = AccountInfo.GetSavedAccoutInfo();
if(_accountInfo != null)
{
_accountInfo.AddLinkedAccount(accoutType);
_accountInfo.Save();
}
}
return result.isSuccess;
}
#endif
/// <summary>
@@ -365,41 +332,40 @@ namespace tysdk
public async Task<bool> LinkCheck(EAccoutType accoutType)
{
if (_accountInfo == null) return false;
if( _accountInfo.linkedAccout.Contains(accoutType)) return true;
var taskSource = new TaskCompletionSource<LinkCheckInfo>();
callbacks.Add("CheckLinkResult", (ITYSdkCallback callback) =>
{
taskSource.SetResult((LinkCheckInfo)callback);
});
if (_accountInfo.linkedAccout.Contains(accoutType)) return true;
var task = TYSDKCallbackManager.Instance.RegisterCallback<LinkCheckInfo>(TimeSpan.FromSeconds(30));
UnityBridgeFunc.LinkCheck(accoutType);
var code = (await taskSource.Task).code;
if (code == 1 && !_accountInfo.linkedAccout.Contains(accoutType))
try
{
_accountInfo.linkedAccout.Add(accoutType);
_accountInfo.Save();
}
var result = await task;
if(code == -1)
if (result.code == 1 && !_accountInfo.linkedAccout.Contains(accoutType))
{
_accountInfo.linkedAccout.Add(accoutType);
_accountInfo.Save();
}
if (result.code == -1)
{
Debug.LogError("[TYSdkFacade] CheckLinkResult error");
}
return result.code == 1;
}
catch(Exception e)
{
Debug.LogError("[TYSdkFacade] CheckLinkResult error");
Debug.LogWarning($"[TYSdkFacade] CheckLinkResult error: {e}");
return false;
}
return code == 1;
}
public void CheckLinkResult(string codestr)
{
if (callbacks.TryGetValue("CheckLinkResult", out var action))
{
var result = new LinkCheckInfo();
result.code = int.Parse(codestr);
action.Invoke(result);
callbacks.Remove("CheckLinkResult");
}
var result = new LinkCheckInfo();
result.code = int.Parse(codestr);
TYSDKCallbackManager.Instance.TryTriggerCallback(result);
}
public void Signout()
@@ -411,7 +377,7 @@ namespace tysdk
var tyurl = config.Get<string>("AGG_SERVER", defaultTyurl);
string tycs = tyurl == defaultTyurl ?
string tycs = tyurl == defaultTyurl ?
"https://hwcsh.tygameworld.com/template/appCancel/note.html"
:
"https://customermanage-feature-test-web-test.tuyougame.cn/appCancel/note.html";

View File

@@ -1,3 +1,4 @@
using System;
using System.Threading.Tasks;
using UnityEngine;
@@ -27,23 +28,22 @@ namespace tysdk
return new ATTInfo(){isAccepted = true};
#elif UNITY_IOS
var taskSource = new TaskCompletionSource<ATTInfo>();
callbacks.Add("RequestATT", (ITYSdkCallback callback) =>
{
taskSource.SetResult((ATTInfo)callback);
});
var task = tysdk.TYSDKCallbackManager.Instance.RegisterCallback<ATTInfo>();
UnityBridgeFunc.RequestATT();
return await taskSource.Task;
try{
return await task;
}
catch(Exception e)
{
Debug.LogWarning(e.Message);
return new ATTInfo(){isAccepted = false};
}
#endif
}
public void RequestATTResult(string r)
{
if (callbacks.TryGetValue("RequestATT", out var action))
{
action.Invoke(new ATTInfo(){isAccepted = r == "1"});
callbacks.Remove("RequestATT");
}
TYSDKCallbackManager.Instance.TryTriggerCallback(new ATTInfo(){isAccepted = r == "1"});
}
}
}
}

View File

@@ -35,126 +35,4 @@ namespace tysdk
GA_SDK = 9, //SDK相关事件
GA_ABTest = 10, //abtest相关事件
}
/*
public class GAEvent : IDisposable
{
private GATrackType eventType;
private string eventName;
bool AFSend = true;
private JObject content = new JObject();
public static Dictionary<string, string> extraContent = new Dictionary<string, string>();
public GAEvent(GATrackType eventType, string eventName, bool AFSend = true)
{
this.eventType = eventType;
this.eventName = eventName;
this.AFSend = AFSend;
}
public GAEvent AddContent(string key, string value)
{
content[key] = value;
return this; }
public GAEvent AddContent(string key, int value)
{
content[key] = value;
return this;
}
public GAEvent AddContent(string key, bool value)
{
content[key] = value;
return this;
}
public GAEvent AddContent(string key, float value)
{
content[key] = value;
return this;
}
public GAEvent AddContent(string key, JToken value)
{
content[key] = value;
return this;
}
public void Dispose()
{
foreach (var item in extraContent)
{
content[item.Key] = item.Value;
}
string msg = content.ToString();
if (msg == String.Empty) return;
if (AFSend)
{
SendAfEvent(eventType,eventName,msg);
}
TYSdkFacade.Instance.EventTrack((int)eventType, eventName, msg);
content.RemoveAll();
}
private void SendAfEvent(GATrackType type,string eventName,string logMessage)
{
Dictionary<string, string> eventValues = new Dictionary<string, string>();
eventValues.Add("GA_TYPE", type.ToString());
eventValues.Add(eventName, logMessage);
AppsFlyer.sendEvent(AFInAppEvents.GA, eventValues);
}
*/
/*
*GA_TRACK默认类型
*GA_CION金流相关事件
*GA_PAY支付相关事件
*GA_GAME游戏行为
*GA_LOGIN登录注册相关事件
*GA_PUSH推送相关事件
*GA_ADBOXadbox相关事件
*GA_PREFORMANCE性能上报相关事件
*GA_SDKSDK相关事件
*GA_ABTestabtest相关事件
*GA_PROFILE设置用户特征
*/
//TOD SDK
/*
public static GAEvent TackEvent(string eventName, bool afSend = true)
{
return new GAEvent(GATrackType.GA_TRACK, eventName, afSend);
}
public static GAEvent PushEvent(string eventName, bool afSend = true)
{
return new GAEvent(GATrackType.GA_PUSH, eventName, afSend);
}
public static GAEvent CionEvent(string eventName, bool afSend = true)
{
return new GAEvent(GATrackType.GA_CION, eventName, afSend);
}
public static GAEvent PayEvent(string eventName, bool afSend = true)
{
return new GAEvent(GATrackType.GA_PAY, eventName, afSend);
}
public static GAEvent GameEvent(string eventName, bool afSend = true)
{
return new GAEvent(GATrackType.GA_GAME, eventName, afSend);
}
public static GAEvent LoginEvent(string eventName, bool afSend = true)
{
return new GAEvent(GATrackType.GA_LOGIN, eventName, afSend);
}
}
*/
}

View File

@@ -56,37 +56,45 @@ namespace tysdk
#elif UNITY_ANDROID
var pType = "googleiab.global.app";
var taskSource = new TaskCompletionSource<PaymentInfo>();
callbacks.Add("PayResult", (ITYSdkCallback callback) =>
var task = TYSDKCallbackManager.Instance.RegisterCallback<PaymentInfo>(TimeSpan.FromMinutes(1));
try
{
taskSource.SetResult((PaymentInfo)callback);
});
//UnityBridgeFunc.UnityKnow(prodId, prodName, count.ToString(), orderId, extraInfo);
UnityBridgeFunc.UnityKnowNew(prodId, prodPrice, prodName, count.ToString(), orderId, extraInfo,pType);
//UnityBridgeFunc.UnityKnow(prodId, prodName, count.ToString(), orderId, extraInfo);
UnityBridgeFunc.UnityKnowNew(prodId, prodPrice, prodName, count.ToString(), orderId, extraInfo,pType);
var result = await task;
result.count = count;
result.orderId = orderId;
result.productId = prodId;
result.price = prodPrice;
return result;
}
catch (Exception e)
{
Debug.LogWarning($"[TYSdkFacade::Pay] Faild {e.Message}");
return new PaymentInfo(){code = "-1"};
}
var result = await taskSource.Task;
result.count = count;
result.orderId = orderId;
result.productId = prodId;
result.price = prodPrice;
return result;
#elif UNITY_IOS
var taskSource = new TaskCompletionSource<PaymentInfo>();
callbacks.Add("PayResult", (ITYSdkCallback callback) =>
{
taskSource.SetResult((PaymentInfo)callback);
});
var task = TYSDKCallbackManager.Instance.RegisterCallback<PaymentInfo>(TimeSpan.FromMinutes(1));
UnityBridgeFunc.UnityKnow(_accountInfo.strUserId, prodId, prodPrice, prodName, count.ToString(), orderId, extraInfo);
var result = await taskSource.Task;
result.count = count;
result.orderId = orderId;
result.productId = prodId;
result.price = prodPrice;
return result;
try{
var result = await task;
result.count = count;
result.orderId = orderId;
result.productId = prodId;
result.price = prodPrice;
return result;
}
catch(Exception e)
{
Debug.LogWarning($"[TYSdkFacade::Pay] Faild {e.Message}");
return new PaymentInfo(){code = "-1"};
}
#endif
}
@@ -98,12 +106,7 @@ namespace tysdk
var result = new PaymentInfo();
result.code = jresult["code"].ToString();
result.msg = jresult["errStr"].ToString();
if (callbacks.TryGetValue("PayResult", out var action))
{
action.Invoke(result);
callbacks.Remove("PayResult");
}
TYSDKCallbackManager.Instance.TryTriggerCallback(result);
}
// Get Pay list
@@ -117,13 +120,9 @@ namespace tysdk
var result = new ProductListInfo();
return result;
#elif UNITY_ANDROID || UNITY_IOS
var taskSource = new TaskCompletionSource<ProductListInfo>();
callbacks.Add("SKUListResult", (ITYSdkCallback callback) =>
{
taskSource.SetResult((ProductListInfo) callback);
});
var task = TYSDKCallbackManager.Instance.RegisterCallback<ProductListInfo>();
UnityBridgeFunc.GetSKUList();
var result = await taskSource.Task;
var result = await task;
return result;
#endif
}
@@ -147,11 +146,7 @@ namespace tysdk
#endif
}
if (callbacks.TryGetValue("SKUListResult", out var action))
{
action.Invoke(result);
callbacks.Remove("SKUListResult");
}
TYSDKCallbackManager.Instance.TryTriggerCallback(result);
}
}
}

View File

@@ -13,9 +13,8 @@ namespace tysdk
none
}
public interface ITYSdkCallback { }
public class LoginInfo : ITYSdkCallback
public class LoginInfo
{
public bool isSuccess;
public int userId;
@@ -24,17 +23,17 @@ namespace tysdk
public int code;
}
public class LinkResult : ITYSdkCallback
public class LinkResult
{
public bool isSuccess;
}
public class LinkCheckInfo : ITYSdkCallback
public class LinkCheckInfo
{
public int code;
}
public class PaymentInfo : ITYSdkCallback
public class PaymentInfo
{
public bool isSuccessFromSdk => code == "0";
public bool isSuccess => isSuccessFromSdk && confirmed;
@@ -62,7 +61,7 @@ namespace tysdk
}
}
public class ProductListInfo: ITYSdkCallback
public class ProductListInfo
{
public int code = 1;
public string msg = string.Empty;
@@ -134,7 +133,7 @@ namespace tysdk
#endif
public class ATTInfo : ITYSdkCallback
public class ATTInfo
{
public bool isAccepted;
}