com.taptap.sdk.compliance 4.5.2 → 4.5.4

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.4"/>
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.4" 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.4";
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>
@@ -115,6 +115,11 @@ namespace TapSDK.Compliance
115
115
  if(!CheckInitState()){
116
116
  return;
117
117
  }
118
+ if (string.IsNullOrEmpty(userId))
119
+ {
120
+ TapLogger.Error(" current user is invalid:" + userId);
121
+ return;
122
+ }
118
123
  // 如果正在处理中,直接返回
119
124
  if (isCheckingUser) {
120
125
  TapLogger.Debug(" current user is checking so return");
@@ -18,10 +18,8 @@ namespace TapSDK.Compliance.Internal
18
18
 
19
19
  private const string TIME_FROMAT = "HH:mm";
20
20
 
21
- internal static readonly Persistence persistence = new Persistence(Path.Combine(Application.persistentDataPath,
22
- ANTI_ADDICTION_DIR, CONFIG_FILENAME));
23
- internal static readonly Persistence userPersistence = new Persistence(Path.Combine(Application.persistentDataPath,
24
- ANTI_ADDICTION_DIR, USER_CONFIG_FILENAME));
21
+ internal static readonly Lazy<Persistence> persistence = new Lazy<Persistence>(() => new Persistence(CONFIG_FILENAME));
22
+ internal static readonly Lazy<Persistence> userPersistence = new Lazy<Persistence>(() =>new Persistence(USER_CONFIG_FILENAME));
25
23
 
26
24
 
27
25
  static RealNameConfigResult current;
@@ -46,7 +44,7 @@ namespace TapSDK.Compliance.Internal
46
44
  Current = await Network.FetchConfig(userId);
47
45
  if (IsValid())
48
46
  {
49
- await persistence.Save(Current);
47
+ await persistence.Value.Save(Current);
50
48
  return true;
51
49
  }
52
50
  }
@@ -64,7 +62,7 @@ namespace TapSDK.Compliance.Internal
64
62
  // 从设备缓存加载
65
63
  try
66
64
  {
67
- Current = await persistence.Load<RealNameConfigResult>();
65
+ Current = await persistence.Value.Load<RealNameConfigResult>();
68
66
  if (Current != null)
69
67
  return true;
70
68
  }
@@ -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
  }
@@ -4,6 +4,7 @@ using System.IO;
4
4
  using System.Threading.Tasks;
5
5
  using Newtonsoft.Json;
6
6
  using TapSDK.Core;
7
+ using UnityEngine;
7
8
 
8
9
  namespace TapSDK.Compliance.Internal
9
10
  {
@@ -13,10 +14,20 @@ namespace TapSDK.Compliance.Internal
13
14
  internal class Persistence
14
15
  {
15
16
  private readonly string _filePath;
16
-
17
17
  internal Persistence(string path)
18
18
  {
19
- _filePath = path;
19
+ string new_cacheDir = Path.Combine(Application.persistentDataPath, Config.ANTI_ADDICTION_DIR);
20
+ if (!string.IsNullOrEmpty(TapTapComplianceManager.ClientId)){
21
+ new_cacheDir = Path.Combine(Application.persistentDataPath, Config.ANTI_ADDICTION_DIR + "_" + TapTapComplianceManager.ClientId);
22
+ }
23
+ // 文件夹不存在时,尝试兼容旧版本数据
24
+ if(!Directory.Exists(new_cacheDir)) {
25
+ string old_cacheDir = Path.Combine(Application.persistentDataPath, Config.ANTI_ADDICTION_DIR);
26
+ if(Directory.Exists(old_cacheDir)) {
27
+ Directory.Move(old_cacheDir, new_cacheDir);
28
+ }
29
+ }
30
+ _filePath = Path.Combine(new_cacheDir, path);
20
31
  }
21
32
 
22
33
  internal async Task<T> Load<T>() where T : class
@@ -24,7 +35,7 @@ namespace TapSDK.Compliance.Internal
24
35
  TapLogger.Debug(_filePath);
25
36
  if (!File.Exists(_filePath))
26
37
  {
27
- return null;
38
+ return null;
28
39
  }
29
40
 
30
41
  string text;
@@ -48,8 +48,7 @@ namespace TapSDK.Compliance.Internal
48
48
  string filename = Tool.EncryptString(userId);
49
49
  // 存储 v2 token 数据
50
50
  if(persistenceV2 == null){
51
- persistenceV2 = new Persistence(Path.Combine(Application.persistentDataPath,
52
- Config.ANTI_ADDICTION_DIR,
51
+ persistenceV2 = new Persistence(Path.Combine(
53
52
  VERIFICATION_V2_FILENAME,
54
53
  filename));
55
54
  }
@@ -94,8 +93,7 @@ namespace TapSDK.Compliance.Internal
94
93
  string filename = Tool.EncryptString(userId);
95
94
  //存储 v1 token数据
96
95
  if(persistence == null){
97
- persistence = new Persistence(Path.Combine(Application.persistentDataPath,
98
- Config.ANTI_ADDICTION_DIR,
96
+ persistence = new Persistence(Path.Combine(
99
97
  VERIFICATION_FILENAME,
100
98
  filename));
101
99
  }
@@ -210,8 +208,7 @@ namespace TapSDK.Compliance.Internal
210
208
  await FetchByTapToken(userId, token);
211
209
  if(persistenceV2 == null){
212
210
  var filename = Tool.EncryptString(userId);
213
- persistenceV2 = new Persistence(Path.Combine(Application.persistentDataPath,
214
- Config.ANTI_ADDICTION_DIR,
211
+ persistenceV2 = new Persistence(Path.Combine(
215
212
  VERIFICATION_V2_FILENAME,
216
213
  filename));
217
214
  }
@@ -237,8 +234,7 @@ namespace TapSDK.Compliance.Internal
237
234
  TapLogger.Debug("try save v2 token to local");
238
235
  if(persistenceV2 == null){
239
236
  var filename = Tool.EncryptString(userId);
240
- persistenceV2 = new Persistence(Path.Combine(Application.persistentDataPath,
241
- Config.ANTI_ADDICTION_DIR,
237
+ persistenceV2 = new Persistence(Path.Combine(
242
238
  VERIFICATION_V2_FILENAME,
243
239
  filename));
244
240
  }
@@ -252,8 +248,7 @@ namespace TapSDK.Compliance.Internal
252
248
  current.IsAdult = isAdult;
253
249
  if(persistenceV2 == null){
254
250
  var filename = Tool.EncryptString(current.UserId);
255
- persistenceV2 = new Persistence(Path.Combine(Application.persistentDataPath,
256
- Config.ANTI_ADDICTION_DIR,
251
+ persistenceV2 = new Persistence(Path.Combine(
257
252
  VERIFICATION_V2_FILENAME,
258
253
  filename));
259
254
  }
@@ -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>
@@ -124,8 +129,7 @@ namespace TapSDK.Compliance
124
129
  protected virtual async Task<UserComplianceConfigResult> CheckUserConfigAsyncWithFallback()
125
130
  {
126
131
  string filename = Tool.EncryptString(Verification.Current.UserId);
127
- Persistence persistence = new Persistence(Path.Combine(Application.persistentDataPath,
128
- Config.ANTI_ADDICTION_DIR,
132
+ Persistence persistence = new Persistence(Path.Combine(
129
133
  USER_ANTI_FILENAME,
130
134
  filename));
131
135
  UserComplianceConfigResult result = await persistence.Load<UserComplianceConfigResult>();
@@ -145,6 +149,7 @@ namespace TapSDK.Compliance
145
149
  throw;
146
150
  }else{
147
151
  if(result != null){
152
+ ResetBaseLocalTime();
148
153
  TapTapComplianceManager.CurrentSession = GenerateSession();
149
154
  return result;
150
155
  }else{
@@ -158,6 +163,7 @@ namespace TapSDK.Compliance
158
163
  if(result == null){
159
164
  throw;
160
165
  }else{
166
+ ResetBaseLocalTime();
161
167
  TapTapComplianceManager.CurrentSession = GenerateSession();
162
168
  return result;
163
169
  }
@@ -165,6 +171,24 @@ namespace TapSDK.Compliance
165
171
 
166
172
  }
167
173
 
174
+ private void ResetBaseLocalTime(){
175
+ if(BaseLocalTime > 0){
176
+ return;
177
+ }
178
+ BaseLocalTime = DateTimeOffset.Now.ToUnixTimeSeconds();
179
+ BaseLocalStartUpTime = (long)Time.realtimeSinceStartup;
180
+ TapLogger.Debug(" current local time " + DateTimeOffset.Now);
181
+ }
182
+
183
+ /// <summary>
184
+ /// 获取基于本地时间的当前时间戳,用于离线心跳计算
185
+ /// </summary>
186
+ /// <returns></returns>
187
+ protected long GetCurrentLocalTime(){
188
+ long currentStartUpTime = (long) Time.realtimeSinceStartup;
189
+ return BaseLocalTime + currentStartUpTime - BaseLocalStartUpTime;
190
+ }
191
+
168
192
  private string GenerateSession()
169
193
  {
170
194
  const string baseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
@@ -304,8 +328,7 @@ namespace TapSDK.Compliance
304
328
  {
305
329
  if(needClearCache){
306
330
  string filename = Tool.EncryptString(Verification.Current.UserId);
307
- Persistence persistence = new Persistence(Path.Combine(Application.persistentDataPath,
308
- Config.ANTI_ADDICTION_DIR,
331
+ Persistence persistence = new Persistence(Path.Combine(
309
332
  USER_ANTI_FILENAME,
310
333
  filename));
311
334
  persistence.Delete();
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.4",
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.4",
10
+ "com.taptap.sdk.login": "4.5.4"
11
11
  }
12
12
  }