TapClientBridge.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Threading.Tasks;
  5. using UnityEngine;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using TapSDK.Core.Internal.Log;
  9. namespace TapSDK.Core.Standalone.Internal
  10. {
  11. internal enum TapSDKInitResult
  12. {
  13. // 初始化成功
  14. OK = 0,
  15. // 其他错误
  16. FailedGeneric = 1,
  17. // 未找到 TapTap,用户可能未安装,请引导用户下载安装 TapTap
  18. NoPlatform = 2,
  19. // 已安装 TapTap,游戏未通过 TapTap 启动
  20. NotLaunchedByPlatform = 3,
  21. // 平台版本不匹配,请引导用户升级 TapTap 与游戏至最新版本,再重新运行游戏
  22. PlatformVersionMismatch = 4,
  23. // SDK 本地执行时未知错误
  24. Unknown = -1
  25. };
  26. internal enum TapEventID
  27. {
  28. AuthorizeFinished_internal = 2001,
  29. AuthorizeFinished = 2002,
  30. // [4001, 6000), reserved for TapTap ownership events
  31. GamePlayableStatusChanged = 4001,
  32. DLCPlayableStatusChanged = 4002,
  33. };
  34. // 系统事件类型
  35. internal enum SystemState
  36. {
  37. kSystemState_Unknown = 0, // 未知
  38. kSystemState_PlatformExit = 1, // 平台退出
  39. };
  40. // 是否触发授权的返回结果
  41. internal enum AuthorizeResult
  42. {
  43. UNKNOWN = 0, // 未知
  44. OK = 1, // 成功触发授权
  45. FAILED = 2, // 授权失败
  46. };
  47. // 完成授权后的返回结果
  48. internal enum Result
  49. {
  50. kResult_OK = 0,
  51. kResult_Failed = 1,
  52. kResult_Canceled = 2,
  53. };
  54. public class TapClientBridge
  55. {
  56. #if UNITY_STANDALONE_WIN
  57. public const string DLL_NAME = "taptap_api";
  58. #endif
  59. #if UNITY_STANDALONE_WIN
  60. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  61. internal static extern bool TapSDK_RestartAppIfNecessary([MarshalAs(UnmanagedType.LPStr)] string clientId);
  62. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  63. internal static extern int TapSDK_Init(StringBuilder errMsg, [MarshalAs(UnmanagedType.LPStr)] string pubKey);
  64. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  65. internal static extern void TapSDK_Shutdown();
  66. // 定义与 C 兼容的委托
  67. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  68. internal delegate void CallbackDelegate(int id, IntPtr userData);
  69. // 系统状态返回结果结构体
  70. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  71. internal struct SystemStateResponse
  72. {
  73. public SystemState state; // 枚举直接映射
  74. }
  75. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  76. internal static extern void TapSDK_RegisterCallback(int callbackId, IntPtr callback);
  77. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  78. internal static extern void TapSDK_RunCallbacks();
  79. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  80. internal static extern void TapSDK_UnregisterCallback(int callbackId, IntPtr callback);
  81. // 登录相关接口
  82. // 授权返回结果结构体
  83. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  84. public struct AuthorizeFinishedResponse
  85. {
  86. public int is_cancel; // 是否取消
  87. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
  88. public string callback_uri; // 256 字节的 C 端字符串
  89. }
  90. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  91. internal static extern bool TapUser_GetOpenID(StringBuilder openId);
  92. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  93. internal static extern bool TapSDK_GetClientID(StringBuilder clientId);
  94. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  95. internal static extern int TapUser_AsyncAuthorize_internal([MarshalAs(UnmanagedType.LPStr)] string scopeStrings, [MarshalAs(UnmanagedType.LPStr)] string responseType,
  96. [MarshalAs(UnmanagedType.LPStr)] string redirectUri, [MarshalAs(UnmanagedType.LPStr)] string codeChallenge, [MarshalAs(UnmanagedType.LPStr)] string state,
  97. [MarshalAs(UnmanagedType.LPStr)] string codeChallengeMethod, [MarshalAs(UnmanagedType.LPStr)] string versonCode, [MarshalAs(UnmanagedType.LPStr)] string sdkUa, [MarshalAs(UnmanagedType.LPStr)] string info);
  98. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  99. internal static extern int TapUser_AsyncAuthorize([MarshalAs(UnmanagedType.LPStr)] string scopeStrings);
  100. // DLC 接口
  101. // 检查是否拥有当前游戏
  102. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  103. internal static extern bool TapApps_IsOwned();
  104. // 游戏本体可玩状态变更事件响应结构体
  105. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  106. public struct GamePlayableStatusChangedResponse
  107. {
  108. public byte is_playable; // 游戏本体是否可玩
  109. };
  110. // 显示指定 DLC 的商店页面
  111. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  112. internal static extern bool TapDLC_ShowStore([MarshalAs(UnmanagedType.LPStr)] string dlcId);
  113. // 查询用户是否拥有指定的 DLC
  114. [DllImport(DLL_NAME, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
  115. internal static extern bool TapDLC_IsOwned([MarshalAs(UnmanagedType.LPStr)] string dlcId);
  116. // DLC 授权完成响应结果
  117. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  118. public struct DLCPlayableStatusChangedResponse
  119. {
  120. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
  121. public string dlc_id; // DLC ID
  122. public byte is_playable; // 是否可玩,当用户购买 DLC (外置 DLC 为购买且下载完成后),此值返回 true。其他情况返回 false
  123. }
  124. // 初始化检查
  125. internal static int CheckInitState(out string errMessage, string key)
  126. {
  127. StringBuilder errMsgBuffer = new StringBuilder(1024); // 分配 1024 字节缓冲区
  128. int result = TapSDK_Init(errMsgBuffer, key);
  129. errMessage = errMsgBuffer.ToString();
  130. TapLog.Log("CheckInitState result = " + result);
  131. return result;
  132. }
  133. // 预防 GC 回收的静态变量
  134. private static CallbackDelegate _dlcCallbackInstance;
  135. private static CallbackDelegate _userCallbackInternalInstance;
  136. private static CallbackDelegate _userCallbackInstance;
  137. private static CallbackDelegate _licenseCallbackInstance;
  138. internal static void RegisterCallback(TapEventID eventID, CallbackDelegate callback)
  139. {
  140. IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(callback);
  141. switch (eventID)
  142. {
  143. case TapEventID.DLCPlayableStatusChanged:
  144. if (_dlcCallbackInstance != null)
  145. {
  146. UnRegisterCallback(eventID, _dlcCallbackInstance);
  147. }
  148. _dlcCallbackInstance = callback;
  149. break;
  150. case TapEventID.GamePlayableStatusChanged:
  151. if (_licenseCallbackInstance != null)
  152. {
  153. UnRegisterCallback(eventID, _licenseCallbackInstance);
  154. }
  155. _licenseCallbackInstance = callback;
  156. break;
  157. case TapEventID.AuthorizeFinished_internal:
  158. if (_userCallbackInternalInstance != null)
  159. {
  160. UnRegisterCallback(eventID, _userCallbackInternalInstance);
  161. }
  162. _userCallbackInternalInstance = callback;
  163. break;
  164. case TapEventID.AuthorizeFinished:
  165. if (_userCallbackInstance != null)
  166. {
  167. UnRegisterCallback(eventID, _userCallbackInstance);
  168. }
  169. _userCallbackInstance = callback;
  170. break;
  171. }
  172. TapSDK_RegisterCallback((int)eventID, funcPtr);
  173. }
  174. // 移除回调
  175. internal static void UnRegisterCallback(TapEventID eventID, CallbackDelegate callback)
  176. {
  177. IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(callback);
  178. switch (eventID)
  179. {
  180. case TapEventID.DLCPlayableStatusChanged:
  181. _dlcCallbackInstance = null;
  182. break;
  183. case TapEventID.GamePlayableStatusChanged:
  184. _licenseCallbackInstance = null;
  185. break;
  186. case TapEventID.AuthorizeFinished_internal:
  187. _userCallbackInternalInstance = null;
  188. break;
  189. case TapEventID.AuthorizeFinished:
  190. _userCallbackInstance = null;
  191. break;
  192. }
  193. TapSDK_UnregisterCallback((int)eventID, funcPtr);
  194. }
  195. internal static AuthorizeResult LoginWithScopesInternal(string[] scopeStrings, string responseType, string redirectUri,
  196. string codeChallenge, string state, string codeChallengeMethod, string versonCode, string sdkUa, string info)
  197. {
  198. try
  199. {
  200. TapLog.Log("login start ==== " + string.Join(",", scopeStrings));
  201. int result = TapUser_AsyncAuthorize_internal(string.Join(",", scopeStrings), responseType, redirectUri,
  202. codeChallenge, state, codeChallengeMethod, versonCode, sdkUa, info);
  203. TapLog.Log("login end === " + result);
  204. return (AuthorizeResult)result;
  205. }
  206. catch (Exception ex)
  207. {
  208. TapLog.Log("login crash = " + ex.StackTrace);
  209. return AuthorizeResult.UNKNOWN;
  210. }
  211. }
  212. internal static AuthorizeResult LoginWithScopes(string[] scopeStrings)
  213. {
  214. try
  215. {
  216. int result = TapUser_AsyncAuthorize(string.Join(",", scopeStrings));
  217. return (AuthorizeResult)result;
  218. }
  219. catch (Exception ex)
  220. {
  221. TapLog.Log("login crash = " + ex.Message);
  222. return AuthorizeResult.UNKNOWN;
  223. }
  224. }
  225. internal static bool GetTapUserOpenId(out string openId)
  226. {
  227. StringBuilder openIdBuffer = new StringBuilder(256); // 分配一个足够大的缓冲区
  228. bool success = TapUser_GetOpenID(openIdBuffer); // 调用 C 函数
  229. openId = openIdBuffer.ToString();
  230. return success;
  231. }
  232. internal static bool GetClientId(out string clientId)
  233. {
  234. StringBuilder clientIDBuffer = new StringBuilder(256); // 分配一个足够大的缓冲区
  235. bool success = TapSDK_GetClientID(clientIDBuffer); // 调用 C 函数
  236. clientId = clientIDBuffer.ToString();
  237. return success;
  238. }
  239. internal static bool QueryDLC(string skuId)
  240. {
  241. return TapDLC_IsOwned(skuId);
  242. }
  243. internal static bool ShowDLCStore(string skuId)
  244. {
  245. return TapDLC_ShowStore(skuId);
  246. }
  247. internal static bool HasLicense()
  248. {
  249. return TapApps_IsOwned();
  250. }
  251. #endif
  252. }
  253. }