add Tech3CSDK

This commit is contained in:
Le Duc Anh
2026-02-02 19:21:45 +07:00
parent 9454ad884f
commit 689f8a45b6
45 changed files with 3092 additions and 11 deletions
@@ -17,5 +17,10 @@ namespace BrewMonster
if (_instance.IsValueCreated)
throw new InvalidOperationException($"Singleton<{typeof(T).Name}> already created!");
}
protected virtual void Initialize()
{
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9cfabbaaddd233a4a9d4f07a3577d3a2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,207 @@
using Tech3C;
using BrewMonster;
using System;
using UnityEngine;
namespace BrewMonster.Scripts
{
public enum LOGIN_ERROR_CODE
{
SUCCESS = 0,
CANCELLED = -1
}
public class Tech3CSDKWrapper : Singleton<Tech3CSDKWrapper>
{
public string clientId = "";
public string clientSecret = "";
private AuthCallback authCallback;
private LogoutCallback logoutCallback;
/// <summary>
/// After Tech3C SDK returns result, this callback will be called. <br/>
/// (errorCode, userId, password)
/// </summary>
public Action<int, string, string> onLoginCallback;
public Action<int, string> onLogOutCallback;
public bool isInitialized = false;
public bool isProcessing = false; // true if the SDK is processing a request (login or logout)
#region private functions
protected override void Initialize()
{
base.Initialize();
SetupCallbacks();
// Auto-initialize SDK
if (!string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(clientSecret))
{
BMLogger.Log($"Initializing Tech3C SDK...\n Client ID: {clientId}");
Tech3CSDK.Instance.Initialize(clientId, clientSecret);
if (Tech3CSDK.Instance.IsInitialized)
{
BMLogger.Log("[SDK] SDK Initialized Successfully!");
}
else
{
BMLogger.Log("[SDK] Failed to initialize SDK");
}
}
else
{
BMLogger.Log("[SDK] Client ID and/or Client Secret not set. Please configure in Inspector.");
}
BMLogger.Log("[SDK] Tech3C SDK Simple Demo Started");
isInitialized = true;
}
private void SetupCallbacks()
{
// Auth callback
authCallback = new AuthCallback();
authCallback.OnAuthSuccessEvent += OnAuthSuccessEvent;
authCallback.OnAuthCancelledEvent += OnAuthCancelledEvent;
authCallback.OnAuthErrorEvent += OnAuthErrorEvent;
// Logout callback
logoutCallback = new LogoutCallback();
logoutCallback.OnLogoutSuccessEvent += OnLogoutSuccessEvent;
logoutCallback.OnLogoutErrorEvent += OnLogoutErrorEvent;
}
#endregion
#region SDK Callbacks
private void OnAuthSuccessEvent(string userId, string password, string accessToken, string refreshToken, LoginType loginType, long expiryTime)
{
isProcessing = false;
BMLogger.Log($"[SDK] Auth Success!\n User ID: {userId}\n Password: {password}\n Login Type: {loginType}\n Token: {accessToken?.Substring(0, Mathf.Min(20, accessToken?.Length ?? 0))}...");
onLoginCallback?.Invoke((byte)LOGIN_ERROR_CODE.SUCCESS, userId, password);
}
private void OnAuthCancelledEvent()
{
isProcessing = false;
BMLogger.Log("[SDK] Auth Cancelled by user");
onLoginCallback?.Invoke((int)LOGIN_ERROR_CODE.CANCELLED, "", "");
}
private void OnAuthErrorEvent(int errorCode, string errorMessage)
{
isProcessing = false;
BMLogger.Log($"[SDK] Auth Error [{errorCode}]: {errorMessage}");
onLoginCallback?.Invoke(errorCode, errorMessage, string.Empty);
}
private void OnLogoutSuccessEvent()
{
isProcessing = false;
BMLogger.Log("[SDK] Logout Successful");
onLogOutCallback?.Invoke((int)LOGIN_ERROR_CODE.SUCCESS, "");
}
private void OnLogoutErrorEvent(int errorCode, string errorMessage)
{
isProcessing = false;
BMLogger.Log($"[SDK] Logout Error [{errorCode}]: {errorMessage}");
onLogOutCallback?.Invoke(errorCode, errorMessage);
}
#endregion
#region public functions
public void SetLoginCallback(Action<int, string, string> callback)
{
if (callback != null)
{
BMLogger.LogWarning("[SDK] Login callback is already set, it will be overridden");
}
onLoginCallback = callback;
}
public void RemoveLoginCallback()
{
onLoginCallback = null;
}
public void SetLogoutCallback(Action<int, string> callback)
{
if (callback != null)
{
BMLogger.LogWarning("[SDK] Logout callback is already set, it will be overridden");
}
onLogOutCallback = callback;
}
public void RemoveLogoutCallback()
{
onLogOutCallback = null;
}
/// <summary>
/// Show Tech3C SDK login screen.
/// Callback will be called after login success or failed.
/// </summary>
public bool Login()
{
if (!isInitialized)
{
BMLogger.LogError("[SDK] SDK is not initialized, please call Initialize() first");
return false;
}
if (isProcessing)
{
BMLogger.LogError("[SDK] SDK is already processing a request, please wait for the current request to complete");
return false;
}
if (onLoginCallback == null)
{
BMLogger.LogError("[SDK] Login callback is not set, please set it using SetLoginCallback");
return false;
}
isProcessing = true;
Tech3CSDK.Instance.ShowAuth(authCallback);
return true;
}
public bool Logout()
{
if (!isInitialized)
{
BMLogger.LogError("[SDK] SDK is not initialized, please call Initialize() first");
return false;
}
if (isProcessing)
{
BMLogger.LogError("[SDK] SDK is already processing a request, please wait for the current request to complete");
return false;
}
if (onLogOutCallback == null)
{
BMLogger.LogError("[SDK] Logout callback is not set, please set it using SetLogoutCallback");
return false;
}
isProcessing = true;
Tech3CSDK.Instance.Logout(logoutCallback);
return true;
}
#endregion
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 61795692226b05849aec56bf168c905a
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using BrewMonster.Network;
using BrewMonster.Scripts;
using CSNetwork.Protocols;
using CSNetwork.Protocols.RPCData;
using TMPro;
@@ -33,6 +34,12 @@ namespace BrewMonster.UI
bool isDoneNPCRender = false;
private SynchronizationContext context;
public AudioClip loginBGM;
void Awake()
{
var tech3CWrapper = Tech3CSDKWrapper.Instance;
}
void Start()
{
AudioManager.Instance.PlayBGM(loginBGM, 1.5f);
@@ -41,7 +48,9 @@ namespace BrewMonster.UI
_usernameInputField.text = PlayerPrefs.GetString("username", "");
_passwordInputField.text = PlayerPrefs.GetString("password", "");
Tech3CSDKWrapper.Instance.SetLoginCallback(OnLoginCallback);
Tech3CSDKWrapper.Instance.SetLogoutCallback(OnLogoutCallback);
}
// Update is called once per frame
@@ -69,18 +78,16 @@ namespace BrewMonster.UI
#endif
}
private void OnDisable()
{
Tech3CSDKWrapper.Instance.RemoveLoginCallback();
Tech3CSDKWrapper.Instance.RemoveLogoutCallback();
}
public async void OnLoginButtonClicked()
{
BMLogger.Log("OnLoginButtonClicked");
string username = _usernameInputField.text;
string password = _passwordInputField.text;
// UnityGameSession.SetConnectionInfo("103.182.22.52", 29000);
UnityGameSession.SetConnectionInfo("103.51.120.195", 29000);
PlayerPrefs.SetString("username", username);
PlayerPrefs.SetString("password", password);
PlayerPrefs.Save();
await UnityGameSession.Login(username, password, OnLoginComplete);
_selectCharacterScreen.gameObject.SetActive(true);
Tech3CSDKWrapper.Instance.Login();
}
/// <summary>
@@ -278,5 +285,37 @@ namespace BrewMonster.UI
}
}
#endif
private async void OnLoginCallback(int errorCode, string userId, string password)
{
if (errorCode == 0)
{
BMLogger.Log($"Login success -- userId: {userId} - {password}");
// UnityGameSession.SetConnectionInfo("103.182.22.52", 29000);
UnityGameSession.SetConnectionInfo("103.51.120.195", 29000);
PlayerPrefs.SetString("username", userId);
PlayerPrefs.SetString("password", password);
PlayerPrefs.Save();
await UnityGameSession.Login(userId, password, OnLoginComplete);
_selectCharacterScreen.gameObject.SetActive(true);
}
else
{
// if it failed, the userId will be the error message
BMLogger.LogError($"Login failed -- errorCode: {errorCode}: {userId}");
}
}
private void OnLogoutCallback(int errorCode, string errorMessage)
{
if (errorCode == 0)
{
BMLogger.Log("Logout success");
}
else
{
BMLogger.LogError($"Logout failed -- errorCode: {errorCode}: {errorMessage}");
}
}
}
}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f45408c4c89289d498475d0e1e1e5b7e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<!--Used when Application Entry is set to Activity, otherwise remove this activity block-->
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:theme="@style/Tech3CTheme.LoginGame">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
<!--Used when Application Entry is set to GameActivity, otherwise remove this activity block-->
<activity android:name="com.unity3d.player.UnityPlayerGameActivity"
android:theme="@style/BaseUnityGameActivityTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="android.app.lib_name" android:value="game" />
</activity>
</application>
</manifest>
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 11f5d7426047d6048a47d330b02103d9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
plugins {
// If you are changing the Android Gradle Plugin version, make sure it is compatible with the Gradle version preinstalled with Unity
// See which Gradle version is preinstalled with Unity here https://docs.unity3d.com/Manual/android-gradle-overview.html
// See official Gradle and Android Gradle Plugin compatibility table here https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
// To specify a custom Gradle version in Unity, go do "Preferences > External Tools", uncheck "Gradle Installed with Unity (recommended)" and specify a path to a custom Gradle version
id 'com.android.application' version '7.4.2' apply false
id 'com.android.library' version '7.4.2' apply false
**BUILD_SCRIPT_DEPS**
}
task clean(type: Delete) {
delete rootProject.buildDir
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7736ab544ec5cab4a89af84ac45b5a75
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,51 @@
apply plugin: 'com.android.library'
apply from: '../shared/keepUnitySymbols.gradle'
**APPLY_PLUGINS**
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "com.google.android.material:material:1.11.0"
**DEPS**}
android {
ndkVersion "**NDKVERSION**"
namespace "com.unity3d.player"
ndkPath "**NDKPATH**"
compileSdk **APIVERSION**
buildToolsVersion '**BUILDTOOLS**'
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
buildFeatures {
viewBinding true
}
defaultConfig {
**DEFAULT_CONFIG_SETUP**
minSdk **MINSDK**
targetSdk **TARGETSDK**
ndk {
debugSymbolLevel **DEBUGSYMBOLLEVEL**
abiFilters **ABIFILTERS**
}
versionCode **VERSIONCODE**
versionName '**VERSIONNAME**'
consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
}
lint {
abortOnError false
}
androidResources {
noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
}**PACKAGING**
}
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**
@@ -0,0 +1,47 @@
apply plugin: 'com.android.library'
**APPLY_PLUGINS**
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "com.google.android.material:material:1.11.0"
**DEPS**}
android {
namespace "com.unity3d.player"
ndkPath "**NDKPATH**"
compileSdkVersion **APIVERSION**
buildToolsVersion '**BUILDTOOLS**'
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
buildFeatures {
viewBinding true
}
defaultConfig {
minSdkVersion **MINSDKVERSION**
targetSdkVersion **TARGETSDKVERSION**
ndk {
abiFilters **ABIFILTERS**
}
versionCode **VERSIONCODE**
versionName '**VERSIONNAME**'
consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
}
lintOptions {
abortOnError false
}
aaptOptions {
noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
}**PACKAGING_OPTIONS**
}
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f3bedb9070cd041a2bb8a27d9751aada
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 950fdc575e5b3b74ea1d3f1c60322d4f
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 86378052e9798924e8ee14f4fa780f0f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4c935d070fff35741adebc5424c4e02b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2111256da5c2b2a469d98ce0f103cdb7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,184 @@
package vn.tech3c.sdk.unity;
import android.util.Log;
import vn.tech3c.sdk.auth.callback.OnAuthCallback;
import vn.tech3c.sdk.auth.controller.Tech3CIdController;
import vn.tech3c.sdk.auth.entities.enums.LoginType;
import vn.tech3c.sdk.auth.exceptions.Tech3CIdException;
import com.unity3d.player.UnityPlayer;
/**
* Unity Bridge for Tech3C SDK
* This class receives callbacks from Tech3C SDK and sends them to Unity via UnitySendMessage
*/
public class Tech3CUnityBridge implements OnAuthCallback {
private static final String TAG = "Tech3CUnityBridge";
private static final String UNITY_GAME_OBJECT = "Tech3CSDKBridge";
private static Tech3CUnityBridge instance;
private OnUnityAuthCallback unityAuthCallback;
private OnUnityLogoutCallback unityLogoutCallback;
private OnUnityUserInfoCallback unityUserInfoCallback;
// Singleton
public static synchronized Tech3CUnityBridge getInstance() {
if (instance == null) {
instance = new Tech3CUnityBridge();
}
return instance;
}
// Interfaces for Unity callbacks
public interface OnUnityAuthCallback {
void onAuthSuccess(String userId, String password, String accessToken, String refreshToken, LoginType loginType, long expiryTime);
void onAuthCancelled();
void onAuthError(int errorCode, String errorMessage);
}
public interface OnUnityLogoutCallback {
void onLogoutSuccess();
void onLogoutError(int errorCode, String errorMessage);
}
public interface OnUnityUserInfoCallback {
void onUserInfoReceived(String userId, String username, String email, String phone);
void onUserInfoCancelled();
void onUserInfoError(int errorCode, String errorMessage);
}
// Set callbacks
public void setUnityAuthCallback(OnUnityAuthCallback callback) {
this.unityAuthCallback = callback;
}
public void setUnityLogoutCallback(OnUnityLogoutCallback callback) {
this.unityLogoutCallback = callback;
}
public void setUnityUserInfoCallback(OnUnityUserInfoCallback callback) {
this.unityUserInfoCallback = callback;
}
// Send message to Unity
private void sendToUnity(String methodName, String message) {
try {
UnityPlayer.UnitySendMessage(UNITY_GAME_OBJECT, methodName, message);
Log.d(TAG, "Sent to Unity: " + methodName + " - " + message);
} catch (Exception e) {
Log.e(TAG, "Error sending to Unity: " + e.getMessage());
}
}
// ========== OnAuthCallback Implementation ==========
@Override
public void onLoginSuccess(String userId, String password, String accessToken, String refreshToken, LoginType loginType, long expiryTime) {
Log.d(TAG, "onLoginSuccess: " + userId);
// Send to Unity
String message = userId + "|" + password + "|" + accessToken + "|" + refreshToken + "|" + loginType.name() + "|" + expiryTime;
sendToUnity("OnAuthSuccess", message);
// Also call Unity callback if set
if (unityAuthCallback != null) {
unityAuthCallback.onAuthSuccess(userId, password, accessToken, refreshToken, loginType, expiryTime);
}
}
@Override
public void onRegisterSuccess(String accessToken, String refreshToken, String userId, long expiryTime) {
Log.d(TAG, "onRegisterSuccess: " + userId);
// Treat register success as auth success (password is empty for register)
String message = userId + "|" + "" + "|" + accessToken + "|" + refreshToken + "|REGISTER|" + expiryTime;
sendToUnity("OnAuthSuccess", message);
if (unityAuthCallback != null) {
unityAuthCallback.onAuthSuccess(userId, "", accessToken, refreshToken, LoginType.ACCOUNT, expiryTime);
}
}
@Override
public void onAuthCancelled() {
Log.d(TAG, "onAuthCancelled");
sendToUnity("OnAuthCancelled", "");
if (unityAuthCallback != null) {
unityAuthCallback.onAuthCancelled();
}
}
@Override
public void onAuthScreenOpened() {
Log.d(TAG, "onAuthScreenOpened");
// Optional: Send to Unity if needed
}
@Override
public void onError(Tech3CIdException exception) {
Log.d(TAG, "onError: " + exception.getMessage());
String message = exception.getErrorCode() + "|" + exception.getMessage();
sendToUnity("OnAuthError", message);
if (unityAuthCallback != null) {
unityAuthCallback.onAuthError(exception.getErrorCode(), exception.getMessage());
}
}
// ========== Additional Callback Methods ==========
public void onLogoutSuccess() {
Log.d(TAG, "onLogoutSuccess");
sendToUnity("OnLogoutSuccess", "");
if (unityLogoutCallback != null) {
unityLogoutCallback.onLogoutSuccess();
}
}
public void onLogoutError(int errorCode, String errorMessage) {
Log.d(TAG, "onLogoutError: " + errorMessage);
String message = errorCode + "|" + errorMessage;
sendToUnity("OnLogoutError", message);
if (unityLogoutCallback != null) {
unityLogoutCallback.onLogoutError(errorCode, errorMessage);
}
}
public void onUserInfoReceived(String userId, String username, String email, String phone) {
Log.d(TAG, "onUserInfoReceived: " + userId);
String message = userId + "|" + username + "|" + email + "|" + phone;
sendToUnity("OnUserInfoReceived", message);
if (unityUserInfoCallback != null) {
unityUserInfoCallback.onUserInfoReceived(userId, username, email, phone);
}
}
public void onUserInfoCancelled() {
Log.d(TAG, "onUserInfoCancelled");
sendToUnity("OnUserInfoCancelled", "");
if (unityUserInfoCallback != null) {
unityUserInfoCallback.onUserInfoCancelled();
}
}
public void onUserInfoError(int errorCode, String errorMessage) {
Log.d(TAG, "onUserInfoError: " + errorMessage);
String message = errorCode + "|" + errorMessage;
sendToUnity("OnUserInfoError", message);
if (unityUserInfoCallback != null) {
unityUserInfoCallback.onUserInfoError(errorCode, errorMessage);
}
}
}
@@ -0,0 +1,32 @@
fileFormatVersion: 2
guid: e32ed25f4a2155a4f8106c56c82bb7fc
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:
Binary file not shown.
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3385cda9ff7dcd74ebc47f50d2e8196c
@@ -0,0 +1,2 @@
android.useAndroidX=true
android.enableJetifier=true
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5b51400b9b30374459987374d5fb2a0a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,43 @@
apply plugin: 'com.android.library'
**APPLY_PLUGINS**
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "com.google.android.material:material:1.11.0"
**DEPS**}
android {
namespace "com.unity3d.player"
ndkPath "**NDKPATH**"
compileSdkVersion **APIVERSION**
buildToolsVersion '**BUILDTOOLS**'
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
defaultConfig {
minSdkVersion **MINSDKVERSION**
targetSdkVersion **TARGETSDKVERSION**
ndk {
abiFilters **ABIFILTERS**
}
versionCode **VERSIONCODE**
versionName '**VERSIONNAME**'
consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
}
lintOptions {
abortOnError false
}
aaptOptions {
noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
}**PACKAGING_OPTIONS**
}
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 68ef4c077c6bfee47ad1aa16645a896d
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
#### Proguard class tech3c
-keep public class vn.tech3c.sdk.auth.entities.* {
public *;
}
-keep public class vn.tech3c.sdk.auth.entities.enums.* {
public *;
}
-keep public class vn.tech3c.sdk.auth.entities.response.* {
public *;
}
-keep public class vn.tech3c.sdk.auth.entities.request.* {
public *;
}
-keep public interface vn.tech3c.sdk.auth.** { *; }
-keep public class vn.tech3c.sdk.auth.controller.Tech3CIdController { public *;}
-keep public class vn.tech3c.sdk.auth.exceptions.Tech3CIdException { public *;}
-keep public class vn.tech3c.sdk.auth.Tech3CIdAuthentication {
public *;
}
-keep public class vn.tech3c.sdk.auth.config.Tech3CIdConfig {
public *;
}
-keep public class vn.tech3c.sdk.example.Tech3CUnityBridge { public *;}
-keep public class vn.tech3c.sdk.example.Tech3CUnityBridge$** { *; }
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0a1d44356c1df074d8cd78bee53cbafa
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c5469f93c69421146854ce74deba7931
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,452 @@
using UnityEngine;
using System;
namespace Tech3C
{
/// <summary>
/// Bridge class for Android platform to communicate with Tech3C native SDK
/// </summary>
public class Tech3CAndroidBridge : ITech3CNativeBridge
{
private const string CLASS_NAME = "vn.tech3c.sdk.auth.controller.Tech3CIdController";
private const string BRIDGE_CLASS = "vn.tech3c.sdk.unity.Tech3CUnityBridge";
private AndroidJavaObject controller;
private AndroidJavaObject unityBridge;
/// <summary>
/// Initialize the Tech3C SDK
/// </summary>
public void Initialize(string clientId, string clientSecret, Tech3CConfig config)
{
try
{
Debug.Log("[Tech3C] Bridge GameObject initialized");
// Initialize Unity Bridge for callbacks first
using (AndroidJavaClass bridgeClass = new AndroidJavaClass(BRIDGE_CLASS))
{
unityBridge = bridgeClass.CallStatic<AndroidJavaObject>("getInstance");
}
// Initialize controller with method chaining to set callback
if (controller == null)
{
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
using (AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
using (AndroidJavaClass controllerClass = new AndroidJavaClass(CLASS_NAME))
{
// Chain methods like MainActivity: initialize() -> setDebug() -> setOnAuthCallback()
controller = controllerClass.CallStatic<AndroidJavaObject>(
"initialize",
activity,
clientId,
clientSecret
)
// .Call<AndroidJavaObject>("setDebug", true)
// .Call<AndroidJavaObject>("setDisableExitLogin", false)
// .Call<AndroidJavaObject>("setEnableMaintenanceCheck", true)
.Call<AndroidJavaObject>("setOnAuthCallback", unityBridge);
Debug.Log("[Tech3C] Unity Bridge registered with native SDK");
}
}
if (controller != null)
{
// Apply configuration
ApplyConfig(config);
Debug.Log("[Tech3C] Initialized successfully");
}
else
{
Debug.LogError("[Tech3C] Failed to initialize controller");
}
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] Initialize error: {e.Message}");
}
}
/// <summary>
/// Apply configuration settings to the SDK
/// </summary>
private void ApplyConfig(Tech3CConfig config)
{
if (controller == null || config == null) return;
try
{
// Set debug mode (returns Tech3CIdController for chaining)
controller = controller.Call<AndroidJavaObject>("setDebug", config.debugMode);
// Set language - pass Java Language enum
using (AndroidJavaClass languageEnumClass = new AndroidJavaClass("vn.tech3c.sdk.auth.entities.enums.Language"))
{
string javaEnumValue = config.language == Language.Vietnamese ? "VIETNAMESE" : "ENGLISH";
AndroidJavaObject javaLanguage = languageEnumClass.GetStatic<AndroidJavaObject>(javaEnumValue);
controller = controller.Call<AndroidJavaObject>("setLanguageDisplay", javaLanguage);
}
// Set UI mode - pass Java UiMode enum
using (AndroidJavaClass uiModeEnumClass = new AndroidJavaClass("vn.tech3c.sdk.auth.entities.enums.UiMode"))
{
string javaEnumValue = config.uiMode == UiMode.Fullscreen ? "FULLSCREEN" : "DIALOG";
AndroidJavaObject javaUiMode = uiModeEnumClass.GetStatic<AndroidJavaObject>(javaEnumValue);
controller = controller.Call<AndroidJavaObject>("setUiMode", javaUiMode);
}
// Set orientation - pass Java OrientationMode enum
using (AndroidJavaClass orientationEnumClass = new AndroidJavaClass("vn.tech3c.sdk.auth.entities.enums.OrientationMode"))
{
string javaEnumValue = config.screenOrientation.ToString().ToUpper();
AndroidJavaObject javaOrientation = orientationEnumClass.GetStatic<AndroidJavaObject>(javaEnumValue);
controller = controller.Call<AndroidJavaObject>("setOrientation", javaOrientation);
}
// Set guest login
controller = controller.Call<AndroidJavaObject>("setEnableGuestLogin", config.enableGuestLogin);
// Set OTP requirement
controller = controller.Call<AndroidJavaObject>("setRequireOtp", config.requireOtp);
// Set disable exit login
controller = controller.Call<AndroidJavaObject>("setDisableExitLogin", config.disableExitLogin);
// Set maintenance check
controller = controller.Call<AndroidJavaObject>("setEnableMaintenanceCheck", config.enableMaintenanceCheck);
if (!string.IsNullOrEmpty(config.maintenanceCheckUrl))
{
controller = controller.Call<AndroidJavaObject>("setMaintenanceCheckUrl", config.maintenanceCheckUrl);
}
if (!string.IsNullOrEmpty(config.serverIp))
{
controller = controller.Call<AndroidJavaObject>("setIpMaintenanceCheck", config.serverIp);
}
Debug.Log("[Tech3C] Configuration applied successfully");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] ApplyConfig error: {e.Message}");
}
}
/// <summary>
/// Show authentication screen
/// </summary>
public void ShowAuth(IAuthCallback callback)
{
try
{
if (controller == null)
{
Debug.LogError("[Tech3C] Controller not initialized");
callback?.OnAuthError(-1, "SDK not initialized");
return;
}
// Register callback with bridge
Tech3CSDKBridge.SetAuthCallback(callback);
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
using (AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
{
controller.Call("showAuth", activity);
Debug.Log("[Tech3C] Auth screen shown");
}
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] ShowAuth error: {e.Message}");
callback?.OnAuthError(-1, e.Message);
}
}
/// <summary>
/// Logout current user
/// </summary>
public void Logout(ILogoutCallback callback)
{
try
{
if (controller == null)
{
Debug.LogError("[Tech3C] Controller not initialized");
callback?.OnLogoutError(-1, "SDK not initialized");
return;
}
// Register callback with bridge
Tech3CSDKBridge.SetLogoutCallback(callback);
controller.Call("logout");
Debug.Log("[Tech3C] Logout initiated");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] Logout error: {e.Message}");
callback?.OnLogoutError(-1, e.Message);
}
}
/// <summary>
/// Get user information
/// </summary>
public void GetUserInfo(IUserInfoCallback callback)
{
try
{
if (controller == null)
{
Debug.LogError("[Tech3C] Controller not initialized");
callback?.OnUserInfoError(-1, "SDK not initialized");
return;
}
// Register callback with bridge
Tech3CSDKBridge.SetUserInfoCallback(callback);
controller.Call("getUserInfo");
Debug.Log("[Tech3C] GetUserInfo called");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] GetUserInfo error: {e.Message}");
callback?.OnUserInfoError(-1, e.Message);
}
}
/// <summary>
/// Check if user is logged in
/// </summary>
public bool IsLoggedIn()
{
try
{
if (controller == null) return false;
return controller.Call<bool>("isLogin");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] IsLoggedIn error: {e.Message}");
return false;
}
}
/// <summary>
/// Get access token
/// </summary>
public string GetAccessToken()
{
try
{
if (controller == null) return null;
return controller.Call<string>("getAccessToken");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] GetAccessToken error: {e.Message}");
return null;
}
}
/// <summary>
/// Get refresh token
/// </summary>
public string GetRefreshToken()
{
try
{
if (controller == null) return null;
return controller.Call<string>("getRefreshToken");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] GetRefreshToken error: {e.Message}");
return null;
}
}
/// <summary>
/// Get user ID
/// </summary>
public string GetUserId()
{
try
{
if (controller == null) return null;
return controller.Call<string>("getUserId");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] GetUserId error: {e.Message}");
return null;
}
}
/// <summary>
/// Get device ID
/// </summary>
public string GetDeviceId()
{
try
{
if (controller == null) return null;
return controller.Call<string>("getDeviceId");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] GetDeviceId error: {e.Message}");
return null;
}
}
/// <summary>
/// Get login time
/// </summary>
public long GetLoginTime()
{
try
{
if (controller == null) return 0;
return controller.Call<long>("getLoginTime");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] GetLoginTime error: {e.Message}");
return 0;
}
}
/// <summary>
/// Get token expiry time
/// </summary>
public long GetTokenExpiry()
{
try
{
if (controller == null) return 0;
return controller.Call<long>("getTokenExpiry");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] GetTokenExpiry error: {e.Message}");
return 0;
}
}
/// <summary>
/// Check if token is expired
/// </summary>
public bool IsTokenExpired()
{
try
{
if (controller == null) return false;
return controller.Call<bool>("isTokenExpired");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] IsTokenExpired error: {e.Message}");
return false;
}
}
/// <summary>
/// Set language
/// </summary>
public void SetLanguage(Language language)
{
try
{
if (controller == null) return;
// Set language - pass Java Language enum
using (AndroidJavaClass languageEnumClass = new AndroidJavaClass("vn.tech3c.sdk.auth.entities.enums.Language"))
{
string javaEnumValue = language == Language.Vietnamese ? "VIETNAMESE" : "ENGLISH";
AndroidJavaObject javaLanguage = languageEnumClass.GetStatic<AndroidJavaObject>(javaEnumValue);
controller = controller.Call<AndroidJavaObject>("setLanguageDisplay", javaLanguage);
}
Debug.Log($"[Tech3C] Language set to {language}");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] SetLanguage error: {e.Message}");
}
}
/// <summary>
/// Set debug mode
/// </summary>
public void SetDebug(bool debug)
{
try
{
if (controller == null) return;
controller = controller.Call<AndroidJavaObject>("setDebug", debug);
Debug.Log($"[Tech3C] Debug mode set to {debug}");
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] SetDebug error: {e.Message}");
}
}
/// <summary>
/// Cleanup resources
/// </summary>
public void Cleanup()
{
try
{
if (controller != null)
{
controller.Call("cleanup");
controller.Dispose();
controller = null;
Debug.Log("[Tech3C] Cleanup completed");
}
}
catch (Exception e)
{
Debug.LogError($"[Tech3C] Cleanup error: {e.Message}");
}
}
}
/// <summary>
/// Interface for native bridge implementations
/// </summary>
public interface ITech3CNativeBridge
{
void Initialize(string clientId, string clientSecret, Tech3CConfig config);
void ShowAuth(IAuthCallback callback);
void Logout(ILogoutCallback callback);
void GetUserInfo(IUserInfoCallback callback);
bool IsLoggedIn();
string GetAccessToken();
string GetRefreshToken();
string GetUserId();
string GetDeviceId();
long GetLoginTime();
long GetTokenExpiry();
bool IsTokenExpired();
void SetLanguage(Language language);
void SetDebug(bool debug);
void Cleanup();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50744a202f3e9e24a80e10aecf427dac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+150
View File
@@ -0,0 +1,150 @@
using System;
namespace Tech3C
{
/// <summary>
/// Callback for authentication operations (login, register, etc.)
/// </summary>
public interface IAuthCallback
{
/// <summary>
/// Called when authentication is successful
/// </summary>
/// <param name="userId">The authenticated user ID</param>
/// <param name="password">The user password</param>
/// <param name="accessToken">The access token</param>
/// <param name="refreshToken">The refresh token</param>
/// <param name="loginType">The type of login used</param>
/// <param name="expiryTime">Token expiry timestamp</param>
void OnAuthSuccess(string userId, string password, string accessToken, string refreshToken, LoginType loginType, long expiryTime);
/// <summary>
/// Called when authentication is cancelled by the user
/// </summary>
void OnAuthCancelled();
/// <summary>
/// Called when an error occurs during authentication
/// </summary>
/// <param name="errorCode">The error code</param>
/// <param name="errorMessage">The error message</param>
void OnAuthError(int errorCode, string errorMessage);
}
/// <summary>
/// Callback for logout operations
/// </summary>
public interface ILogoutCallback
{
/// <summary>
/// Called when logout is successful
/// </summary>
void OnLogoutSuccess();
/// <summary>
/// Called when an error occurs during logout
/// </summary>
/// <param name="errorCode">The error code</param>
/// <param name="errorMessage">The error message</param>
void OnLogoutError(int errorCode, string errorMessage);
}
/// <summary>
/// Callback for user info operations
/// </summary>
public interface IUserInfoCallback
{
/// <summary>
/// Called when user info is successfully retrieved
/// </summary>
/// <param name="userId">The user ID</param>
/// <param name="username">The username</param>
/// <param name="email">The email address</param>
/// <param name="phone">The phone number</param>
void OnUserInfoReceived(string userId, string username, string email, string phone);
/// <summary>
/// Called when user info retrieval is cancelled
/// </summary>
void OnUserInfoCancelled();
/// <summary>
/// Called when an error occurs while retrieving user info
/// </summary>
/// <param name="errorCode">The error code</param>
/// <param name="errorMessage">The error message</param>
void OnUserInfoError(int errorCode, string errorMessage);
}
/// <summary>
/// Default implementation of IAuthCallback using Unity events
/// </summary>
[Serializable]
public class AuthCallback : IAuthCallback
{
public event Action<string, string, string, string, LoginType, long> OnAuthSuccessEvent;
public event Action OnAuthCancelledEvent;
public event Action<int, string> OnAuthErrorEvent;
public void OnAuthSuccess(string userId, string password, string accessToken, string refreshToken, LoginType loginType, long expiryTime)
{
OnAuthSuccessEvent?.Invoke(userId, password, accessToken, refreshToken, loginType, expiryTime);
}
public void OnAuthCancelled()
{
OnAuthCancelledEvent?.Invoke();
}
public void OnAuthError(int errorCode, string errorMessage)
{
OnAuthErrorEvent?.Invoke(errorCode, errorMessage);
}
}
/// <summary>
/// Default implementation of ILogoutCallback using Unity events
/// </summary>
[Serializable]
public class LogoutCallback : ILogoutCallback
{
public event Action OnLogoutSuccessEvent;
public event Action<int, string> OnLogoutErrorEvent;
public void OnLogoutSuccess()
{
OnLogoutSuccessEvent?.Invoke();
}
public void OnLogoutError(int errorCode, string errorMessage)
{
OnLogoutErrorEvent?.Invoke(errorCode, errorMessage);
}
}
/// <summary>
/// Default implementation of IUserInfoCallback using Unity events
/// </summary>
[Serializable]
public class UserInfoCallback : IUserInfoCallback
{
public event Action<string, string, string, string> OnUserInfoReceivedEvent;
public event Action OnUserInfoCancelledEvent;
public event Action<int, string> OnUserInfoErrorEvent;
public void OnUserInfoReceived(string userId, string username, string email, string phone)
{
OnUserInfoReceivedEvent?.Invoke(userId, username, email, phone);
}
public void OnUserInfoCancelled()
{
OnUserInfoCancelledEvent?.Invoke();
}
public void OnUserInfoError(int errorCode, string errorMessage)
{
OnUserInfoErrorEvent?.Invoke(errorCode, errorMessage);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed5aa8a6da34849438530838098c8ca0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+114
View File
@@ -0,0 +1,114 @@
using UnityEngine;
namespace Tech3C
{
/// <summary>
/// Configuration class for Tech3C SDK
/// </summary>
[CreateAssetMenu(fileName = "Tech3CConfig", menuName = "Tech3C SDK/Configuration", order = 1)]
public class Tech3CConfig : ScriptableObject
{
[Header("Client Credentials")]
[Tooltip("Client ID for Tech3C authentication")]
public string clientId;
[Tooltip("Client Secret for Tech3C authentication")]
public string clientSecret;
[Header("General Settings")]
[Tooltip("Enable debug mode for detailed logging")]
public bool debugMode = false;
[Tooltip("Display language for the SDK")]
public Language language = Language.English;
[Tooltip("Environment for the SDK")]
public Environment environment = Environment.Production;
[Header("UI Settings")]
[Tooltip("UI mode for authentication (Fullscreen or Dialog)")]
public UiMode uiMode = UiMode.Fullscreen;
[Tooltip("Dialog size when UI mode is Dialog")]
public DialogSize dialogSize = DialogSize.Medium;
[Tooltip("Screen orientation for authentication")]
public OrientationMode screenOrientation = OrientationMode.Auto;
[Tooltip("Disable exit button on login screen")]
public bool disableExitLogin = false;
[Header("Authentication Settings")]
[Tooltip("Enable guest login")]
public bool enableGuestLogin = false;
[Tooltip("Require OTP for authentication")]
public bool requireOtp = false;
[Tooltip("Enable Google login")]
public bool enableGoogleLogin = false;
[Tooltip("Enable Facebook login")]
public bool enableFacebookLogin = false;
[Tooltip("Enable Apple login")]
public bool enableAppleLogin = false;
[Header("Maintenance Settings")]
[Tooltip("Enable maintenance check")]
public bool enableMaintenanceCheck = false;
[Tooltip("Maintenance check URL")]
public string maintenanceCheckUrl;
[Tooltip("Server IP for maintenance check")]
public string serverIp;
[Header("Network Settings")]
[Tooltip("Timeout in seconds for network requests")]
public int timeoutSeconds = 30;
/// <summary>
/// Creates a default Tech3CConfig asset
/// </summary>
public static Tech3CConfig CreateDefault()
{
var config = CreateInstance<Tech3CConfig>();
config.clientId = "";
config.clientSecret = "";
config.debugMode = false;
config.language = Language.English;
config.environment = Environment.Production;
config.uiMode = UiMode.Fullscreen;
config.dialogSize = DialogSize.Medium;
config.screenOrientation = OrientationMode.Auto;
config.disableExitLogin = false;
config.enableGuestLogin = false;
config.requireOtp = false;
config.enableGoogleLogin = false;
config.enableFacebookLogin = false;
config.enableAppleLogin = false;
config.enableMaintenanceCheck = false;
config.maintenanceCheckUrl = "";
config.serverIp = "";
config.timeoutSeconds = 30;
return config;
}
/// <summary>
/// Validates the configuration
/// </summary>
public bool IsValid()
{
return !string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(clientSecret);
}
/// <summary>
/// Gets the language code string
/// </summary>
public string GetLanguageCode()
{
return language == Language.Vietnamese ? "vi" : "en";
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 95a442ac7dacf8b4484a10035308bc31
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+64
View File
@@ -0,0 +1,64 @@
using System;
namespace Tech3C
{
/// <summary>
/// Language options for the SDK
/// </summary>
public enum Language
{
Vietnamese,
English
}
/// <summary>
/// UI mode for authentication dialog
/// </summary>
public enum UiMode
{
Fullscreen,
Dialog
}
/// <summary>
/// Screen orientation for authentication
/// </summary>
public enum OrientationMode
{
Auto,
Portrait,
Landscape
}
/// <summary>
/// Login type for authentication
/// Matches the native SDK's LoginType enum
/// </summary>
public enum LoginType
{
GUEST,
ACCOUNT,
SOCIAL,
REGISTER // For register success handling
}
/// <summary>
/// Environment for the SDK
/// </summary>
public enum Environment
{
Production,
Staging,
Development
}
/// <summary>
/// Dialog size for UI mode
/// </summary>
public enum DialogSize
{
Small,
Medium,
Large
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c35f3ea36736dfe439eb6f4b8a314dde
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+473
View File
@@ -0,0 +1,473 @@
using UnityEngine;
using System;
namespace Tech3C
{
/// <summary>
/// Main API wrapper for Tech3C SDK
/// This is the main entry point for using the SDK in Unity
/// </summary>
public class Tech3CSDK : MonoBehaviour
{
private static Tech3CSDK instance;
private ITech3CNativeBridge nativeBridge;
private Tech3CConfig config;
private bool isInitialized = false;
#region Singleton
/// <summary>
/// Get the singleton instance of Tech3CSDK
/// </summary>
public static Tech3CSDK Instance
{
get
{
if (instance == null)
{
GameObject go = new GameObject("Tech3CSDK");
instance = go.AddComponent<Tech3CSDK>();
DontDestroyOnLoad(go);
}
return instance;
}
}
private void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else if (instance != this)
{
Destroy(gameObject);
}
}
#endregion
#region Initialization
/// <summary>
/// Initialize the Tech3C SDK with configuration
/// </summary>
/// <param name="config">The configuration object</param>
public void Initialize(Tech3CConfig config)
{
if (config == null)
{
Debug.LogError("[Tech3C] Config cannot be null");
return;
}
if (!config.IsValid())
{
Debug.LogError("[Tech3C] Invalid config: Client ID and Client Secret are required");
return;
}
this.config = config;
// Ensure Tech3CSDKBridge is created to receive callbacks from native code
var bridge = Tech3CSDKBridge.Instance;
Debug.Log("[Tech3C] Tech3CSDKBridge ensured for callbacks");
// Create platform-specific bridge
CreateNativeBridge();
if (nativeBridge != null)
{
nativeBridge.Initialize(config.clientId, config.clientSecret, config);
isInitialized = true;
Debug.Log("[Tech3C] Initialization completed successfully");
}
else
{
Debug.LogError("[Tech3C] Failed to create native bridge");
}
}
/// <summary>
/// Initialize the Tech3C SDK with client credentials
/// </summary>
/// <param name="clientId">The client ID</param>
/// <param name="clientSecret">The client secret</param>
public void Initialize(string clientId, string clientSecret)
{
if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret))
{
Debug.LogError("[Tech3C] Client ID and Client Secret are required");
return;
}
config = Tech3CConfig.CreateDefault();
config.clientId = clientId;
config.clientSecret = clientSecret;
Initialize(config);
}
private void CreateNativeBridge()
{
#if UNITY_ANDROID && !UNITY_EDITOR
nativeBridge = new Tech3CAndroidBridge();
#elif UNITY_IOS && !UNITY_EDITOR
nativeBridge = new Tech3CiOSBridge();
#else
#if UNITY_ANDROID
nativeBridge = new Tech3CAndroidBridge();
#elif UNITY_IOS
nativeBridge = new Tech3CiOSBridge();
#else
Debug.LogWarning("[Tech3C] Running in Editor or unsupported platform. Using mock implementation.");
nativeBridge = new MockBridge();
#endif
#endif
}
#endregion
#region Authentication
/// <summary>
/// Show authentication screen (login/register/forgot password)
/// </summary>
/// <param name="callback">The callback for authentication result</param>
public void ShowAuth(IAuthCallback callback)
{
if (!isInitialized)
{
Debug.LogError("[Tech3C] SDK not initialized. Call Initialize() first.");
callback?.OnAuthError(-1, "SDK not initialized");
return;
}
nativeBridge?.ShowAuth(callback);
}
/// <summary>
/// Show authentication screen without callback
/// </summary>
public void ShowAuth()
{
ShowAuth(null);
}
#endregion
#region User Management
/// <summary>
/// Logout current user
/// </summary>
/// <param name="callback">The callback for logout result</param>
public void Logout(ILogoutCallback callback)
{
if (!isInitialized)
{
Debug.LogError("[Tech3C] SDK not initialized. Call Initialize() first.");
callback?.OnLogoutError(-1, "SDK not initialized");
return;
}
nativeBridge?.Logout(callback);
}
/// <summary>
/// Logout current user without callback
/// </summary>
public void Logout()
{
Logout(null);
}
/// <summary>
/// Get user information
/// </summary>
/// <param name="callback">The callback for user info result</param>
public void GetUserInfo(IUserInfoCallback callback)
{
if (!isInitialized)
{
Debug.LogError("[Tech3C] SDK not initialized. Call Initialize() first.");
callback?.OnUserInfoError(-1, "SDK not initialized");
return;
}
nativeBridge?.GetUserInfo(callback);
}
/// <summary>
/// Get user information without callback
/// </summary>
public void GetUserInfo()
{
GetUserInfo(null);
}
#endregion
#region State Checkers
/// <summary>
/// Check if user is logged in
/// </summary>
public bool IsLoggedIn()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return false;
}
return nativeBridge?.IsLoggedIn() ?? false;
}
/// <summary>
/// Check if access token is expired
/// </summary>
public bool IsTokenExpired()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return true;
}
return nativeBridge?.IsTokenExpired() ?? true;
}
#endregion
#region Token Management
/// <summary>
/// Get access token
/// </summary>
public string GetAccessToken()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return null;
}
return nativeBridge?.GetAccessToken();
}
/// <summary>
/// Get refresh token
/// </summary>
public string GetRefreshToken()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return null;
}
return nativeBridge?.GetRefreshToken();
}
#endregion
#region User Information
/// <summary>
/// Get user ID
/// </summary>
public string GetUserId()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return null;
}
return nativeBridge?.GetUserId();
}
/// <summary>
/// Get device ID
/// </summary>
public string GetDeviceId()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return null;
}
return nativeBridge?.GetDeviceId();
}
/// <summary>
/// Get login timestamp
/// </summary>
public long GetLoginTime()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return 0;
}
return nativeBridge?.GetLoginTime() ?? 0;
}
/// <summary>
/// Get token expiry timestamp
/// </summary>
public long GetTokenExpiry()
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return 0;
}
return nativeBridge?.GetTokenExpiry() ?? 0;
}
#endregion
#region Configuration
/// <summary>
/// Set display language
/// </summary>
/// <param name="language">The language to set</param>
public void SetLanguage(Language language)
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return;
}
nativeBridge?.SetLanguage(language);
}
/// <summary>
/// Set debug mode
/// </summary>
/// <param name="debug">Enable or disable debug mode</param>
public void SetDebug(bool debug)
{
if (!isInitialized)
{
Debug.LogWarning("[Tech3C] SDK not initialized");
return;
}
nativeBridge?.SetDebug(debug);
}
#endregion
#region Cleanup
/// <summary>
/// Cleanup SDK resources
/// </summary>
public void Cleanup()
{
nativeBridge?.Cleanup();
nativeBridge = null;
config = null;
isInitialized = false;
Debug.Log("[Tech3C] Cleanup completed");
}
private void OnDestroy()
{
Cleanup();
}
#endregion
#region Properties
/// <summary>
/// Get the current configuration
/// </summary>
public Tech3CConfig Config => config;
/// <summary>
/// Check if SDK is initialized
/// </summary>
public bool IsInitialized => isInitialized;
#endregion
}
/// <summary>
/// Mock bridge for testing in editor or unsupported platforms
/// </summary>
internal class MockBridge : ITech3CNativeBridge
{
private bool isLoggedIn = false;
private string accessToken = "mock_access_token";
private string refreshToken = "mock_refresh_token";
private string userId = "mock_user_id";
public void Initialize(string clientId, string clientSecret, Tech3CConfig config)
{
Debug.Log($"[Tech3C Mock] Initialized with Client ID: {clientId}");
}
public void ShowAuth(IAuthCallback callback)
{
Debug.Log("[Mock3C Mock] ShowAuth called");
isLoggedIn = true;
string password = "mock_password";
callback?.OnAuthSuccess(userId, password, accessToken, refreshToken, LoginType.ACCOUNT, DateTime.Now.Ticks + 3600000);
}
public void Logout(ILogoutCallback callback)
{
Debug.Log("[Tech3C Mock] Logout called");
isLoggedIn = false;
callback?.OnLogoutSuccess();
}
public void GetUserInfo(IUserInfoCallback callback)
{
Debug.Log("[Tech3C Mock] GetUserInfo called");
callback?.OnUserInfoReceived(userId, "mock_username", "mock@example.com", "1234567890");
}
public bool IsLoggedIn() => isLoggedIn;
public string GetAccessToken() => isLoggedIn ? accessToken : null;
public string GetRefreshToken() => isLoggedIn ? refreshToken : null;
public string GetUserId() => isLoggedIn ? userId : null;
public string GetDeviceId() => "mock_device_id";
public long GetLoginTime() => isLoggedIn ? DateTime.Now.Ticks : 0;
public long GetTokenExpiry() => isLoggedIn ? DateTime.Now.Ticks + 3600000 : 0;
public bool IsTokenExpired() => false;
public void SetLanguage(Language language)
{
Debug.Log($"[Tech3C Mock] Language set to {language}");
}
public void SetDebug(bool debug)
{
Debug.Log($"[Tech3C Mock] Debug mode set to {debug}");
}
public void Cleanup()
{
Debug.Log("[Tech3C Mock] Cleanup completed");
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3afb6189c673cea45a34e6e75c1f5ccb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+332
View File
@@ -0,0 +1,332 @@
using UnityEngine;
using System;
namespace Tech3C
{
/// <summary>
/// Bridge component to receive callbacks from native Android/iOS SDK via Unity messaging
/// This GameObject receives UnitySendMessage calls from native code
/// </summary>
public class Tech3CSDKBridge : MonoBehaviour
{
private static Tech3CSDKBridge instance;
// Callback references
private static IAuthCallback authCallback;
private static ILogoutCallback logoutCallback;
private static IUserInfoCallback userInfoCallback;
#region Singleton
public static Tech3CSDKBridge Instance
{
get
{
if (instance == null)
{
GameObject go = new GameObject("Tech3CSDKBridge");
instance = go.AddComponent<Tech3CSDKBridge>();
DontDestroyOnLoad(go);
}
return instance;
}
}
private void Awake()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
Debug.Log("[Tech3C Bridge] Bridge initialized");
}
else if (instance != this)
{
Destroy(gameObject);
}
}
#endregion
#region Set Callbacks
/// <summary>
/// Set the auth callback to be invoked when auth events occur
/// </summary>
public static void SetAuthCallback(IAuthCallback callback)
{
authCallback = callback;
Debug.Log("[Tech3C Bridge] Auth callback set");
}
/// <summary>
/// Set the logout callback to be invoked when logout events occur
/// </summary>
public static void SetLogoutCallback(ILogoutCallback callback)
{
logoutCallback = callback;
Debug.Log("[Tech3C Bridge] Logout callback set");
}
/// <summary>
/// Set the user info callback to be invoked when user info events occur
/// </summary>
public static void SetUserInfoCallback(IUserInfoCallback callback)
{
userInfoCallback = callback;
Debug.Log("[Tech3C Bridge] User info callback set");
}
#endregion
#region Auth Callbacks
/// <summary>
/// Called from native code when authentication is successful
/// Message format: "userId|password|accessToken|refreshToken|loginType|expiryTime"
/// </summary>
public void OnAuthSuccess(string message)
{
Debug.Log($"[Tech3C Bridge] OnAuthSuccess received: {message}");
if (authCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No auth callback registered");
return;
}
try
{
string[] parts = message.Split('|');
if (parts.Length >= 6)
{
string userId = parts[0];
string password = parts[1];
string accessToken = parts[2];
string refreshToken = parts[3];
LoginType loginType = (LoginType)Enum.Parse(typeof(LoginType), parts[4]);
long expiryTime = long.Parse(parts[5]);
Debug.Log($"[Tech3C Bridge] Parsed auth success: userId={userId}, loginType={loginType}");
authCallback.OnAuthSuccess(userId, password, accessToken, refreshToken, loginType, expiryTime);
}
else
{
Debug.LogError($"[Tech3C Bridge] Invalid message format: {message}");
}
}
catch (Exception e)
{
Debug.LogError($"[Tech3C Bridge] Error parsing auth success message: {e.Message}");
}
}
/// <summary>
/// Called from native code when authentication is cancelled
/// </summary>
public void OnAuthCancelled(string message)
{
Debug.Log("[Tech3C Bridge] OnAuthCancelled received");
if (authCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No auth callback registered");
return;
}
authCallback.OnAuthCancelled();
}
/// <summary>
/// Called from native code when an authentication error occurs
/// Message format: "errorCode|errorMessage"
/// </summary>
public void OnAuthError(string message)
{
Debug.Log($"[Tech3C Bridge] OnAuthError received: {message}");
if (authCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No auth callback registered");
return;
}
try
{
string[] parts = message.Split('|');
int errorCode = -1;
string errorMessage = "Unknown error";
if (parts.Length >= 1)
{
int.TryParse(parts[0], out errorCode);
}
if (parts.Length >= 2)
{
errorMessage = parts[1];
}
Debug.Log($"[Tech3C Bridge] Parsed auth error: code={errorCode}, message={errorMessage}");
authCallback.OnAuthError(errorCode, errorMessage);
}
catch (Exception e)
{
Debug.LogError($"[Tech3C Bridge] Error parsing auth error message: {e.Message}");
}
}
#endregion
#region Logout Callbacks
/// <summary>
/// Called from native code when logout is successful
/// </summary>
public void OnLogoutSuccess(string message)
{
Debug.Log("[Tech3C Bridge] OnLogoutSuccess received");
if (logoutCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No logout callback registered");
return;
}
logoutCallback.OnLogoutSuccess();
}
/// <summary>
/// Called from native code when a logout error occurs
/// Message format: "errorCode|errorMessage"
/// </summary>
public void OnLogoutError(string message)
{
Debug.Log($"[Tech3C Bridge] OnLogoutError received: {message}");
if (logoutCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No logout callback registered");
return;
}
try
{
string[] parts = message.Split('|');
int errorCode = -1;
string errorMessage = "Unknown error";
if (parts.Length >= 1)
{
int.TryParse(parts[0], out errorCode);
}
if (parts.Length >= 2)
{
errorMessage = parts[1];
}
logoutCallback.OnLogoutError(errorCode, errorMessage);
}
catch (Exception e)
{
Debug.LogError($"[Tech3C Bridge] Error parsing logout error message: {e.Message}");
}
}
#endregion
#region User Info Callbacks
/// <summary>
/// Called from native code when user info is received
/// Message format: "userId|username|email|phone"
/// </summary>
public void OnUserInfoReceived(string message)
{
Debug.Log($"[Tech3C Bridge] OnUserInfoReceived received: {message}");
if (userInfoCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No user info callback registered");
return;
}
try
{
string[] parts = message.Split('|');
if (parts.Length >= 4)
{
string userId = parts[0];
string username = parts[1];
string email = parts[2];
string phone = parts[3];
Debug.Log($"[Tech3C Bridge] Parsed user info: userId={userId}, username={username}");
userInfoCallback.OnUserInfoReceived(userId, username, email, phone);
}
else
{
Debug.LogError($"[Tech3C Bridge] Invalid message format: {message}");
}
}
catch (Exception e)
{
Debug.LogError($"[Tech3C Bridge] Error parsing user info message: {e.Message}");
}
}
/// <summary>
/// Called from native code when user info retrieval is cancelled
/// </summary>
public void OnUserInfoCancelled(string message)
{
Debug.Log("[Tech3C Bridge] OnUserInfoCancelled received");
if (userInfoCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No user info callback registered");
return;
}
userInfoCallback.OnUserInfoCancelled();
}
/// <summary>
/// Called from native code when a user info error occurs
/// Message format: "errorCode|errorMessage"
/// </summary>
public void OnUserInfoError(string message)
{
Debug.Log($"[Tech3C Bridge] OnUserInfoError received: {message}");
if (userInfoCallback == null)
{
Debug.LogWarning("[Tech3C Bridge] No user info callback registered");
return;
}
try
{
string[] parts = message.Split('|');
int errorCode = -1;
string errorMessage = "Unknown error";
if (parts.Length >= 1)
{
int.TryParse(parts[0], out errorCode);
}
if (parts.Length >= 2)
{
errorMessage = parts[1];
}
userInfoCallback.OnUserInfoError(errorCode, errorMessage);
}
catch (Exception e)
{
Debug.LogError($"[Tech3C Bridge] Error parsing user info error message: {e.Message}");
}
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 46cf26ff28457b04890e322b5b161a67
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+147
View File
@@ -0,0 +1,147 @@
using UnityEngine;
using System;
namespace Tech3C
{
/// <summary>
/// Bridge class for iOS platform to communicate with Tech3C native SDK
/// Note: iOS implementation requires native framework. This is a placeholder.
/// </summary>
public class Tech3CiOSBridge : ITech3CNativeBridge
{
private bool initialized = false;
/// <summary>
/// Initialize the Tech3C SDK
/// </summary>
public void Initialize(string clientId, string clientSecret, Tech3CConfig config)
{
Debug.LogWarning("[Tech3C] iOS platform is not yet supported. Please provide the native iOS framework.");
initialized = true;
}
/// <summary>
/// Show authentication screen
/// </summary>
public void ShowAuth(IAuthCallback callback)
{
Debug.LogWarning("[Tech3C] ShowAuth is not implemented for iOS platform");
callback?.OnAuthError(-1, "iOS platform not supported");
}
/// <summary>
/// Logout current user
/// </summary>
public void Logout(ILogoutCallback callback)
{
Debug.LogWarning("[Tech3C] Logout is not implemented for iOS platform");
callback?.OnLogoutError(-1, "iOS platform not supported");
}
/// <summary>
/// Get user information
/// </summary>
public void GetUserInfo(IUserInfoCallback callback)
{
Debug.LogWarning("[Tech3C] GetUserInfo is not implemented for iOS platform");
callback?.OnUserInfoError(-1, "iOS platform not supported");
}
/// <summary>
/// Check if user is logged in
/// </summary>
public bool IsLoggedIn()
{
Debug.LogWarning("[Tech3C] IsLoggedIn is not implemented for iOS platform");
return false;
}
/// <summary>
/// Get access token
/// </summary>
public string GetAccessToken()
{
Debug.LogWarning("[Tech3C] GetAccessToken is not implemented for iOS platform");
return null;
}
/// <summary>
/// Get refresh token
/// </summary>
public string GetRefreshToken()
{
Debug.LogWarning("[Tech3C] GetRefreshToken is not implemented for iOS platform");
return null;
}
/// <summary>
/// Get user ID
/// </summary>
public string GetUserId()
{
Debug.LogWarning("[Tech3C] GetUserId is not implemented for iOS platform");
return null;
}
/// <summary>
/// Get device ID
/// </summary>
public string GetDeviceId()
{
Debug.LogWarning("[Tech3C] GetDeviceId is not implemented for iOS platform");
return null;
}
/// <summary>
/// Get login time
/// </summary>
public long GetLoginTime()
{
Debug.LogWarning("[Tech3C] GetLoginTime is not implemented for iOS platform");
return 0;
}
/// <summary>
/// Get token expiry time
/// </summary>
public long GetTokenExpiry()
{
Debug.LogWarning("[Tech3C] GetTokenExpiry is not implemented for iOS platform");
return 0;
}
/// <summary>
/// Check if token is expired
/// </summary>
public bool IsTokenExpired()
{
Debug.LogWarning("[Tech3C] IsTokenExpired is not implemented for iOS platform");
return false;
}
/// <summary>
/// Set language
/// </summary>
public void SetLanguage(Language language)
{
Debug.LogWarning("[Tech3C] SetLanguage is not implemented for iOS platform");
}
/// <summary>
/// Set debug mode
/// </summary>
public void SetDebug(bool debug)
{
Debug.LogWarning("[Tech3C] SetDebug is not implemented for iOS platform");
}
/// <summary>
/// Cleanup resources
/// </summary>
public void Cleanup()
{
Debug.Log("[Tech3C] iOS bridge cleanup completed");
initialized = false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7199bd7af3b75294c84f9d6451df86d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a947977eda82ae34b85413ea17ef265a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+473
View File
@@ -0,0 +1,473 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
namespace Tech3C
{
/// <summary>
/// Simple demo that creates UI programmatically
/// Just attach this script to any GameObject in your scene
/// </summary>
public class Tech3CSimpleDemo : MonoBehaviour
{
[Header("Configuration")]
public string clientId = "your_client_id";
public string clientSecret = "your_client_secret";
private Canvas canvas;
private Text logText;
private AuthCallback authCallback;
private LogoutCallback logoutCallback;
private GameObject dialogPanel;
private Text dialogText;
private Button dialogCloseButton;
private void Start()
{
EnsureEventSystem();
CreateUI();
SetupCallbacks();
// Auto-initialize SDK
if (!string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(clientSecret))
{
Log($"Initializing Tech3C SDK...\n Client ID: {clientId}");
Tech3CSDK.Instance.Initialize(clientId, clientSecret);
if (Tech3CSDK.Instance.IsInitialized)
{
Log("✓ SDK Initialized Successfully!");
}
else
{
Log("✗ Failed to initialize SDK");
}
}
else
{
Log("⚠ Client ID and/or Client Secret not set. Please configure in Inspector.");
}
Debug.Log("[Tech3C Demo] Tech3C SDK Simple Demo Started");
}
private void EnsureEventSystem()
{
if (EventSystem.current == null)
{
GameObject eventSystemGO = new GameObject("EventSystem");
eventSystemGO.AddComponent<EventSystem>();
eventSystemGO.AddComponent<StandaloneInputModule>();
Debug.Log("[Tech3C Demo] EventSystem created");
}
}
private void CreateUI()
{
// Create Canvas
GameObject canvasGO = new GameObject("Tech3CDemoCanvas");
canvasGO.transform.SetParent(transform);
canvas = canvasGO.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
// Configure CanvasScaler for responsive 16:9 ratio
CanvasScaler canvasScaler = canvasGO.AddComponent<CanvasScaler>();
canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
canvasScaler.referenceResolution = new Vector2(1920, 1080); // 16:9 ratio
canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
canvasScaler.matchWidthOrHeight = 0.5f; // Balance between width and height
canvasGO.AddComponent<GraphicRaycaster>();
// Create Scroll Panel
GameObject scrollPanel = new GameObject("ScrollPanel");
scrollPanel.transform.SetParent(canvasGO.transform, false);
RectTransform scrollPanelRect = scrollPanel.AddComponent<RectTransform>();
scrollPanelRect.anchorMin = Vector2.zero;
scrollPanelRect.anchorMax = Vector2.one;
scrollPanelRect.sizeDelta = Vector2.zero;
Image scrollPanelImage = scrollPanel.AddComponent<Image>();
scrollPanelImage.color = new Color(0.2f, 0.2f, 0.2f, 1f);
// Create ScrollRect
ScrollRect scrollRect = scrollPanel.AddComponent<ScrollRect>();
scrollRect.horizontal = false;
scrollRect.vertical = true;
scrollRect.scrollSensitivity = 50f;
// Create Content Panel
GameObject panel = new GameObject("Content");
panel.transform.SetParent(scrollPanel.transform, false);
RectTransform panelRect = panel.AddComponent<RectTransform>();
panelRect.anchorMin = new Vector2(0, 1);
panelRect.anchorMax = new Vector2(1, 1);
panelRect.pivot = new Vector2(0.5f, 1f);
panelRect.sizeDelta = new Vector2(0, 0);
scrollRect.content = panelRect;
// Create Vertical Layout Group
VerticalLayoutGroup layoutGroup = panel.AddComponent<VerticalLayoutGroup>();
layoutGroup.childControlHeight = false;
layoutGroup.childControlWidth = true;
layoutGroup.childForceExpandWidth = true;
layoutGroup.childForceExpandHeight = false;
layoutGroup.spacing = 15;
layoutGroup.padding = new RectOffset(40, 40, 40, 40);
ContentSizeFitter contentSizeFitter = panel.AddComponent<ContentSizeFitter>();
contentSizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// Create Title
CreateTextResponsive(panel.transform, "Tech3C SDK Demo", 28, TextAnchor.MiddleCenter, 60);
// Create Separator
CreateTextResponsive(panel.transform, "--- Authentication ---", 18, TextAnchor.MiddleCenter, 30);
// Create Show Auth Button
Button showAuthButton = CreateButtonResponsive(panel.transform, "Show Auth Screen", 70);
showAuthButton.onClick.AddListener(OnShowAuthClick);
// Create Logout Button
Button logoutButton = CreateButtonResponsive(panel.transform, "Logout", 70);
logoutButton.onClick.AddListener(OnLogoutClick);
// Create Log Text
CreateTextResponsive(panel.transform, "Logs:", 16, TextAnchor.MiddleLeft, 35);
logText = CreateTextResponsive(panel.transform, "Ready...", 16, TextAnchor.MiddleLeft, 400);
logText.color = Color.green;
// Reposition panel
panelRect.anchoredPosition = Vector2.zero;
}
private void SetupCallbacks()
{
// Auth callback
authCallback = new AuthCallback();
authCallback.OnAuthSuccessEvent += (userId, password, accessToken, refreshToken, loginType, expiryTime) =>
{
Debug.Log($"[Tech3C Demo] === AUTH SUCCESS CALLBACK FIRED ===");
Debug.Log($"[Tech3C Demo] UserId: {userId}");
Debug.Log($"[Tech3C Demo] Password: {password?.Substring(0, Math.Min(3, password?.Length ?? 0))}...");
Debug.Log($"[Tech3C Demo] LoginType: {loginType}");
Debug.Log($"[Tech3C Demo] AccessToken: {accessToken?.Substring(0, Math.Min(20, accessToken?.Length ?? 0))}...");
Debug.Log($"[Tech3C Demo] RefreshToken: {refreshToken?.Substring(0, Math.Min(20, refreshToken?.Length ?? 0))}...");
Debug.Log($"[Tech3C Demo] ExpiryTime: {expiryTime}");
Log($"✓ Auth Success!\n User ID: {userId}\n Password: {password}\n Login Type: {loginType}\n Token: {accessToken?.Substring(0, Math.Min(20, accessToken?.Length ?? 0))}...");
ShowAuthSuccessDialog(userId, password, loginType.ToString());
};
authCallback.OnAuthCancelledEvent += () =>
{
Debug.Log($"[Tech3C Demo] === AUTH CANCELLED CALLBACK FIRED ===");
Log("✗ Auth Cancelled by user");
};
authCallback.OnAuthErrorEvent += (errorCode, errorMessage) =>
{
Debug.Log($"[Tech3C Demo] === AUTH ERROR CALLBACK FIRED ===");
Debug.Log($"[Tech3C Demo] ErrorCode: {errorCode}");
Debug.Log($"[Tech3C Demo] ErrorMessage: {errorMessage}");
Log($"✗ Auth Error [{errorCode}]: {errorMessage}");
};
// Logout callback
logoutCallback = new LogoutCallback();
logoutCallback.OnLogoutSuccessEvent += () =>
{
Debug.Log($"[Tech3C Demo] === LOGOUT SUCCESS CALLBACK FIRED ===");
Log("✓ Logout Successful");
};
logoutCallback.OnLogoutErrorEvent += (errorCode, errorMessage) =>
{
Debug.Log($"[Tech3C Demo] === LOGOUT ERROR CALLBACK FIRED ===");
Debug.Log($"[Tech3C Demo] ErrorCode: {errorCode}");
Debug.Log($"[Tech3C Demo] ErrorMessage: {errorMessage}");
Log($"✗ Logout Error [{errorCode}]: {errorMessage}");
};
}
#region Button Handlers
private void OnInitializeClick(string newClientId, string newClientSecret)
{
if (string.IsNullOrEmpty(newClientId) || string.IsNullOrEmpty(newClientSecret))
{
Log("✗ Client ID and Client Secret are required!");
return;
}
clientId = newClientId;
clientSecret = newClientSecret;
Log($"Initializing Tech3C SDK...\n Client ID: {clientId}");
Tech3CSDK.Instance.Initialize(clientId, clientSecret);
if (Tech3CSDK.Instance.IsInitialized)
{
Log("✓ SDK Initialized Successfully!");
}
else
{
Log("✗ Failed to initialize SDK");
}
}
private void OnShowAuthClick()
{
if (!Tech3CSDK.Instance.IsInitialized)
{
Log("✗ SDK not initialized. Click Initialize first!");
return;
}
Log("Opening Auth Screen...");
Tech3CSDK.Instance.ShowAuth(authCallback);
}
private void OnLogoutClick()
{
if (!Tech3CSDK.Instance.IsInitialized)
{
Log("✗ SDK not initialized.");
return;
}
Log("Logging out...");
Tech3CSDK.Instance.Logout(logoutCallback);
}
#endregion
#region UI Helper Methods
private Button CreateButton(Transform parent, string text, float width, float height)
{
GameObject buttonGO = new GameObject(text.Replace(" ", "_"));
buttonGO.transform.SetParent(parent, false);
RectTransform rect = buttonGO.AddComponent<RectTransform>();
rect.sizeDelta = new Vector2(width, height);
Image image = buttonGO.AddComponent<Image>();
image.color = new Color(0.3f, 0.5f, 0.8f, 1f);
Button button = buttonGO.AddComponent<Button>();
// Set up button transition for visual feedback
ColorBlock colors = button.colors;
colors.normalColor = new Color(0.3f, 0.5f, 0.8f, 1f);
colors.highlightedColor = new Color(0.4f, 0.6f, 0.9f, 1f);
colors.pressedColor = new Color(0.2f, 0.4f, 0.7f, 1f);
colors.selectedColor = new Color(0.3f, 0.5f, 0.8f, 1f);
colors.colorMultiplier = 1f;
button.colors = colors;
GameObject textGO = new GameObject("Text");
textGO.transform.SetParent(buttonGO.transform, false);
RectTransform textRect = textGO.AddComponent<RectTransform>();
textRect.anchorMin = Vector2.zero;
textRect.anchorMax = Vector2.one;
textRect.sizeDelta = Vector2.zero;
Text textComponent = textGO.AddComponent<Text>();
textComponent.text = text;
textComponent.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
textComponent.fontSize = 18;
textComponent.alignment = TextAnchor.MiddleCenter;
textComponent.color = Color.white;
textComponent.raycastTarget = false; // Important: Allow click to pass through to button
Debug.Log($"[Tech3C Demo] Created button: {text}");
return button;
}
private Text CreateText(Transform parent, string text, int fontSize, TextAnchor alignment, float width, float height)
{
GameObject textGO = new GameObject("Text");
textGO.transform.SetParent(parent, false);
RectTransform rect = textGO.AddComponent<RectTransform>();
rect.sizeDelta = new Vector2(width, height);
Text textComponent = textGO.AddComponent<Text>();
textComponent.text = text;
textComponent.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
textComponent.fontSize = fontSize;
textComponent.alignment = alignment;
textComponent.color = Color.white;
textComponent.raycastTarget = false; // Prevent text from blocking button clicks
return textComponent;
}
private Text CreateLabel(Transform parent, string text)
{
return CreateText(parent, text, 14, TextAnchor.MiddleLeft, 500, 30);
}
private InputField CreateInputField(Transform parent, string defaultValue)
{
GameObject inputGO = new GameObject("InputField");
inputGO.transform.SetParent(parent, false);
RectTransform rect = inputGO.AddComponent<RectTransform>();
rect.sizeDelta = new Vector2(500, 40);
Image image = inputGO.AddComponent<Image>();
image.color = new Color(0.3f, 0.3f, 0.3f, 1f);
InputField inputField = inputGO.AddComponent<InputField>();
inputField.textComponent = CreateText(inputGO.transform, defaultValue, 16, TextAnchor.MiddleLeft, 500, 40);
inputField.textComponent.color = Color.black;
inputField.textComponent.raycastTarget = false; // Prevent text from blocking input
inputField.lineType = InputField.LineType.MultiLineSubmit;
Debug.Log($"[Tech3C Demo] Created input field with default value");
return inputField;
}
private void Log(string message)
{
Debug.Log($"[Tech3C Demo] {message}");
if (logText != null)
{
string timestamp = System.DateTime.Now.ToString("HH:mm:ss");
logText.text = $"[{timestamp}] {message}\n{logText.text}";
}
}
#endregion
#region Responsive UI Helper Methods
private Button CreateButtonResponsive(Transform parent, string text, float height)
{
GameObject buttonGO = new GameObject(text.Replace(" ", "_"));
buttonGO.transform.SetParent(parent, false);
RectTransform rect = buttonGO.AddComponent<RectTransform>();
rect.anchorMin = new Vector2(0, 0);
rect.anchorMax = new Vector2(1, 0);
rect.pivot = new Vector2(0.5f, 0.5f);
rect.sizeDelta = new Vector2(-80, height); // -80 for left/right padding
Image image = buttonGO.AddComponent<Image>();
image.color = new Color(0.3f, 0.5f, 0.8f, 1f);
Button button = buttonGO.AddComponent<Button>();
// Set up button transition for visual feedback
ColorBlock colors = button.colors;
colors.normalColor = new Color(0.3f, 0.5f, 0.8f, 1f);
colors.highlightedColor = new Color(0.4f, 0.6f, 0.9f, 1f);
colors.pressedColor = new Color(0.2f, 0.4f, 0.7f, 1f);
colors.selectedColor = new Color(0.3f, 0.5f, 0.8f, 1f);
colors.colorMultiplier = 1f;
button.colors = colors;
GameObject textGO = new GameObject("Text");
textGO.transform.SetParent(buttonGO.transform, false);
RectTransform textRect = textGO.AddComponent<RectTransform>();
textRect.anchorMin = Vector2.zero;
textRect.anchorMax = Vector2.one;
textRect.sizeDelta = Vector2.zero;
Text textComponent = textGO.AddComponent<Text>();
textComponent.text = text;
textComponent.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
textComponent.fontSize = 22;
textComponent.alignment = TextAnchor.MiddleCenter;
textComponent.color = Color.white;
textComponent.raycastTarget = false;
return button;
}
private Text CreateTextResponsive(Transform parent, string text, int fontSize, TextAnchor alignment, float height)
{
GameObject textGO = new GameObject("Text");
textGO.transform.SetParent(parent, false);
RectTransform rect = textGO.AddComponent<RectTransform>();
rect.anchorMin = new Vector2(0, 0);
rect.anchorMax = new Vector2(1, 0);
rect.pivot = new Vector2(0.5f, 0.5f);
rect.sizeDelta = new Vector2(0, height);
Text textComponent = textGO.AddComponent<Text>();
textComponent.text = text;
textComponent.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
textComponent.fontSize = fontSize;
textComponent.alignment = alignment;
textComponent.color = Color.white;
textComponent.raycastTarget = false;
return textComponent;
}
private void ShowAuthSuccessDialog(string userId, string password, string loginType)
{
// Remove existing dialog if any
if (dialogPanel != null)
{
Destroy(dialogPanel);
}
// Create dialog background (full screen overlay)
GameObject overlayGO = new GameObject("DialogOverlay");
overlayGO.transform.SetParent(canvas.transform, false);
RectTransform overlayRect = overlayGO.AddComponent<RectTransform>();
overlayRect.anchorMin = Vector2.zero;
overlayRect.anchorMax = Vector2.one;
overlayRect.sizeDelta = Vector2.zero;
Image overlayImage = overlayGO.AddComponent<Image>();
overlayImage.color = new Color(0, 0, 0, 0.7f); // Semi-transparent black
// Create dialog panel
dialogPanel = new GameObject("AuthSuccessDialog");
dialogPanel.transform.SetParent(overlayGO.transform, false);
RectTransform dialogRect = dialogPanel.AddComponent<RectTransform>();
dialogRect.anchorMin = new Vector2(0.3f, 0.4f);
dialogRect.anchorMax = new Vector2(0.7f, 0.6f);
dialogRect.offsetMin = Vector2.zero;
dialogRect.offsetMax = Vector2.zero;
Image dialogImage = dialogPanel.AddComponent<Image>();
dialogImage.color = new Color(0.15f, 0.35f, 0.15f, 1f);
// Create vertical layout group for dialog
VerticalLayoutGroup dialogLayout = dialogPanel.AddComponent<VerticalLayoutGroup>();
dialogLayout.childControlHeight = false;
dialogLayout.childControlWidth = true;
dialogLayout.childForceExpandWidth = true;
dialogLayout.childAlignment = TextAnchor.MiddleCenter;
dialogLayout.spacing = 20;
dialogLayout.padding = new RectOffset(20, 20, 20, 20);
ContentSizeFitter dialogFitter = dialogPanel.AddComponent<ContentSizeFitter>();
dialogFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// Create success message
Text successTitle = CreateText(dialogPanel.transform, "✓ LOGIN SUCCESSFUL", 32, TextAnchor.MiddleCenter, 400, 50);
successTitle.color = Color.green;
// Create user info
string userInfoText = $"User ID: {userId}\nPassword: {password}\nLogin Type: {loginType}";
Text userInfoComponent = CreateText(dialogPanel.transform, userInfoText, 20, TextAnchor.MiddleCenter, 400, 80);
userInfoComponent.color = Color.white;
// Create close button
dialogCloseButton = CreateButton(dialogPanel.transform, "OK", 200, 50);
dialogCloseButton.onClick.AddListener(() =>
{
Debug.Log("[Tech3C Demo] Dialog close button clicked");
Destroy(overlayGO);
dialogPanel = null;
});
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 00000000000000000000000000000003
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: