com.taptap.sdk.compliance 4.5.2 → 4.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,12 +4,12 @@
4
4
  <repositories>
5
5
  <repository>https://repo.maven.apache.org/maven2</repository>
6
6
  </repositories>
7
- <androidPackage spec="com.taptap.sdk:tap-compliance:4.5.2"/>
7
+ <androidPackage spec="com.taptap.sdk:tap-compliance:4.5.3"/>
8
8
  </androidPackages>
9
9
  <iosPods>
10
10
  <sources>
11
11
  <source>https://github.com/CocoaPods/Specs.git</source>
12
12
  </sources>
13
- <iosPod name="TapTapComplianceSDK" version="~> 4.5.2" bitcodeEnabled="false" addToAllTargets="false"/>
13
+ <iosPod name="TapTapComplianceSDK" version="~> 4.5.3" bitcodeEnabled="false" addToAllTargets="false"/>
14
14
  </iosPods>
15
15
  </dependencies>
@@ -10,7 +10,7 @@ namespace TapSDK.Compliance
10
10
  public static class TapTapCompliance
11
11
  {
12
12
 
13
- public static readonly string Version = "4.5.2";
13
+ public static readonly string Version = "4.5.3";
14
14
 
15
15
  public static void RegisterComplianceCallback(Action<int, string> callback)
16
16
  {
@@ -109,6 +109,7 @@ namespace TapSDK.Compliance
109
109
  /// 设置测试环境,需要在 startup 接口调用前设置
110
110
  /// </summary>
111
111
  /// <param name="enable">测试环境是否可用</param>
112
+ [Obsolete("该方法已失效,不需要再额外调用")]
112
113
  public static void SetTestEnvironment(bool enable) {
113
114
  ComplianceJobManager.Job?.SetTestEnvironment(enable);
114
115
  }
@@ -16,6 +16,7 @@ using TapSDK.Core.Internal;
16
16
  using UnityEngine;
17
17
  using System.Linq;
18
18
  using TapSDK.Compliance.Standalone.Internal;
19
+ using TapSDK.Core.Standalone.Internal.Http;
19
20
 
20
21
 
21
22
  namespace TapSDK.Compliance
@@ -107,7 +108,8 @@ namespace TapSDK.Compliance
107
108
 
108
109
  // 计算时间
109
110
  DateTimeOffset gameEndTime = Config.StrictEndTime;
110
- TimeSpan remain = gameEndTime - DateTimeOffset.Now;
111
+ DateTimeOffset now = DateTimeOffset.FromUnixTimeSeconds(GetCurrentTime()).ToOffset(DateTimeOffset.Now.Offset);
112
+ TimeSpan remain = gameEndTime - now;
111
113
 
112
114
  return new PlayableResult
113
115
  {
@@ -221,7 +223,8 @@ namespace TapSDK.Compliance
221
223
  /// </summary>
222
224
  private bool IsGameTime()
223
225
  {
224
- string currentDate = System.DateTime.Now.ToString( "yyyy-MM-dd" );
226
+ DateTimeOffset now = DateTimeOffset.FromUnixTimeSeconds(GetCurrentTime()).ToOffset(DateTimeOffset.Now.Offset);
227
+ string currentDate = now.ToString( "yyyy-MM-dd" );
225
228
  List<string> holidays = TapTapComplianceManager.CurrentUserAntiResult.localConfig.timeRangeConfig.holidays;
226
229
  TapLogger.Debug("current date = " + currentDate + " holidays = " + holidays.ToArray());
227
230
  if(holidays.Contains(currentDate)){
@@ -229,7 +232,6 @@ namespace TapSDK.Compliance
229
232
  DateTimeOffset strictEnd = Config.StrictEndTime;
230
233
 
231
234
  bool playable;
232
- DateTimeOffset now = DateTimeOffset.Now;
233
235
  TapLogger.Debug(" now = " + now + " ,start = " + strictStart + ", end = " + strictEnd);
234
236
  playable = now >= strictStart && now < strictEnd;
235
237
  return playable;
@@ -237,6 +239,15 @@ namespace TapSDK.Compliance
237
239
  return false;
238
240
  }
239
241
 
242
+ private long GetCurrentTime(){
243
+ long serverTime = TapHttpTime.GetCurrentServerTime();
244
+ TapLogger.Debug("current serverTime = " + serverTime + " localTime = " + GetCurrentLocalTime());
245
+ if ( serverTime > 0){
246
+ return serverTime;
247
+ }
248
+ return GetCurrentLocalTime();
249
+ }
250
+
240
251
  /// <summary>
241
252
  /// 打开中国实名制窗口
242
253
  /// </summary>
@@ -1,44 +1,29 @@
1
1
  using System;
2
- using System.Text;
3
- using System.Linq;
4
2
  using System.Collections.Generic;
5
3
  using System.Net;
6
4
  using System.Net.Http;
7
- using System.Net.Http.Headers;
5
+ using System.Text;
8
6
  using System.Threading.Tasks;
9
- using Newtonsoft.Json;
10
- using TapSDK.Core;
11
- using TapSDK.Core.Internal.Json;
12
- using TapSDK.Core.Internal.Http;
13
- using TapSDK.Compliance.Model;
7
+ using TapSDK.Core.Standalone.Internal.Http;
14
8
 
15
9
  namespace TapSDK.Compliance.Internal.Http {
16
10
  public class ComplianceHttpClient {
11
+
17
12
  static readonly int INTERNAL_SERVER_ERROR_LIMIT = 3;
18
13
 
19
14
  internal readonly string serverUrl;
20
15
 
21
- private readonly HttpClient client;
16
+ private static readonly TapHttp tapHttp = TapHttp
17
+ .NewBuilder("TapCompliance", TapTapCompliance.Version)
18
+ .Build();
22
19
 
23
- private readonly Dictionary<string, Func<Task<string>>> runtimeHeaderTasks = new Dictionary<string, Func<Task<string>>>();
24
20
 
25
21
  private readonly Dictionary<string, string> additionalHeaders = new Dictionary<string, string>();
26
22
 
27
23
  public ComplianceHttpClient(string serverUrl) {
28
24
  this.serverUrl = serverUrl;
29
- client = new HttpClient();
30
- client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
31
25
  }
32
26
 
33
- public void AddRuntimeHeaderTask(string key, Func<Task<string>> task) {
34
- if (string.IsNullOrEmpty(key)) {
35
- return;
36
- }
37
- if (task == null) {
38
- return;
39
- }
40
- runtimeHeaderTasks[key] = task;
41
- }
42
27
 
43
28
  public void ChangeAddtionalHeader(string key, string value) {
44
29
  if (string.IsNullOrEmpty(key)) {
@@ -69,19 +54,6 @@ namespace TapSDK.Compliance.Internal.Http {
69
54
  return Request<T>(path, HttpMethod.Post, headers, data, queryParams);
70
55
  }
71
56
 
72
- public Task<T> Put<T>(string path,
73
- Dictionary<string, object> headers = null,
74
- object data = null,
75
- Dictionary<string, object> queryParams = null) {
76
- return Request<T>(path, HttpMethod.Put, headers, data, queryParams);
77
- }
78
-
79
- public Task Delete(string path,
80
- Dictionary<string, object> headers = null,
81
- object data = null,
82
- Dictionary<string, object> queryParams = null) {
83
- return Request<Dictionary<string, object>>(path, HttpMethod.Delete, headers, data, queryParams);
84
- }
85
57
 
86
58
  async Task<T> Request<T>(string path,
87
59
  HttpMethod method,
@@ -89,123 +61,56 @@ namespace TapSDK.Compliance.Internal.Http {
89
61
  object data = null,
90
62
  Dictionary<string, object> queryParams = null) {
91
63
 
92
- int retryTimes = INTERNAL_SERVER_ERROR_LIMIT;
93
- HttpStatusCode serverErrorStatusCode = HttpStatusCode.InternalServerError;
94
- string serverErrorString = "";
95
- while(retryTimes > 0){
96
- string url = BuildUrl(path, queryParams);
97
- HttpRequestMessage request = new HttpRequestMessage {
98
- RequestUri = new Uri(url),
99
- Method = method,
100
- };
101
- await FillHeaders(request.Headers, headers);
102
-
103
- string content = null;
104
- if (data != null) {
105
- content = JsonConvert.SerializeObject(data);
106
- StringContent requestContent = new StringContent(content);
107
- requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
108
- request.Content = requestContent;
109
- }
110
- TapHttpUtils.PrintRequest(client, request, content);
111
-
112
- HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
113
- request.Dispose();
114
-
115
- string resultString = await response.Content.ReadAsStringAsync();
116
- response.Dispose();
117
- TapHttpUtils.PrintResponse(response, resultString);
118
-
119
- if (response.IsSuccessStatusCode)
120
- {
121
- T ret = JsonConvert.DeserializeObject<T>(resultString,
122
- TapJsonConverter.Default);
123
- if (ret is BaseResponse baseResponse && !baseResponse.Success)
124
- {
125
- throw HandleErrorResponse(response.StatusCode, resultString);
126
- }
127
- return ret;
128
- }
129
- TapLogger.Debug("http log response code = " + response.StatusCode + " result = " + resultString);
130
- if(response.StatusCode >= HttpStatusCode.InternalServerError){
131
- retryTimes--;
132
- serverErrorStatusCode = response.StatusCode;
133
- serverErrorString = resultString;
134
- }else{
135
- throw HandleErrorResponse(response.StatusCode, resultString);
136
- }
137
- }
138
- throw HandleErrorResponse(serverErrorStatusCode, serverErrorString);
139
- }
140
-
141
- Exception HandleErrorResponse(HttpStatusCode statusCode, string responseContent)
142
- {
143
-
144
- if (statusCode >= HttpStatusCode.InternalServerError) {
145
- return new ComplianceException((int)statusCode, responseContent);
146
- }
147
-
148
- int code = (int)statusCode;
149
- string message = responseContent;
150
- string err = null;
151
- string desc = null;
152
- long timestamp = 0;
153
- long errorCode = -1;
154
- try {
155
- // 尝试获取 LeanCloud 返回错误信息
156
- ErrorResponse error = JsonConvert.DeserializeObject<ErrorResponse>(responseContent,
157
- TapJsonConverter.Default);
158
- message = error.Result.Message;
159
- err = error.Result.Error;
160
- desc = error.Result.Description;
161
- timestamp = error.Now;
162
- errorCode = error.Result.ErrorCode;
163
- } catch (Exception e) {
164
- TapLogger.Error(e);
165
- }
166
- return new ComplianceException(code, message) {
167
- Error = err,
168
- Description = desc,
169
- Now = timestamp,
170
- ErrorCode = errorCode
171
- };
172
- }
173
-
174
- string BuildUrl(string path, Dictionary<string, object> queryParams) {
175
64
  string apiServer = serverUrl;
176
65
  StringBuilder urlSB = new StringBuilder(apiServer.TrimEnd('/'));
177
66
  urlSB.Append($"/{path}");
178
67
  string url = urlSB.ToString();
179
- if (queryParams != null) {
180
- IEnumerable<string> queryPairs = queryParams.Select(kv => $"{kv.Key}={Uri.EscapeDataString(kv.Value.ToString())}");
181
- string queries = string.Join("&", queryPairs);
182
- url = $"{url}?{queries}";
183
- }
184
- return url;
185
- }
186
68
 
187
- async Task FillHeaders(HttpRequestHeaders headers, Dictionary<string, object> reqHeaders = null) {
188
- // 额外 headers
189
- if (reqHeaders != null) {
190
- foreach (KeyValuePair<string, object> kv in reqHeaders) {
191
- headers.Add(kv.Key, kv.Value.ToString());
69
+ Dictionary<string, string> newHeaders = null;
70
+ if(headers != null){
71
+ newHeaders = new Dictionary<string, string>();
72
+ foreach (KeyValuePair<string, object> kv in headers) {
73
+ newHeaders.Add(kv.Key, kv.Value.ToString());
192
74
  }
193
75
  }
194
- if (additionalHeaders.Count > 0) {
195
- foreach (KeyValuePair<string, string> kv in additionalHeaders) {
196
- headers.Add(kv.Key, kv.Value);
76
+
77
+ Dictionary<string, string> newQueryParams = null;
78
+ if(queryParams != null){
79
+ newQueryParams = new Dictionary<string, string>();
80
+ foreach (KeyValuePair<string, object> kv in queryParams) {
81
+ newQueryParams.Add(kv.Key, kv.Value.ToString());
197
82
  }
198
83
  }
199
- // 服务额外 headers
200
- foreach (KeyValuePair<string, Func<Task<string>>> kv in runtimeHeaderTasks) {
201
- if (headers.Contains(kv.Key)) {
202
- continue;
203
- }
204
- string value = await kv.Value.Invoke();
205
- if (string.IsNullOrEmpty(value)) {
206
- continue;
207
- }
208
- headers.Add(kv.Key, value);
84
+
85
+ TapHttpResult<T> result;
86
+ if(method == HttpMethod.Get)
87
+ {
88
+ result = await tapHttp.GetAsync<T>(url:url, headers:newHeaders, queryParams: newQueryParams);
89
+ } else {
90
+ result = await tapHttp.PostJsonAsync<T>(path:url, headers: newHeaders, queryParams:newQueryParams,
91
+ json: data, retryStrategy: TapHttpRetryStrategy.CreateDefault(TapHttpBackoffStrategy.CreateFixed(INTERNAL_SERVER_ERROR_LIMIT)));
92
+ }
93
+ if (result.IsSuccess){
94
+ return result.Data;
95
+ }else{
96
+ AbsTapHttpException exception = result.HttpException;
97
+ if(exception is TapHttpServerException serverException) {
98
+ ComplianceException complianceException;
99
+ if(serverException.StatusCode >= HttpStatusCode.InternalServerError){
100
+ complianceException = new ComplianceException((int)serverException.StatusCode, serverException.Message);
101
+ }else {
102
+ complianceException = new ComplianceException((int)serverException.StatusCode, serverException.Message) {
103
+ Error = serverException.ErrorData.Error,
104
+ Description = serverException.ErrorData.ErrorDescription,
105
+ Now = serverException.TapHttpResponse.Now,
106
+ ErrorCode = serverException.ErrorData.Code
107
+ };
108
+ }
109
+ throw complianceException;
110
+ }else {
111
+ throw exception;
112
+ }
113
+
209
114
  }
210
115
  }
211
116
 
@@ -1,22 +1,12 @@
1
1
  using System;
2
2
  using System.Collections.Generic;
3
- using System.Globalization;
4
- using System.Net.Http.Headers;
5
3
  using System.Reflection;
6
4
  using System.Threading.Tasks;
7
- using Newtonsoft.Json;
8
5
  using TapSDK.Compliance.Internal.Http;
9
6
  using TapSDK.Compliance.Model;
10
7
  using TapSDK.Core;
11
8
  using TapSDK.Login;
12
9
  using TapSDK.Login.Internal;
13
- using TapSDK.Login.Standalone;
14
- using UnityEngine;
15
- using System.Security.Cryptography;
16
- using System.Text;
17
- using System.Linq;
18
- using TapSDK.Core.Standalone.Internal;
19
- using TapSDK.Core.Standalone;
20
10
  using System.Net;
21
11
 
22
12
 
@@ -32,13 +22,10 @@ namespace TapSDK.Compliance.Internal
32
22
 
33
23
  private static string clientToken;
34
24
 
35
- private static bool enableTestMode;
36
-
37
25
  internal static void SetGameInfo(string gameId, string clientToken)
38
26
  {
39
27
  Network.gameId = gameId;
40
28
  Network.clientToken = clientToken;
41
- HttpClient.ChangeAddtionalHeader("X-LC-Id", gameId);
42
29
  }
43
30
 
44
31
  internal static void InitSetting()
@@ -59,10 +46,14 @@ namespace TapSDK.Compliance.Internal
59
46
  /// </summary>
60
47
  /// <returns></returns>
61
48
  internal static async Task<RealNameConfigResult> FetchConfig(string userId) {
62
- string path = $"real-name/v1/get-global-config?client_id={gameId}&user_identifier={WebUtility.UrlEncode(userId)}";
63
- var headers = GetAuthHeaders(path,"GET", 0, null);
64
- RealNameConfigResponse response = await HttpClient.Get<RealNameConfigResponse>(path, headers);
65
- return response.Result;
49
+ string path = $"real-name/v1/get-global-config";
50
+ var headers = GetAuthHeaders();
51
+ var queryParams = new Dictionary<string, object>{
52
+ ["client_id"] = gameId,
53
+ ["user_identifier"] = userId
54
+ };
55
+ RealNameConfigResult response = await HttpClient.Get<RealNameConfigResult>(path, headers, queryParams);
56
+ return response;
66
57
  }
67
58
 
68
59
  /// <summary>
@@ -71,30 +62,38 @@ namespace TapSDK.Compliance.Internal
71
62
  /// <returns></returns>
72
63
  internal static async Task<VerificationResult> FetchVerification(string userId)
73
64
  {
74
- string path = $"real-name/v1/anti-addiction-token?client_id={gameId}&user_identifier={WebUtility.UrlEncode(userId)}";
75
- var headers = GetAuthHeaders(path,"GET", 0, null);
76
- ServerVerificationResponse response = await HttpClient.Get<ServerVerificationResponse>(path, headers);
77
- return response.Result;
65
+ string path = $"real-name/v1/anti-addiction-token";
66
+ var headers = GetAuthHeaders();
67
+ var queryParams = new Dictionary<string, object>{
68
+ ["client_id"] = gameId,
69
+ ["user_identifier"] = userId
70
+ };
71
+ VerificationResult response = await HttpClient.Get<VerificationResult>(path, headers, queryParams);
72
+ return response;
78
73
  }
79
74
 
80
75
  /// <summary>
81
76
  /// V1 升级 v2 token
82
77
  internal static async Task<VerificationResult> UpgradeToken(string userId, string oldToken)
83
78
  {
84
- string path = $"real-name/v1/anti-addiction-token-upgrade?client_id={gameId}";
79
+ string path = $"real-name/v1/anti-addiction-token-upgrade";
85
80
  var param = new Dictionary<string, object> {
86
81
  ["anti_addiction_token_v1"] = oldToken,
87
82
  ["user_identifier"] = userId
88
83
  };
89
- var headers = GetAuthHeaders(path,"POST", 0, param);
90
- ServerVerificationResponse response = await HttpClient.Post<ServerVerificationResponse>(path, headers, data:param);
91
- return response.Result;
84
+ var queryParams = new Dictionary<string, object>{
85
+ ["client_id"] = gameId
86
+ };
87
+ var headers = GetAuthHeaders();
88
+ VerificationResult response = await HttpClient.Post<VerificationResult>(path, headers, data:param, queryParams);
89
+ return response;
92
90
  }
93
91
 
94
92
  /// </summary>
95
93
  /// 使用 TapToken 获取实名 token
96
94
  /// <returns></returns>
97
95
  public static async Task<VerificationResult> FetchVerificationByTapToken(string userId, AccessToken token, long timestamp = 0) {
96
+ // 这里手动拼 query 是为了进行 Tap 的签算
98
97
  string path = $"real-name/v1/anti-addiction-token-taptap?client_id={gameId}&user_identifier={WebUtility.UrlEncode(userId)}";
99
98
  var httpClientType = typeof(ComplianceHttpClient);
100
99
  var hostFieldInfo = httpClientType.GetField("serverUrl", BindingFlags.NonPublic | BindingFlags.Instance);
@@ -102,10 +101,15 @@ namespace TapSDK.Compliance.Internal
102
101
  var uri = new Uri(host + "/" + path);
103
102
 
104
103
  var sign = GetMacToken(token, uri, timestamp);
105
- var headers = GetAuthHeaders(path,"GET", (int)timestamp, null);
104
+ var headers = GetAuthHeaders();
106
105
  headers.Add("Authorization", sign);
107
- ServerVerificationResponse response = await HttpClient.Get<ServerVerificationResponse>(path, headers:headers);
108
- return response.Result;
106
+
107
+ var queryParams = new Dictionary<string, object>{
108
+ ["client_id"] = gameId,
109
+ ["user_identifier"] = userId
110
+ };
111
+ VerificationResult response = await HttpClient.Get<VerificationResult>(path, headers:headers, queryParams);
112
+ return response;
109
113
  }
110
114
 
111
115
  private static string GetMacToken(AccessToken token, Uri uri, long timestamp = 0) {
@@ -136,16 +140,19 @@ namespace TapSDK.Compliance.Internal
136
140
  internal static async Task<VerificationResult> FetchVerificationManual(string userName, string idCard)
137
141
  {
138
142
  var tcs = new TaskCompletionSource<VerificationResult>();
139
- string path = $"real-name/v1/anti-addiction-token-manual?client_id={gameId}";
143
+ string path = $"real-name/v1/anti-addiction-token-manual";
140
144
  Dictionary<string, object> data = new Dictionary<string, object>
141
145
  {
142
146
  ["name"] = userName,
143
147
  ["idcard"] = idCard,
144
148
  ["user_identifier"] = TapTapComplianceManager.UserId
145
149
  };
146
- var headers = GetAuthHeaders(path,"POST", 0, data);
147
- ServerVerificationResponse response = await HttpClient.Post<ServerVerificationResponse>(path, headers, data: data);
148
- tcs.TrySetResult(response.Result);
150
+ var headers = GetAuthHeaders();
151
+ var queryParams = new Dictionary<string, object>{
152
+ ["client_id"] = gameId
153
+ };
154
+ VerificationResult response = await HttpClient.Post<VerificationResult>(path, headers, data, queryParams);
155
+ tcs.TrySetResult(response);
149
156
 
150
157
  return await tcs.Task;
151
158
  }
@@ -156,18 +163,18 @@ namespace TapSDK.Compliance.Internal
156
163
  /// <returns></returns>
157
164
  internal static async Task<UserComplianceConfigResult> CheckUserConfig()
158
165
  {
159
- string path;
160
- if (!enableTestMode) {
161
- path = $"anti-addiction/v1/get-config-by-token?platform=pc&client_id={gameId}&user_identifier={WebUtility.UrlEncode(TapTapComplianceManager.UserId)}";
162
- }else{
163
- path = $"anti-addiction/v1/get-config-by-token?platform=pc&client_id={gameId}&test_mode=1&user_identifier={WebUtility.UrlEncode(TapTapComplianceManager.UserId)}";
164
- }
165
- Dictionary<string, object> headers = GetAuthHeaders(path,"GET",0,null);
166
- UserComplianceConfigResponse response = await HttpClient.Get<UserComplianceConfigResponse>(path, headers: headers);
166
+ string path = $"anti-addiction/v1/get-config-by-token";
167
+ Dictionary<string, object> headers = GetAuthHeaders();
168
+ var queryParams = new Dictionary<string, object>{
169
+ ["client_id"] = gameId,
170
+ ["user_identifier"] = TapTapComplianceManager.UserId,
171
+ ["platform"] = "pc"
172
+ };
173
+ UserComplianceConfigResult response = await HttpClient.Get<UserComplianceConfigResult>(path, headers, queryParams);
167
174
  #if UNITY_EDITOR
168
- TapLogger.Debug($"检查用户状态: ageLimit: {response.Result.userState.ageLimit} ageCheck: {response.Result.ageCheckResult.allow} IsAdult: {response.Result.userState.isAdult} ");
175
+ TapLogger.Debug($"检查用户状态: ageLimit: {response.userState.ageLimit} ageCheck: {response.ageCheckResult.allow} IsAdult: {response.userState.isAdult} ");
169
176
  #endif
170
- return response.Result;
177
+ return response;
171
178
  }
172
179
  /// <summary>
173
180
  /// 检测是否可玩
@@ -175,23 +182,21 @@ namespace TapSDK.Compliance.Internal
175
182
  /// <returns></returns>
176
183
  internal static async Task<PlayableResult> CheckPlayable()
177
184
  {
178
- string path = "";
179
- if (!enableTestMode) {
180
- path = $"anti-addiction/v1/heartbeat?client_id={gameId}";
181
- }
182
- else {
183
- path = $"anti-addiction/v1/heartbeat?client_id={gameId}&test_mode=1";
184
- }
185
+ string path = $"anti-addiction/v1/heartbeat";
186
+
185
187
  Dictionary<string,object> data = new Dictionary<string,object>{
186
188
  ["session_id"] = TapTapComplianceManager.CurrentSession,
187
189
  ["user_identifier"] = TapTapComplianceManager.UserId
188
190
  };
189
- Dictionary<string, object> headers = GetAuthHeaders(path,"POST",0, data);
190
- PlayableResponse response = await HttpClient.Post<PlayableResponse>(path, headers: headers, data:data);
191
+ Dictionary<string, object> headers = GetAuthHeaders();
192
+ var queryParams = new Dictionary<string, object>{
193
+ ["client_id"] = gameId
194
+ };
195
+ PlayableResult response = await HttpClient.Post<PlayableResult>(path, headers, data, queryParams);
191
196
  #if UNITY_EDITOR
192
- TapLogger.Debug($"检查是否可玩结果: remainTime: {response.Result.RemainTime} Content: {response.Result.Content}");
197
+ TapLogger.Debug($"检查是否可玩结果: remainTime: {response.RemainTime} Content: {response.Content}");
193
198
  #endif
194
- return response.Result;
199
+ return response;
195
200
  }
196
201
 
197
202
  /// <summary>
@@ -201,16 +206,15 @@ namespace TapSDK.Compliance.Internal
201
206
  /// <returns></returns>
202
207
  internal static async Task<PayableResult> CheckPayable(long amount)
203
208
  {
204
- string path = "";
205
- if (!enableTestMode) {
206
- path = $"anti-addiction/v1/payable?client_id={gameId}&amount={amount}&user_identifier={WebUtility.UrlEncode(TapTapComplianceManager.UserId)}";
207
- }
208
- else {
209
- path = $"anti-addiction/v1/payable?client_id={gameId}&amount={amount}&test_mode=1&user_identifier={WebUtility.UrlEncode(TapTapComplianceManager.UserId)}";
210
- }
211
- Dictionary<string, object> headers = GetAuthHeaders(path, "GET", 0, null);
212
- PayableResponse response = await HttpClient.Get<PayableResponse>(path, headers: headers);
213
- return response.Result;
209
+ string path = $"anti-addiction/v1/payable";
210
+ Dictionary<string, object> headers = GetAuthHeaders();
211
+ var queryParams = new Dictionary<string, object>{
212
+ ["client_id"] = gameId,
213
+ ["user_identifier"] = TapTapComplianceManager.UserId,
214
+ ["amount"] = amount
215
+ };
216
+ PayableResult response = await HttpClient.Get<PayableResult>(path, headers, queryParams);
217
+ return response;
214
218
  }
215
219
 
216
220
  /// <summary>
@@ -220,86 +224,37 @@ namespace TapSDK.Compliance.Internal
220
224
  /// <returns></returns>
221
225
  internal static async Task SubmitPayment(long amount)
222
226
  {
223
- string path = "";
224
- if (!enableTestMode) {
225
- path = $"anti-addiction/v1/payment-submit?client_id={gameId}";
226
- }
227
- else {
228
- path = $"anti-addiction/v1/payment-submit?client_id={gameId}&test_mode=1";
229
- }
230
- Dictionary<string, object> data = new Dictionary<string, object>
227
+ string path = $"anti-addiction/v1/payment-submit";
228
+
229
+ Dictionary<string, object> data = new Dictionary<string, object>
231
230
  {
232
231
  { "amount", amount },
233
232
  {"user_identifier", TapTapComplianceManager.UserId}
234
233
  };
235
- Dictionary<string, object> headers = GetAuthHeaders(path, "POST", 0, data);
234
+ Dictionary<string, object> headers = GetAuthHeaders();
235
+ var queryParams = new Dictionary<string, object>{
236
+ ["client_id"] = gameId
237
+ };
236
238
 
237
- await HttpClient.Post<SubmitPaymentResponse>(path, headers:headers, data: data);
239
+ await HttpClient.Post<SubmitPaymentResponse>(path, headers, data, queryParams);
238
240
  }
239
241
  // internal static Dictionary<string, object> GetAuthHeaders(){
240
242
  // return new Dictionary<string,object>{};
241
243
  // }
242
244
 
243
- internal static Dictionary<string, object> GetAuthHeaders(string path, string httpMethod,int timestamp, Dictionary<string,object> body)
245
+ internal static Dictionary<string, object> GetAuthHeaders()
244
246
  {
245
- var httpClientType = typeof(ComplianceHttpClient);
246
- var hostFieldInfo = httpClientType.GetField("serverUrl", BindingFlags.NonPublic | BindingFlags.Instance);
247
- string host = hostFieldInfo?.GetValue(HttpClient) as string;
248
- var uri = "/" + path;
249
- int ts = timestamp;
250
- if (ts == 0) {
251
- var dt = DateTime.UtcNow - new DateTime(1970, 1, 1);
252
- ts = (int)dt.TotalSeconds;
253
- }
254
- var nonce = new System.Random().Next().ToString();
255
- var headers = new Dictionary<string, object>
256
- {
257
- { "X-Tap-PN", "TapSDK" },
258
- { "X-Tap-Lang", Tracker.getServerLanguage() },
259
- { "X-Tap-Device-Id", SystemInfo.deviceUniqueIdentifier},
260
- { "X-Tap-Platform", "PC"},
261
- { "X-Tap-SDK-Module","TapCompliance"},
262
- { "X-Tap-SDK-Module-Version", TapTapSDK.Version},
263
- { "X-Tap-SDK-Artifact", "Unity"},
264
- { "User-Agent","TapSDK-Unity/" + TapTapSDK.Version},
265
- { "X-Tap-Nonce", nonce},
266
- { "X-Tap-Ts",ts}
267
- };
247
+ var headers = new Dictionary<string, object>();
268
248
  string token = Verification.GetCurrentToken();
269
249
  if (!string.IsNullOrEmpty(token))
270
250
  {
271
251
  headers.Add("X-Tap-Anti-Addiction-Token", token);
272
252
  }
273
-
274
- string currentDBUserId = TapCoreStandalone.GetCurrentUserId();
275
- if(currentDBUserId != null && currentDBUserId.Length > 0) {
276
- headers.Add("X-Tap-SDK-Game-User-Id", currentDBUserId);
277
- }
278
-
279
- headers = headers.OrderBy(x => x.Key).ToDictionary(x => x.Key, y=>y.Value);
280
- List<string> headerList = new List<string>();
281
- foreach(KeyValuePair<string,object> kv in headers){
282
- if(kv.Key.ToLower().StartsWith("x-tap-")){
283
- headerList.Add(kv.Key.ToLower()+":"+kv.Value);
284
- }
285
- }
286
- string headerString = string.Join("\n",headerList);
287
- var normalizedString = $"{httpMethod}\n{uri}\n{headerString}\n";
288
- if(body != null){
289
- normalizedString += $"{JsonConvert.SerializeObject(body)}\n";
290
- }else{
291
- normalizedString += "\n";
292
- }
293
-
294
- HashAlgorithm hashGenerator= new HMACSHA256(Encoding.UTF8.GetBytes(clientToken));
295
-
296
- var hash = Convert.ToBase64String(hashGenerator.ComputeHash(Encoding.UTF8.GetBytes(normalizedString)));
297
- headers.Add("X-Tap-Sign",hash);
298
253
  return headers;
299
254
  }
300
255
 
301
256
  internal static void SetTestEnvironment(bool enable) {
302
- enableTestMode = enable;
257
+
303
258
  }
304
259
  }
305
260
  }
@@ -22,6 +22,11 @@ namespace TapSDK.Compliance
22
22
  #region Abstract
23
23
 
24
24
  static readonly string USER_ANTI_FILENAME = "user_anti_config";
25
+
26
+ // 本地基准时间戳
27
+ private long BaseLocalTime = 0;
28
+ //获取本地时间戳时,应用运行的时间
29
+ private long BaseLocalStartUpTime = 0;
25
30
 
26
31
 
27
32
  /// <summary>
@@ -145,6 +150,7 @@ namespace TapSDK.Compliance
145
150
  throw;
146
151
  }else{
147
152
  if(result != null){
153
+ ResetBaseLocalTime();
148
154
  TapTapComplianceManager.CurrentSession = GenerateSession();
149
155
  return result;
150
156
  }else{
@@ -158,6 +164,7 @@ namespace TapSDK.Compliance
158
164
  if(result == null){
159
165
  throw;
160
166
  }else{
167
+ ResetBaseLocalTime();
161
168
  TapTapComplianceManager.CurrentSession = GenerateSession();
162
169
  return result;
163
170
  }
@@ -165,6 +172,24 @@ namespace TapSDK.Compliance
165
172
 
166
173
  }
167
174
 
175
+ private void ResetBaseLocalTime(){
176
+ if(BaseLocalTime > 0){
177
+ return;
178
+ }
179
+ BaseLocalTime = DateTimeOffset.Now.ToUnixTimeSeconds();
180
+ BaseLocalStartUpTime = (long)Time.realtimeSinceStartup;
181
+ TapLogger.Debug(" current local time " + DateTimeOffset.Now);
182
+ }
183
+
184
+ /// <summary>
185
+ /// 获取基于本地时间的当前时间戳,用于离线心跳计算
186
+ /// </summary>
187
+ /// <returns></returns>
188
+ protected long GetCurrentLocalTime(){
189
+ long currentStartUpTime = (long) Time.realtimeSinceStartup;
190
+ return BaseLocalTime + currentStartUpTime - BaseLocalStartUpTime;
191
+ }
192
+
168
193
  private string GenerateSession()
169
194
  {
170
195
  const string baseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
package/link.xml ADDED
@@ -0,0 +1,5 @@
1
+ <linker>
2
+ <assembly fullname="TapSDK.Compliance" preserve="all" />
3
+ <assembly fullname="TapSDK.Compliance.Runtime" preserve="all" />
4
+ <assembly fullname="TapSDK.Compliance.Mobile.Runtime" preserve="all" />
5
+ </linker>
package/link.xml.meta ADDED
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: 366bb74499caa4189bcb11c3aa8608f7
3
+ TextScriptImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
package/package.json CHANGED
@@ -2,11 +2,11 @@
2
2
  "name": "com.taptap.sdk.compliance",
3
3
  "displayName": "TapTapSDK Compliance",
4
4
  "description": "TapTapSDK Compliance",
5
- "version": "4.5.2",
5
+ "version": "4.5.3",
6
6
  "unity": "2019.4",
7
7
  "license": "MIT",
8
8
  "dependencies": {
9
- "com.taptap.sdk.core": "4.5.2",
10
- "com.taptap.sdk.login": "4.5.2"
9
+ "com.taptap.sdk.core": "4.5.3",
10
+ "com.taptap.sdk.login": "4.5.3"
11
11
  }
12
12
  }