[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

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ bin
bin_BurstDebugInformation_DoNotShip bin_BurstDebugInformation_DoNotShip
sdk-intergration/.vscode sdk-intergration/.vscode
sdk-intergration/' sdk-intergration/'
sdk-intergration/Assets/.claude/settings.json

View File

@@ -0,0 +1,40 @@
package com.unity3d.player;
import android.util.Log;
import com.tuyoo.gamesdk.api.SDKAPI;
import com.tuyoo.gamesdk.api.SDKAPIConstant;
import com.tuyoo.gamesdk.api.SDKCallBack;
import com.tuyoo.gamesdk.api.SDKWrapper;
public class SnsTest {
static final String TAG = "SNSTEST";
public static void Bind(String type, String guserId)
{
SDKAPI.getIns().getSnsInfo(type, (snscode, snsInfo, snsmsg) ->{
if(snscode == SDKCallBack.CODE_SUCCESS && snsInfo !=null)
{
SDKAPI.getIns().bindBySnsId(snsInfo, guserId, (bindcode, bindmsg)->{
if(bindcode == SDKCallBack.CODE_SUCCESS)
{
Log.i(TAG, "LinkSns success");
}
else
{
Log.i(TAG, String.format("LinkSns failed, code: %d, msg: %s", bindcode, bindmsg));
}
});
}
else
{
Log.i(TAG, "getSnsInfo failed");
}
});
}
public static void Unbind(String type, int userId)
{
}
}

View File

@@ -0,0 +1,32 @@
fileFormatVersion: 2
guid: 0e17ee73ac07b4006a871da89b5103ae
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,138 @@
using System;
using System.Collections;
using System.Collections.Generic;
using tysdk;
using UnityEngine;
using UnityEngine.UI;
public class UnbindTest : MonoBehaviour
{
[SerializeField]
private Text message;
[SerializeField]
private Button cleanBtn;
[SerializeField]
private Button initBtn;
[SerializeField]
private Dropdown accoutTypeDropdown;
[SerializeField]
private Button loginBtn;
[SerializeField]
private Button logoutBtn;
[SerializeField]
private Button getSnsBtn;
[SerializeField]
private Button checkSnsBtn;
[SerializeField]
private Button bindBtn;
[SerializeField]
private Button unbindBtn;
private EAccoutType accoutType;
private const string Cls = "com.unity3d.player.SnsTest";
// Start is called before the first frame update
void Start()
{
Screen.sleepTimeout = SleepTimeout.NeverSleep;
message.text = string.Empty;
accoutType = (EAccoutType)accoutTypeDropdown.value;
cleanBtn.onClick.AddListener(() => message.text = string.Empty);
initBtn.onClick.AddListener(Init);
accoutTypeDropdown.onValueChanged.AddListener((index) =>
{
accoutType = (EAccoutType)index;
message.text += $"[Account Type] {accoutType.ToString()}\r\n";
}); loginBtn.onClick.AddListener(OnLogin);
logoutBtn.onClick.AddListener(OnLogout);
getSnsBtn.onClick.AddListener(OnGetSns);
checkSnsBtn.onClick.AddListener(OnCheckSns);
bindBtn.onClick.AddListener(OnBind);
unbindBtn.onClick.AddListener(OnUnbind);
Debug.Log("========== Init =============");
TYSdkFacade.Instance.Init();
Debug.Log($"AccoutType {accoutType}");
}
private void Init()
{
UnityBridgeFunc.UnityResetServerUrl("https://128-hwsfsdk-sdk-test01.qijihdhk.com");
}
private void OnLogout()
{
Debug.Log("========== Logout =============");
TYSdkFacade.Instance.Logout();
}
private LoginInfo loginInfo;
private async void OnLogin()
{
Debug.Log("========== Login =============");
message.text += $"Login {accoutType}\r\n";
var info = await TYSdkFacade.Instance.Login(accoutType);
message.text = $"Login Success {info.isSuccess}\r\n";
if(info.isSuccess)
{
loginInfo = info;
}
}
private void OnGetSns()
{
Debug.Log("========== Get SNS =============");
using (var t = new AndroidJavaClass(Cls))
{
t.CallStatic("GetSns", accoutType.ToString());
}
}
private void OnCheckSns()
{
Debug.Log("========== Check SNS =============");
using (var t = new AndroidJavaClass(Cls))
{
t.CallStatic("CheckSns", accoutType.ToString());
}
}
private void OnBind()
{
Debug.Log("========== Bind =============");
using (var t = new AndroidJavaClass(Cls))
{
t.CallStatic("Bind", accoutType.ToString(), loginInfo.StrUserId);
}
}
public void BindCallback(string message)
{
}
private void OnUnbind()
{
using (var t = new AndroidJavaClass(Cls))
{
t.CallStatic("Unbind");
}
}
public void UnbindCallback(string message)
{
}
}

View File

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

114
sdk-intergration/CLAUDE.md Normal file
View File

@@ -0,0 +1,114 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
This is a Unity 2022.3.53f1c1 mobile game SDK integration testing project for "Fishing Travel" (com.arkgame.ft). The project focuses on validating and testing various mobile SDK integrations including authentication, payments, analytics, and advertising networks.
## Build Commands
### Android Builds
```bash
# Command-line build (CI/CD)
/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -quit -projectPath . -executeMethod BuildTool.CIBuildAndroid --out ../Bin/tysdkTest.apk --bundle-type FirstPack --build-type New
# Manual build via Unity Editor
Tools > Build Android
```
### iOS Builds
```bash
# Command-line build (CI/CD)
/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -quit -projectPath . -executeMethod BuildTool.CIBuildIOS --out ../Bin --bundle-type FirstPack --build-type New
# Manual build via Unity Editor
Tools > Build iOS
```
### Build Parameters
- `--out`: Output path for build
- `--bundle-type`: None, FirstPack, or ALL
- `--build-type`: Build type (default: "New")
- `--define-symbol`: Custom compilation defines
- `--patch`: Enable patch build
- `--split`: Enable split APKs
- `--aab`: Build Android App Bundle instead of APK
## Architecture
### Core SDK Structure
- **TYSdkFacade** (`Packages/tysdk/Runtime/TYSdkFacade.cs`): Main SDK interface using facade pattern
- Account management with persistent storage
- Multiple social login providers (Google, Facebook, Apple, Guest)
- JWT token handling and linked account tracking
- Singleton pattern with DontDestroyOnLoad
- **UnityBridgeFunc** (`Assets/CoreLib/Data/sdk/base/UnityBridgeFunc.cs`): Platform-specific native bridge
- Android/iOS native method calls
- ATT (App Tracking Transparency) handling
- Social sharing functionality
### Test Infrastructure
- **SDKTest.cs** (`Assets/Scripts/SDKTest.cs`): Comprehensive SDK testing UI
- Tests all login methods and account linking
- Payment testing and ad display
- Integrates AppsFlyer, Max SDK, Thinking Analytics
- **UnbindTest.cs**: Account unbinding functionality test
- **Test Scenes**: SampleScene, UnbindTest, OneLinkTest
### Package Dependencies
Key Unity packages and third-party SDKs:
- **UniRx**: Reactive Extensions for Unity
- **tysdk**: Custom Tuyoo SDK wrapper (v0.0.1)
- **AppsFlyer SDK**: Attribution tracking
- **Max SDK**: Ad mediation platform
- **Thinking Analytics**: Custom analytics
- **Facebook SDK**: Social login and sharing
- **Firebase Analytics**: Google analytics
- **Google Play Services**: Auth, Billing, Review
## Platform-Specific Configuration
### Android
- **Target SDK**: 35 (configurable via gradle template)
- **Package Name**: com.arkgame.ft
- **Deep Linking**: OneLink support and custom URI scheme `zzft://mainactivity`
- **Key Files**:
- `Assets/Plugins/Android/AndroidManifest.xml`
- `Assets/Plugins/Android/mainTemplate.gradle`
- `Assets/Plugins/Android/gradleTemplate.properties`
### iOS
- **Build Output**: `../Bin` directory
- **Keystore**: Located in `keystore/` directory
- **Apple Sign-In**: Supported for iOS platform
## Development Workflow
### Testing SDK Features
1. Open `SampleScene` or test scenes
2. Use SDKTest UI to test:
- Initialization
- Login methods (Guest, Google, Facebook, Apple, Token)
- Account linking/unlinking
- Payments and ad display
- Analytics events
### Adding New SDK Tests
1. Create test methods in SDKTest.cs
2. Add UI buttons in the corresponding scene
3. Hook up button listeners in Start() method
### Modifying Build Configuration
1. Edit BuildTool.cs for new build parameters
2. Modify mainTemplate.gradle for Android dependencies
3. Update AndroidManifest.xml for permissions/activities
## Important Notes
- The project uses a custom TYApp/TYUnityActivity for Android
- Multiple ad network adapters integrated via Max SDK mediation
- Server URLs can be configured for test/production environments
- Uses PlayerPrefs for account persistence
- Implements comprehensive callback management for async operations

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

View File

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

View File

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

View File

@@ -6,9 +6,6 @@ EditorBuildSettings:
serializedVersion: 2 serializedVersion: 2
m_Scenes: m_Scenes:
- enabled: 1 - enabled: 1
path: Assets/Scenes/SampleScene.unity path: Assets/Scenes/UnbindTest.unity
guid: 99c9720ab356a0642a771bea13969a05 guid: e55d807d563854943a26ad6dadec548d
- enabled: 1
path: Assets/Scenes/OneLinkTest.unity
guid: 61b7489d20aa24ed1b5cdc4fcfd05a65
m_configObjects: {} m_configObjects: {}