@truewatchtech/cocos-sdk 0.1.0-alpha.4 → 0.1.0-alpha.6

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.
Files changed (175) hide show
  1. package/README.md +49 -1
  2. package/bin/cli.cjs +48 -18
  3. package/bin/legacy-asset-hashes.json +32 -0
  4. package/bin/managed-assets.cjs +67 -0
  5. package/dist/creator2/core/client.d.ts +23 -7
  6. package/dist/creator2/core/client.d.ts.map +1 -1
  7. package/dist/creator2/core/client.js +74 -28
  8. package/dist/creator2/core/client.js.map +1 -1
  9. package/dist/creator2/core/index.d.ts +1 -1
  10. package/dist/creator2/core/index.d.ts.map +1 -1
  11. package/dist/creator2/core/index.js.map +1 -1
  12. package/dist/creator2/core/plugin-api.d.ts +15 -0
  13. package/dist/creator2/core/plugin-api.d.ts.map +1 -0
  14. package/dist/creator2/core/plugin-api.js +3 -0
  15. package/dist/creator2/core/plugin-api.js.map +1 -0
  16. package/dist/creator2/core/types.d.ts +0 -78
  17. package/dist/creator2/core/types.d.ts.map +1 -1
  18. package/dist/creator2/core/validation.d.ts +0 -11
  19. package/dist/creator2/core/validation.d.ts.map +1 -1
  20. package/dist/creator2/core/validation.js +0 -63
  21. package/dist/creator2/core/validation.js.map +1 -1
  22. package/dist/creator2/core/version.d.ts +1 -1
  23. package/dist/creator2/core/version.js +1 -1
  24. package/dist/creator2/creator2/auto.d.ts +1 -3
  25. package/dist/creator2/creator2/auto.d.ts.map +1 -1
  26. package/dist/creator2/creator2/auto.js +0 -25
  27. package/dist/creator2/creator2/auto.js.map +1 -1
  28. package/dist/creator2/creator2/index.d.ts +0 -7
  29. package/dist/creator2/creator2/index.d.ts.map +1 -1
  30. package/dist/creator2/creator2/index.js +1 -13
  31. package/dist/creator2/creator2/index.js.map +1 -1
  32. package/dist/creator2/creator2/transport.d.ts +0 -1
  33. package/dist/creator2/creator2/transport.d.ts.map +1 -1
  34. package/dist/creator2/creator2/transport.js +0 -4
  35. package/dist/creator2/creator2/transport.js.map +1 -1
  36. package/dist/creator3/core/client.d.ts +23 -7
  37. package/dist/creator3/core/client.d.ts.map +1 -1
  38. package/dist/creator3/core/client.js +72 -28
  39. package/dist/creator3/core/client.js.map +1 -1
  40. package/dist/creator3/core/index.d.ts +1 -1
  41. package/dist/creator3/core/index.d.ts.map +1 -1
  42. package/dist/creator3/core/index.js.map +1 -1
  43. package/dist/creator3/core/plugin-api.d.ts +15 -0
  44. package/dist/creator3/core/plugin-api.d.ts.map +1 -0
  45. package/dist/creator3/core/plugin-api.js +2 -0
  46. package/dist/creator3/core/plugin-api.js.map +1 -0
  47. package/dist/creator3/core/types.d.ts +0 -78
  48. package/dist/creator3/core/types.d.ts.map +1 -1
  49. package/dist/creator3/core/validation.d.ts +0 -11
  50. package/dist/creator3/core/validation.d.ts.map +1 -1
  51. package/dist/creator3/core/validation.js +0 -61
  52. package/dist/creator3/core/validation.js.map +1 -1
  53. package/dist/creator3/core/version.d.ts +1 -1
  54. package/dist/creator3/core/version.js +1 -1
  55. package/dist/creator3/creator3/auto.d.ts +1 -3
  56. package/dist/creator3/creator3/auto.d.ts.map +1 -1
  57. package/dist/creator3/creator3/auto.js +1 -24
  58. package/dist/creator3/creator3/auto.js.map +1 -1
  59. package/dist/creator3/creator3/index.d.ts +0 -7
  60. package/dist/creator3/creator3/index.d.ts.map +1 -1
  61. package/dist/creator3/creator3/index.js +1 -12
  62. package/dist/creator3/creator3/index.js.map +1 -1
  63. package/dist/creator3/creator3/transport.d.ts +0 -1
  64. package/dist/creator3/creator3/transport.d.ts.map +1 -1
  65. package/dist/creator3/creator3/transport.js +0 -4
  66. package/dist/creator3/creator3/transport.js.map +1 -1
  67. package/extensions/creator2/install-native.cjs +118 -28
  68. package/extensions/creator2/install-spm.cjs +198 -0
  69. package/extensions/creator2/legacy-asset-hashes.json +32 -0
  70. package/extensions/creator2/managed-assets.cjs +67 -0
  71. package/extensions/creator3/install-native.cjs +118 -28
  72. package/extensions/creator3/install-spm.cjs +198 -0
  73. package/extensions/creator3/legacy-asset-hashes.json +32 -0
  74. package/extensions/creator3/managed-assets.cjs +67 -0
  75. package/native/android/src/main/java/com/ft/sdk/cocos/FTBridgeTransport.java +85 -0
  76. package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridge.java +2 -192
  77. package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridgeModules.java +9 -0
  78. package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridgeProvider.java +1 -1
  79. package/native/ios/FTCocosBridge.m +8 -203
  80. package/native/ios/FTCocosBridge.podspec +3 -4
  81. package/native/ios/Package.swift +25 -0
  82. package/native/ios/include/FTCocosBridge.h +2 -0
  83. package/package.json +10 -5
  84. package/plugin-api/package.json +4 -0
  85. package/components/creator2/ReplayPrivacy.ts +0 -23
  86. package/components/creator3/ReplayPrivacy.ts +0 -25
  87. package/dist/creator2/core/replay-async-transport.d.ts +0 -4
  88. package/dist/creator2/core/replay-async-transport.d.ts.map +0 -1
  89. package/dist/creator2/core/replay-async-transport.js +0 -67
  90. package/dist/creator2/core/replay-async-transport.js.map +0 -1
  91. package/dist/creator2/core/replay-budget.d.ts +0 -28
  92. package/dist/creator2/core/replay-budget.d.ts.map +0 -1
  93. package/dist/creator2/core/replay-budget.js +0 -113
  94. package/dist/creator2/core/replay-budget.js.map +0 -1
  95. package/dist/creator2/core/replay-diagnostics.d.ts +0 -36
  96. package/dist/creator2/core/replay-diagnostics.d.ts.map +0 -1
  97. package/dist/creator2/core/replay-diagnostics.js +0 -40
  98. package/dist/creator2/core/replay-diagnostics.js.map +0 -1
  99. package/dist/creator2/core/replay-encoding.d.ts +0 -31
  100. package/dist/creator2/core/replay-encoding.d.ts.map +0 -1
  101. package/dist/creator2/core/replay-encoding.js +0 -63
  102. package/dist/creator2/core/replay-encoding.js.map +0 -1
  103. package/dist/creator2/core/replay-file.d.ts +0 -5
  104. package/dist/creator2/core/replay-file.d.ts.map +0 -1
  105. package/dist/creator2/core/replay-file.js +0 -101
  106. package/dist/creator2/core/replay-file.js.map +0 -1
  107. package/dist/creator2/core/replay-pixels.d.ts +0 -3
  108. package/dist/creator2/core/replay-pixels.d.ts.map +0 -1
  109. package/dist/creator2/core/replay-pixels.js +0 -16
  110. package/dist/creator2/core/replay-pixels.js.map +0 -1
  111. package/dist/creator2/core/replay-privacy-nodes.d.ts +0 -14
  112. package/dist/creator2/core/replay-privacy-nodes.d.ts.map +0 -1
  113. package/dist/creator2/core/replay-privacy-nodes.js +0 -18
  114. package/dist/creator2/core/replay-privacy-nodes.js.map +0 -1
  115. package/dist/creator2/core/replay-privacy.d.ts +0 -15
  116. package/dist/creator2/core/replay-privacy.d.ts.map +0 -1
  117. package/dist/creator2/core/replay-privacy.js +0 -36
  118. package/dist/creator2/core/replay-privacy.js.map +0 -1
  119. package/dist/creator2/core/replay.d.ts +0 -99
  120. package/dist/creator2/core/replay.d.ts.map +0 -1
  121. package/dist/creator2/core/replay.js +0 -611
  122. package/dist/creator2/core/replay.js.map +0 -1
  123. package/dist/creator2/creator2/capture.d.ts +0 -17
  124. package/dist/creator2/creator2/capture.d.ts.map +0 -1
  125. package/dist/creator2/creator2/capture.js +0 -168
  126. package/dist/creator2/creator2/capture.js.map +0 -1
  127. package/dist/creator3/core/replay-async-transport.d.ts +0 -4
  128. package/dist/creator3/core/replay-async-transport.d.ts.map +0 -1
  129. package/dist/creator3/core/replay-async-transport.js +0 -16
  130. package/dist/creator3/core/replay-async-transport.js.map +0 -1
  131. package/dist/creator3/core/replay-budget.d.ts +0 -28
  132. package/dist/creator3/core/replay-budget.d.ts.map +0 -1
  133. package/dist/creator3/core/replay-budget.js +0 -105
  134. package/dist/creator3/core/replay-budget.js.map +0 -1
  135. package/dist/creator3/core/replay-diagnostics.d.ts +0 -36
  136. package/dist/creator3/core/replay-diagnostics.d.ts.map +0 -1
  137. package/dist/creator3/core/replay-diagnostics.js +0 -36
  138. package/dist/creator3/core/replay-diagnostics.js.map +0 -1
  139. package/dist/creator3/core/replay-encoding.d.ts +0 -31
  140. package/dist/creator3/core/replay-encoding.d.ts.map +0 -1
  141. package/dist/creator3/core/replay-encoding.js +0 -62
  142. package/dist/creator3/core/replay-encoding.js.map +0 -1
  143. package/dist/creator3/core/replay-file.d.ts +0 -5
  144. package/dist/creator3/core/replay-file.d.ts.map +0 -1
  145. package/dist/creator3/core/replay-file.js +0 -31
  146. package/dist/creator3/core/replay-file.js.map +0 -1
  147. package/dist/creator3/core/replay-pixels.d.ts +0 -3
  148. package/dist/creator3/core/replay-pixels.d.ts.map +0 -1
  149. package/dist/creator3/core/replay-pixels.js +0 -13
  150. package/dist/creator3/core/replay-pixels.js.map +0 -1
  151. package/dist/creator3/core/replay-privacy-nodes.d.ts +0 -14
  152. package/dist/creator3/core/replay-privacy-nodes.d.ts.map +0 -1
  153. package/dist/creator3/core/replay-privacy-nodes.js +0 -15
  154. package/dist/creator3/core/replay-privacy-nodes.js.map +0 -1
  155. package/dist/creator3/core/replay-privacy.d.ts +0 -15
  156. package/dist/creator3/core/replay-privacy.d.ts.map +0 -1
  157. package/dist/creator3/core/replay-privacy.js +0 -33
  158. package/dist/creator3/core/replay-privacy.js.map +0 -1
  159. package/dist/creator3/core/replay.d.ts +0 -99
  160. package/dist/creator3/core/replay.d.ts.map +0 -1
  161. package/dist/creator3/core/replay.js +0 -534
  162. package/dist/creator3/core/replay.js.map +0 -1
  163. package/dist/creator3/creator3/capture.d.ts +0 -17
  164. package/dist/creator3/creator3/capture.d.ts.map +0 -1
  165. package/dist/creator3/creator3/capture.js +0 -112
  166. package/dist/creator3/creator3/capture.js.map +0 -1
  167. package/dist/creator3/creator3/replay-render-cycle.d.ts +0 -9
  168. package/dist/creator3/creator3/replay-render-cycle.d.ts.map +0 -1
  169. package/dist/creator3/creator3/replay-render-cycle.js +0 -12
  170. package/dist/creator3/creator3/replay-render-cycle.js.map +0 -1
  171. package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosReplayImageJobs.java +0 -55
  172. package/native/ios/FTCocosReplayImageJobs.h +0 -11
  173. package/native/ios/FTCocosReplayImageJobs.m +0 -54
  174. package/native/shared/FTReplayFileBridge.h +0 -62
  175. package/native/shared/FTReplayFileWorker.h +0 -88
@@ -1,13 +1,5 @@
1
1
  package com.ft.sdk.cocos;
2
2
 
3
- import android.app.Activity;
4
- import android.app.ActivityManager;
5
- import android.app.Application;
6
- import android.content.Context;
7
- import android.net.Uri;
8
- import android.os.Build;
9
- import android.os.Bundle;
10
- import android.os.Process;
11
3
 
12
4
  import com.ft.sdk.DetectFrequency;
13
5
  import com.ft.sdk.FTLogger;
@@ -19,24 +11,15 @@ import com.ft.sdk.FTSdk;
19
11
  import com.ft.sdk.FTTraceConfig;
20
12
  import com.ft.sdk.FTTraceManager;
21
13
  import com.ft.sdk.LogCacheDiscard;
22
- import com.ft.sdk.SessionReplayManager;
23
14
  import com.ft.sdk.TraceType;
24
15
  import com.ft.sdk.garble.bean.AppState;
25
16
  import com.ft.sdk.garble.bean.NetStatusBean;
26
17
  import com.ft.sdk.garble.bean.ResourceParams;
27
18
  import com.ft.sdk.garble.bean.UserData;
28
- import com.ft.sdk.sessionreplay.FTSessionReplayConfig;
29
- import com.ft.sdk.sessionreplay.SessionReplayInternalCallback;
30
- import com.ft.sdk.sessionreplay.TouchPrivacy;
31
19
 
32
20
  import org.json.JSONArray;
33
21
  import org.json.JSONObject;
34
22
 
35
- import java.io.ByteArrayOutputStream;
36
- import java.io.File;
37
- import java.io.FileInputStream;
38
- import java.lang.reflect.InvocationTargetException;
39
- import java.lang.reflect.Method;
40
23
  import java.util.ArrayList;
41
24
  import java.util.HashMap;
42
25
  import java.util.Iterator;
@@ -52,9 +35,7 @@ public final class FTCocosBridge {
52
35
  }
53
36
 
54
37
  public static String invoke(String method, String payload) {
55
- String forwarded = forwardToMainProcess(method, payload);
56
- if (forwarded != null) return forwarded;
57
- return invokeLocal(method, payload);
38
+ return FTBridgeTransport.invoke("sdk", method, payload);
58
39
  }
59
40
 
60
41
  static String invokeLocal(String method, String payload) {
@@ -77,63 +58,11 @@ public final class FTCocosBridge {
77
58
  }
78
59
  }
79
60
 
80
- private static String forwardToMainProcess(String method, String payload) {
81
- Activity activity = resolveActivity();
82
- if (activity == null || !isSecondaryProcess(activity)) return null;
83
-
84
- try {
85
- Bundle arguments = new Bundle();
86
- arguments.putString(FTCocosBridgeProvider.ARGUMENT_PAYLOAD, payload);
87
- Uri uri = Uri.parse("content://" + activity.getPackageName()
88
- + FTCocosBridgeProvider.AUTHORITY_SUFFIX);
89
- Bundle result = activity.getContentResolver().call(
90
- uri,
91
- FTCocosBridgeProvider.METHOD_INVOKE,
92
- method,
93
- arguments);
94
- return result == null
95
- ? null
96
- : result.getString(FTCocosBridgeProvider.RESULT_RESPONSE);
97
- } catch (IllegalArgumentException providerUnavailable) {
98
- // Existing integrations may not have registered the optional bridge
99
- // provider yet. Preserve their same-process behavior.
100
- return null;
101
- }
102
- }
103
-
104
- private static boolean isSecondaryProcess(Context context) {
105
- String currentProcess = currentProcessName(context);
106
- String mainProcess = context.getApplicationInfo().processName;
107
- return currentProcess != null && mainProcess != null && !mainProcess.equals(currentProcess);
108
- }
109
-
110
- private static String currentProcessName(Context context) {
111
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
112
- return Application.getProcessName();
113
- }
114
- ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
115
- if (manager == null) return null;
116
- List<ActivityManager.RunningAppProcessInfo> processes = manager.getRunningAppProcesses();
117
- if (processes == null) return null;
118
- int currentPid = Process.myPid();
119
- for (ActivityManager.RunningAppProcessInfo process : processes) {
120
- if (process.pid == currentPid) return process.processName;
121
- }
122
- return null;
123
- }
124
-
125
61
  private static Object dispatch(String method, JSONObject payload) throws Exception {
126
62
  switch (method) {
127
- case "replay.beginSaveImage":
128
- return FTCocosReplayImageJobs.begin(payload);
129
- case "replay.pollSaveImage":
130
- return FTCocosReplayImageJobs.poll(payload.getString("job"));
131
63
  case "hybrid.attach":
132
64
  attachHybrid(payload);
133
65
  return null;
134
- case "hybrid.setExternalRecorderActive":
135
- setExternalRecorderActive(payload.getBoolean("active"));
136
- return null;
137
66
  case "sdk.configure":
138
67
  configureSdk(payload);
139
68
  return null;
@@ -196,25 +125,6 @@ public final class FTCocosBridge {
196
125
  case "trace.getHeaders":
197
126
  return FTTraceManager.get().getTraceHeader(
198
127
  payload.optString("resourceKey", ""), payload.getString("url"));
199
- case "replay.configure":
200
- configureReplay(payload);
201
- return null;
202
- case "replay.getContext":
203
- return SessionReplayManager.get().getCurrentFlutterRumContext();
204
- case "replay.saveImage":
205
- return saveReplayImage(payload);
206
- case "replay.saveImageV2":
207
- return saveReplayImageV2(payload);
208
- case "replay.writeSegment":
209
- SessionReplayManager.get().writeExternalSegment(
210
- payload.getString("segment"), payload.getString("viewId"));
211
- return null;
212
- case "replay.setRecordCount":
213
- SessionReplayManager.get().setExternalRecordCount(
214
- payload.getString("viewId"), payload.getLong("count"));
215
- return null;
216
- case "replay.stop":
217
- return null;
218
128
  default:
219
129
  throw new IllegalArgumentException("Unknown bridge method: " + method);
220
130
  }
@@ -225,7 +135,6 @@ public final class FTCocosBridge {
225
135
  if (hasText(json, "sdkVersion")) {
226
136
  FTSdk.appendGlobalContext(COCOS_SDK_VERSION_KEY, json.getString("sdkVersion"));
227
137
  }
228
- if (json.optBoolean("requiresReplay", false)) hybridRecorderSwitchMethod();
229
138
  }
230
139
 
231
140
  private static void ensureNativeHostInitialized() {
@@ -235,28 +144,6 @@ public final class FTCocosBridge {
235
144
  }
236
145
  }
237
146
 
238
- private static Method hybridRecorderSwitchMethod() {
239
- try {
240
- return SessionReplayManager.class.getMethod(
241
- "setExternalRecorderActive", boolean.class);
242
- } catch (NoSuchMethodException error) {
243
- throw new IllegalStateException(
244
- "Android Session Replay does not support Hybrid recorder switching; "
245
- + "upgrade the Native SDK");
246
- }
247
- }
248
-
249
- private static void setExternalRecorderActive(boolean active) throws Exception {
250
- ensureNativeHostInitialized();
251
- try {
252
- hybridRecorderSwitchMethod().invoke(SessionReplayManager.get(), active);
253
- } catch (InvocationTargetException error) {
254
- Throwable cause = error.getCause();
255
- if (cause instanceof Exception) throw (Exception) cause;
256
- throw error;
257
- }
258
- }
259
-
260
147
  private static void configureSdk(JSONObject json) throws Exception {
261
148
  FTSDKConfig config;
262
149
  if (hasText(json, "datakitUrl")) {
@@ -340,20 +227,6 @@ public final class FTCocosBridge {
340
227
  FTSdk.initTraceWithConfig(config);
341
228
  }
342
229
 
343
- private static void configureReplay(JSONObject json) throws Exception {
344
- FTSessionReplayConfig config = new FTSessionReplayConfig();
345
- if (json.has("sampleRate")) config.setSampleRate((float) json.getDouble("sampleRate"));
346
- if (json.has("sessionOnErrorSampleRate")) config.setSessionReplayOnErrorSampleRate((float) json.getDouble("sessionOnErrorSampleRate"));
347
- if ("show".equals(json.optString("touchPrivacy"))) config.setTouchPrivacy(TouchPrivacy.SHOW);
348
- config.setInternalCallback(new SessionReplayInternalCallback() {
349
- @Override public Activity getCurrentActivity() { return resolveActivity(); }
350
- });
351
- Method externalMode = FTSessionReplayConfig.class.getDeclaredMethod("setExternalRecorderMode", boolean.class);
352
- externalMode.setAccessible(true);
353
- externalMode.invoke(config, true);
354
- FTSdk.initSessionReplayConfig(config);
355
- }
356
-
357
230
  private static void addResource(JSONObject payload) throws Exception {
358
231
  JSONObject content = payload.getJSONObject("content");
359
232
  ResourceParams params = new ResourceParams();
@@ -383,58 +256,6 @@ public final class FTCocosBridge {
383
256
  FTRUMGlobalManager.get().addResource(payload.getString("key"), params, status);
384
257
  }
385
258
 
386
- private static String saveReplayImage(JSONObject json) throws Exception {
387
- byte[] bytes = readFile(new File(json.getString("path")));
388
- return SessionReplayManager.get().saveFlutterImageResource(bytes, json.getInt("width"), json.getInt("height"));
389
- }
390
-
391
- private static Object saveReplayImageV2(JSONObject json) throws Exception {
392
- byte[] bytes = readFile(new File(json.getString("path")));
393
- Method method;
394
- try {
395
- method = SessionReplayManager.class.getMethod(
396
- "saveExternalImageResourceV2",
397
- byte[].class,
398
- int.class,
399
- int.class,
400
- float.class,
401
- int.class);
402
- } catch (NoSuchMethodException unavailable) {
403
- throw new IllegalArgumentException("Unknown bridge method: replay.saveImageV2");
404
- }
405
- try {
406
- return method.invoke(
407
- SessionReplayManager.get(),
408
- bytes,
409
- json.getInt("width"),
410
- json.getInt("height"),
411
- (float) json.optDouble("quality", 0.45),
412
- json.optInt("maxFrameBytes", 40 * 1024));
413
- } catch (InvocationTargetException error) {
414
- Throwable cause = error.getCause();
415
- if (cause instanceof Exception) throw (Exception) cause;
416
- throw error;
417
- }
418
- }
419
-
420
- private static Activity resolveActivity() {
421
- String[] classNames = {"com.cocos.lib.CocosActivity", "org.cocos2dx.lib.Cocos2dxActivity"};
422
- String[] methodNames = {"getContext", "getActivity"};
423
- for (String className : classNames) {
424
- for (String methodName : methodNames) {
425
- try {
426
- Object value = Class.forName(className).getMethod(methodName).invoke(null);
427
- if (value instanceof Activity) return (Activity) value;
428
- if (value instanceof Context && ((Context) value).getApplicationContext() instanceof Activity) {
429
- return (Activity) ((Context) value).getApplicationContext();
430
- }
431
- } catch (Throwable ignored) {
432
- }
433
- }
434
- }
435
- return null;
436
- }
437
-
438
259
  private static TraceType traceType(String value) {
439
260
  if ("zipkinMultiHeader".equals(value)) return TraceType.ZIPKIN_MULTI_HEADER;
440
261
  if ("zipkinSingleHeader".equals(value)) return TraceType.ZIPKIN_SINGLE_HEADER;
@@ -521,16 +342,5 @@ public final class FTCocosBridge {
521
342
  return json.has(name) ? json.optLong(name, -1) : -1;
522
343
  }
523
344
 
524
- private static byte[] readFile(File file) throws Exception {
525
- FileInputStream input = new FileInputStream(file);
526
- try {
527
- ByteArrayOutputStream output = new ByteArrayOutputStream((int) Math.min(file.length(), Integer.MAX_VALUE));
528
- byte[] buffer = new byte[16 * 1024];
529
- int read;
530
- while ((read = input.read(buffer)) >= 0) output.write(buffer, 0, read);
531
- return output.toByteArray();
532
- } finally {
533
- input.close();
534
- }
535
- }
345
+
536
346
  }
@@ -0,0 +1,9 @@
1
+ package com.ft.sdk.cocos;
2
+
3
+ /** SDK-managed endpoint allowlist, regenerated when optional modules change. */
4
+ final class FTCocosBridgeModules {
5
+ static String invokeLocal(String endpoint, String method, String payload) {
6
+ if ("sdk".equals(endpoint)) return FTCocosBridge.invokeLocal(method, payload);
7
+ return "{\"ok\":false,\"error\":\"Native SDK extension is not installed; rerun the integration installer\"}";
8
+ }
9
+ }
@@ -32,7 +32,7 @@ public final class FTCocosBridgeProvider extends ContentProvider {
32
32
  }
33
33
  String payload = extras == null ? null : extras.getString(ARGUMENT_PAYLOAD);
34
34
  Bundle result = new Bundle();
35
- result.putString(RESULT_RESPONSE, FTCocosBridge.invokeLocal(argument, payload));
35
+ result.putString(RESULT_RESPONSE, FTCocosBridgeModules.invokeLocal(extras == null ? "sdk" : extras.getString("endpoint", "sdk"), argument, payload));
36
36
  return result;
37
37
  }
38
38
 
@@ -1,8 +1,13 @@
1
1
  #import "FTCocosBridge.h"
2
- #import "FTCocosReplayImageJobs.h"
3
2
 
4
- #import "FTMobileSDK.h"
5
- #import "FTSessionReplay.h"
3
+ #import "FTMobileAgent.h"
4
+ #import "FTSDKConfig.h"
5
+ #import "FTRumConfig.h"
6
+ #import "FTLoggerConfig.h"
7
+ #import "FTMobileConfig.h"
8
+ #import "FTExternalDataManager.h"
9
+ #import "FTResourceMetricsModel.h"
10
+ #import "FTResourceContentModel.h"
6
11
  #import <UIKit/UIKit.h>
7
12
  #import <objc/message.h>
8
13
 
@@ -25,10 +30,6 @@
25
30
  }
26
31
 
27
32
  + (id)dispatch:(NSString *)method arguments:(NSDictionary *)arguments {
28
- if ([method isEqualToString:@"replay.beginSaveImage"]) return [self beginSaveImage:arguments];
29
- if ([method isEqualToString:@"replay.pollSaveImage"]) {
30
- return [FTCocosReplayImageJobs poll:[self requiredText:arguments key:@"job"]];
31
- }
32
33
  FTExternalDataManager *rum = [FTExternalDataManager sharedManager];
33
34
  if ([method isEqualToString:@"hybrid.attach"]) {
34
35
  [self ensureNativeHostInitialized];
@@ -36,12 +37,6 @@
36
37
  if (sdkVersion.length > 0) {
37
38
  [FTMobileAgent appendGlobalContext:@{ @"sdk_package_cocos": sdkVersion }];
38
39
  }
39
- if ([arguments[@"requiresReplay"] boolValue]) [self ensureHybridRecorderSwitch];
40
- return nil;
41
- }
42
- if ([method isEqualToString:@"hybrid.setExternalRecorderActive"]) {
43
- [self ensureNativeHostInitialized];
44
- [self setExternalRecorderActive:[arguments[@"active"] boolValue]];
45
40
  return nil;
46
41
  }
47
42
  if ([method isEqualToString:@"sdk.configure"]) {
@@ -180,97 +175,10 @@
180
175
  NSString *key = [self text:arguments[@"resourceKey"]];
181
176
  return key.length > 0 ? [rum getTraceHeaderWithKey:key url:url] : [rum getTraceHeaderWithUrl:url];
182
177
  }
183
- if ([method isEqualToString:@"replay.configure"]) {
184
- FTSessionReplayConfig *config = [[FTSessionReplayConfig alloc] init];
185
- [self ensureExternalReplayAPIForConfig:config];
186
- if (arguments[@"sampleRate"]) config.sampleRate = [self percent:arguments[@"sampleRate"]];
187
- if (arguments[@"sessionOnErrorSampleRate"]) config.sessionReplayOnErrorSampleRate = [self percent:arguments[@"sessionOnErrorSampleRate"]];
188
- if ([[self text:arguments[@"touchPrivacy"]] isEqualToString:@"show"]) config.touchPrivacy = FTTouchPrivacyLevelShow;
189
- SEL externalMode = NSSelectorFromString(@"setExternalRecorderMode:");
190
- ((void (*)(id, SEL, BOOL))objc_msgSend)(config, externalMode, YES);
191
- [[FTRumSessionReplay sharedInstance] startWithSessionReplayConfig:config];
192
- return nil;
193
- }
194
- if ([method isEqualToString:@"replay.getContext"]) {
195
- return [self invokeReplayObjectSelector:NSSelectorFromString(@"currentExternalRUMContext")];
196
- }
197
- if ([method isEqualToString:@"replay.saveImage"]) {
198
- NSData *rgba = [NSData dataWithContentsOfFile:[self requiredText:arguments key:@"path"]];
199
- if (!rgba) [self fail:@"Unable to read replay RGBA file"];
200
- NSData *png = [self pngDataFromRGBA:rgba
201
- width:[arguments[@"width"] unsignedIntegerValue]
202
- height:[arguments[@"height"] unsignedIntegerValue]];
203
- if (!png) [self fail:@"Unable to encode replay image"];
204
- return [self invokeReplayObjectSelector:NSSelectorFromString(@"saveExternalImageResourceData:mimeType:")
205
- first:png
206
- second:@"image/png"];
207
- }
208
- if ([method isEqualToString:@"replay.saveImageV2"]) {
209
- NSUInteger width = [arguments[@"width"] unsignedIntegerValue];
210
- NSUInteger height = [arguments[@"height"] unsignedIntegerValue];
211
- NSData *rgba = [NSData dataWithContentsOfFile:[self requiredText:arguments key:@"path"]];
212
- if (!rgba) [self fail:@"Unable to read replay RGBA file"];
213
- UIImage *image = [self imageFromRGBA:rgba width:width height:height];
214
- if (!image) [self fail:@"Unable to decode replay RGBA image"];
215
-
216
- CGFloat quality = MIN(1.0, MAX(0.1, [arguments[@"quality"] doubleValue] ?: 0.45));
217
- NSUInteger maxFrameBytes = [arguments[@"maxFrameBytes"] unsignedIntegerValue] ?: 40 * 1024;
218
- UIImage *encodedImage = [self opaqueImageFromImage:image size:CGSizeMake(width, height)];
219
- NSData *jpeg = UIImageJPEGRepresentation(encodedImage, quality);
220
- if (jpeg.length > maxFrameBytes) {
221
- quality = MAX(0.2, quality * 0.7);
222
- jpeg = UIImageJPEGRepresentation(encodedImage, quality);
223
- }
224
- if (jpeg.length > maxFrameBytes && width > 1 && height > 1) {
225
- width = MAX(1, (NSUInteger)floor(width * 0.75));
226
- height = MAX(1, (NSUInteger)floor(height * 0.75));
227
- encodedImage = [self opaqueImageFromImage:image size:CGSizeMake(width, height)];
228
- jpeg = UIImageJPEGRepresentation(encodedImage, quality);
229
- }
230
- if (!jpeg || jpeg.length > maxFrameBytes) return @{ @"accepted": @NO };
231
-
232
- NSString *resourceID = [self invokeReplayObjectSelector:NSSelectorFromString(@"saveExternalImageResourceData:mimeType:")
233
- first:jpeg
234
- second:@"image/jpeg"];
235
- if (resourceID.length == 0) [self fail:@"Unable to save replay image resource"];
236
- return @{
237
- @"accepted": @YES,
238
- @"resourceId": resourceID,
239
- @"byteSize": @(jpeg.length),
240
- @"width": @(width),
241
- @"height": @(height),
242
- @"mimeType": @"image/jpeg",
243
- };
244
- }
245
- if ([method isEqualToString:@"replay.writeSegment"]) {
246
- [self invokeReplayVoidSelector:NSSelectorFromString(@"writeExternalSegment:viewID:")
247
- first:[self requiredText:arguments key:@"segment"]
248
- second:[self requiredText:arguments key:@"viewId"]];
249
- return nil;
250
- }
251
- if ([method isEqualToString:@"replay.setRecordCount"]) {
252
- [self invokeReplayCountSelector:NSSelectorFromString(@"setExternalRecordCountForViewID:count:")
253
- viewID:[self requiredText:arguments key:@"viewId"]
254
- count:[arguments[@"count"] unsignedIntegerValue]];
255
- return nil;
256
- }
257
- if ([method isEqualToString:@"replay.stop"]) return nil;
258
178
  [self fail:[NSString stringWithFormat:@"Unknown bridge method: %@", method]];
259
179
  return nil;
260
180
  }
261
181
 
262
- + (NSString *)beginSaveImage:(NSDictionary *)arguments {
263
- NSString *method = [self requiredText:arguments key:@"method"];
264
- if (![method isEqualToString:@"replay.saveImage"] && ![method isEqualToString:@"replay.saveImageV2"]) {
265
- [self fail:@"Unsupported asynchronous Replay method"];
266
- }
267
- NSDictionary *payload = [[self dictionary:arguments[@"arguments"]] copy];
268
- if (!payload) [self fail:@"Replay image arguments are required"];
269
- return [FTCocosReplayImageJobs beginWithWork:^NSString *{
270
- return [self responseWithValue:[self dispatch:method arguments:payload] error:nil];
271
- }];
272
- }
273
-
274
182
  + (void)ensureNativeHostInitialized {
275
183
  @try {
276
184
  if (![FTMobileAgent sharedInstance]) {
@@ -281,19 +189,6 @@
281
189
  }
282
190
  }
283
191
 
284
- + (void)ensureHybridRecorderSwitch {
285
- SEL selector = NSSelectorFromString(@"setExternalRecorderActive:");
286
- if (![[FTRumSessionReplay sharedInstance] respondsToSelector:selector]) {
287
- [self fail:@"iOS Session Replay does not support Hybrid recorder switching; upgrade the Native SDK"];
288
- }
289
- }
290
-
291
- + (void)setExternalRecorderActive:(BOOL)active {
292
- [self ensureHybridRecorderSwitch];
293
- SEL selector = NSSelectorFromString(@"setExternalRecorderActive:");
294
- ((void (*)(id, SEL, BOOL))objc_msgSend)([FTRumSessionReplay sharedInstance], selector, active);
295
- }
296
-
297
192
  + (void)addResource:(NSDictionary *)arguments manager:(FTExternalDataManager *)manager {
298
193
  NSDictionary *input = [self dictionary:arguments[@"content"]] ?: @{};
299
194
  NSURL *url = [NSURL URLWithString:[self text:input[@"url"]] ?: @""];
@@ -323,96 +218,6 @@
323
218
  [manager addResourceWithKey:[self requiredText:arguments key:@"key"] metrics:metrics content:content];
324
219
  }
325
220
 
326
- + (id)invokeReplayObjectSelector:(SEL)selector {
327
- id target = [FTRumSessionReplay sharedInstance];
328
- if (![target respondsToSelector:selector]) [self missingReplayAPI:selector];
329
- return ((id (*)(id, SEL))objc_msgSend)(target, selector);
330
- }
331
-
332
- + (id)invokeReplayObjectSelector:(SEL)selector object:(id)object {
333
- id target = [FTRumSessionReplay sharedInstance];
334
- if (![target respondsToSelector:selector]) [self missingReplayAPI:selector];
335
- return ((id (*)(id, SEL, id))objc_msgSend)(target, selector, object);
336
- }
337
-
338
- + (id)invokeReplayObjectSelector:(SEL)selector first:(id)first second:(id)second {
339
- id target = [FTRumSessionReplay sharedInstance];
340
- if (![target respondsToSelector:selector]) [self missingReplayAPI:selector];
341
- return ((id (*)(id, SEL, id, id))objc_msgSend)(target, selector, first, second);
342
- }
343
-
344
- + (void)invokeReplayVoidSelector:(SEL)selector first:(id)first second:(id)second {
345
- id target = [FTRumSessionReplay sharedInstance];
346
- if (![target respondsToSelector:selector]) [self missingReplayAPI:selector];
347
- ((void (*)(id, SEL, id, id))objc_msgSend)(target, selector, first, second);
348
- }
349
-
350
- + (void)invokeReplayCountSelector:(SEL)selector viewID:(NSString *)viewID count:(NSUInteger)count {
351
- id target = [FTRumSessionReplay sharedInstance];
352
- if (![target respondsToSelector:selector]) [self missingReplayAPI:selector];
353
- ((void (*)(id, SEL, id, NSUInteger))objc_msgSend)(target, selector, viewID, count);
354
- }
355
-
356
- + (void)missingReplayAPI:(SEL)selector {
357
- [self fail:[NSString stringWithFormat:@"FTMobileSDK lacks external Session Replay API %@; use the Cocos-compatible iOS SDK release", NSStringFromSelector(selector)]];
358
- }
359
-
360
- + (void)ensureExternalReplayAPIForConfig:(FTSessionReplayConfig *)config {
361
- SEL externalMode = NSSelectorFromString(@"setExternalRecorderMode:");
362
- if (![config respondsToSelector:externalMode]) [self missingReplayAPI:externalMode];
363
-
364
- id target = [FTRumSessionReplay sharedInstance];
365
- NSArray<NSString *> *selectorNames = @[
366
- @"currentExternalRUMContext",
367
- @"saveExternalImageResourceData:mimeType:",
368
- @"writeExternalSegment:viewID:",
369
- @"setExternalRecordCountForViewID:count:",
370
- ];
371
- for (NSString *name in selectorNames) {
372
- SEL selector = NSSelectorFromString(name);
373
- if (![target respondsToSelector:selector]) [self missingReplayAPI:selector];
374
- }
375
- }
376
-
377
- + (NSData *)pngDataFromRGBA:(NSData *)rgba width:(NSUInteger)width height:(NSUInteger)height {
378
- UIImage *image = [self imageFromRGBA:rgba width:width height:height];
379
- return image ? UIImagePNGRepresentation(image) : nil;
380
- }
381
-
382
- + (UIImage *)imageFromRGBA:(NSData *)rgba width:(NSUInteger)width height:(NSUInteger)height {
383
- if (width == 0 || height == 0 || width > NSUIntegerMax / height / 4 || rgba.length < width * height * 4) {
384
- return nil;
385
- }
386
- NSMutableData *pixels = [rgba mutableCopy];
387
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
388
- CGContextRef context = CGBitmapContextCreate(pixels.mutableBytes,
389
- width,
390
- height,
391
- 8,
392
- width * 4,
393
- colorSpace,
394
- (CGBitmapInfo)kCGBitmapByteOrderDefault |
395
- (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
396
- CGColorSpaceRelease(colorSpace);
397
- if (!context) return nil;
398
- CGImageRef imageRef = CGBitmapContextCreateImage(context);
399
- CGContextRelease(context);
400
- if (!imageRef) return nil;
401
- UIImage *image = [UIImage imageWithCGImage:imageRef];
402
- CGImageRelease(imageRef);
403
- return image;
404
- }
405
-
406
- + (UIImage *)opaqueImageFromImage:(UIImage *)image size:(CGSize)size {
407
- UIGraphicsBeginImageContextWithOptions(size, YES, 1.0);
408
- [[UIColor whiteColor] setFill];
409
- UIRectFill(CGRectMake(0, 0, size.width, size.height));
410
- [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
411
- UIImage *opaque = UIGraphicsGetImageFromCurrentImageContext();
412
- UIGraphicsEndImageContext();
413
- return opaque;
414
- }
415
-
416
221
  + (NSString *)responseWithValue:(id)value error:(NSString *)error {
417
222
  NSMutableDictionary *response = [@{ @"ok": @(error == nil) } mutableCopy];
418
223
  if (value) response[@"value"] = value;
@@ -1,18 +1,17 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'FTCocosBridge'
3
- s.version = '0.1.0-alpha.4'
3
+ s.version = '0.1.0-alpha.6'
4
4
  s.summary = 'TrueWatch Mobile SDK native bridge for Cocos Creator.'
5
5
  s.homepage = 'https://github.com/TrueWatchTech/datakit-cocos'
6
6
  s.license = { :type => 'Apache-2.0' }
7
7
  s.author = { 'TrueWatch' => 'support@truewatch.com' }
8
8
  s.source = { :path => '.' }
9
9
  s.platform = :ios, '12.0'
10
- s.source_files = 'FTCocosBridge.{h,m}', 'FTCocosReplayImageJobs.{h,m}'
10
+ s.source_files = 'FTCocosBridge.{h,m}'
11
11
  s.public_header_files = 'FTCocosBridge.h'
12
12
  s.requires_arc = true
13
13
  # Cocos resolves FTCocosBridge by class name at runtime, so no direct symbol
14
14
  # reference would otherwise keep the Objective-C category/class in the app.
15
15
  s.user_target_xcconfig = { 'OTHER_LDFLAGS' => '$(inherited) -ObjC' }
16
- s.dependency 'TrueWatchSDK/Agent', '1.6.8-alpha.2'
17
- s.dependency 'TrueWatchSDK/FTSessionReplay', '1.6.8-alpha.2'
16
+ s.dependency 'TrueWatchSDK/Agent', '1.6.8-alpha.5'
18
17
  end
@@ -0,0 +1,25 @@
1
+ // swift-tools-version:5.3
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "FTCocosBridge",
6
+ platforms: [.iOS(.v12)],
7
+ products: [.library(name: "FTCocosBridge", targets: ["FTCocosBridge"])],
8
+ dependencies: [
9
+ .package(url: "https://github.com/TrueWatchTech/datakit-ios.git", .exact("1.6.8-alpha.5")),
10
+ ],
11
+ targets: [
12
+ .target(
13
+ name: "FTCocosBridge",
14
+ dependencies: [
15
+ .product(name: "TrueWatchSDK", package: "datakit-ios"),
16
+ ],
17
+ path: ".",
18
+ exclude: ["FTCocosBridge.podspec"],
19
+ sources: ["FTCocosBridge.m"],
20
+ publicHeadersPath: "include",
21
+ cSettings: [.headerSearchPath(".")],
22
+ linkerSettings: [.linkedFramework("UIKit")]
23
+ ),
24
+ ]
25
+ )
@@ -0,0 +1,2 @@
1
+ // Keep the public SPM header in sync with the CocoaPods/source integration.
2
+ #import "../FTCocosBridge.h"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truewatchtech/cocos-sdk",
3
- "version": "0.1.0-alpha.4",
3
+ "version": "0.1.0-alpha.6",
4
4
  "description": "Observability SDK integration for Cocos Creator 2.4 and 3.x",
5
5
  "license": "Apache-2.0",
6
6
  "author": "TrueWatch",
@@ -17,7 +17,6 @@
17
17
  "truewatch",
18
18
  "cocos-creator",
19
19
  "rum",
20
- "session-replay",
21
20
  "observability"
22
21
  ],
23
22
  "exports": {
@@ -31,19 +30,25 @@
31
30
  "import": "./dist/creator3/creator3/index.js",
32
31
  "default": "./dist/creator3/creator3/index.js"
33
32
  },
34
- "./package.json": "./package.json"
33
+ "./package.json": "./package.json",
34
+ "./plugin-api": {
35
+ "types": "./dist/creator2/core/plugin-api.d.ts",
36
+ "import": "./dist/creator3/core/plugin-api.js",
37
+ "require": "./dist/creator2/core/plugin-api.js",
38
+ "default": "./dist/creator2/core/plugin-api.js"
39
+ }
35
40
  },
36
41
  "files": [
37
42
  "creator2",
38
43
  "creator3",
39
44
  "dist",
40
- "components",
41
45
  "extensions",
42
46
  "native",
43
47
  "bin",
44
48
  "README.md",
45
49
  "LICENSE",
46
- "THIRD_PARTY_NOTICES"
50
+ "THIRD_PARTY_NOTICES",
51
+ "plugin-api"
47
52
  ],
48
53
  "bin": {
49
54
  "truewatch-cocos": "bin/cli.cjs"
@@ -0,0 +1,4 @@
1
+ {
2
+ "main": "../dist/creator2/core/plugin-api.js",
3
+ "types": "../dist/creator2/core/plugin-api.d.ts"
4
+ }
@@ -1,23 +0,0 @@
1
- const { ccclass, property, menu, disallowMultiple } = cc._decorator;
2
-
3
- export enum ReplayPrivacyMode {
4
- Mask = 0,
5
- Hide = 1,
6
- }
7
-
8
- /** Attach to a node or prefab to protect its bounds in Session Replay. */
9
- @ccclass('ReplayPrivacy')
10
- @menu('Session Replay/ReplayPrivacy')
11
- @disallowMultiple
12
- export default class ReplayPrivacy extends cc.Component {
13
- @property({
14
- type: cc.Enum(ReplayPrivacyMode),
15
- tooltip: 'Mask fills the Replay region gray; Hide fills it black. The live scene is unchanged.',
16
- })
17
- mode: ReplayPrivacyMode = ReplayPrivacyMode.Mask;
18
-
19
- /** Read by the SDK during capture; independent of SDK initialization order. */
20
- get replayPrivacyMode(): 'mask' | 'hide' {
21
- return this.mode === ReplayPrivacyMode.Hide ? 'hide' : 'mask';
22
- }
23
- }