@cloudcare/cocos-sdk 0.1.0-alpha.5 → 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 (174) hide show
  1. package/README.md +13 -1
  2. package/bin/cli.cjs +40 -21
  3. package/bin/legacy-asset-hashes.json +27 -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 -26
  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 +52 -30
  68. package/extensions/creator2/install-spm.cjs +16 -8
  69. package/extensions/creator2/legacy-asset-hashes.json +27 -0
  70. package/extensions/creator2/managed-assets.cjs +67 -0
  71. package/extensions/creator3/install-native.cjs +52 -30
  72. package/extensions/creator3/install-spm.cjs +16 -8
  73. package/extensions/creator3/legacy-asset-hashes.json +27 -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 +0 -202
  80. package/native/ios/FTCocosBridge.podspec +2 -3
  81. package/native/ios/Package.swift +1 -2
  82. package/package.json +10 -5
  83. package/plugin-api/package.json +4 -0
  84. package/components/creator2/ReplayPrivacy.ts +0 -23
  85. package/components/creator3/ReplayPrivacy.ts +0 -25
  86. package/dist/creator2/core/replay-async-transport.d.ts +0 -4
  87. package/dist/creator2/core/replay-async-transport.d.ts.map +0 -1
  88. package/dist/creator2/core/replay-async-transport.js +0 -67
  89. package/dist/creator2/core/replay-async-transport.js.map +0 -1
  90. package/dist/creator2/core/replay-budget.d.ts +0 -28
  91. package/dist/creator2/core/replay-budget.d.ts.map +0 -1
  92. package/dist/creator2/core/replay-budget.js +0 -113
  93. package/dist/creator2/core/replay-budget.js.map +0 -1
  94. package/dist/creator2/core/replay-diagnostics.d.ts +0 -36
  95. package/dist/creator2/core/replay-diagnostics.d.ts.map +0 -1
  96. package/dist/creator2/core/replay-diagnostics.js +0 -40
  97. package/dist/creator2/core/replay-diagnostics.js.map +0 -1
  98. package/dist/creator2/core/replay-encoding.d.ts +0 -31
  99. package/dist/creator2/core/replay-encoding.d.ts.map +0 -1
  100. package/dist/creator2/core/replay-encoding.js +0 -63
  101. package/dist/creator2/core/replay-encoding.js.map +0 -1
  102. package/dist/creator2/core/replay-file.d.ts +0 -5
  103. package/dist/creator2/core/replay-file.d.ts.map +0 -1
  104. package/dist/creator2/core/replay-file.js +0 -101
  105. package/dist/creator2/core/replay-file.js.map +0 -1
  106. package/dist/creator2/core/replay-pixels.d.ts +0 -3
  107. package/dist/creator2/core/replay-pixels.d.ts.map +0 -1
  108. package/dist/creator2/core/replay-pixels.js +0 -16
  109. package/dist/creator2/core/replay-pixels.js.map +0 -1
  110. package/dist/creator2/core/replay-privacy-nodes.d.ts +0 -14
  111. package/dist/creator2/core/replay-privacy-nodes.d.ts.map +0 -1
  112. package/dist/creator2/core/replay-privacy-nodes.js +0 -18
  113. package/dist/creator2/core/replay-privacy-nodes.js.map +0 -1
  114. package/dist/creator2/core/replay-privacy.d.ts +0 -15
  115. package/dist/creator2/core/replay-privacy.d.ts.map +0 -1
  116. package/dist/creator2/core/replay-privacy.js +0 -36
  117. package/dist/creator2/core/replay-privacy.js.map +0 -1
  118. package/dist/creator2/core/replay.d.ts +0 -99
  119. package/dist/creator2/core/replay.d.ts.map +0 -1
  120. package/dist/creator2/core/replay.js +0 -611
  121. package/dist/creator2/core/replay.js.map +0 -1
  122. package/dist/creator2/creator2/capture.d.ts +0 -17
  123. package/dist/creator2/creator2/capture.d.ts.map +0 -1
  124. package/dist/creator2/creator2/capture.js +0 -168
  125. package/dist/creator2/creator2/capture.js.map +0 -1
  126. package/dist/creator3/core/replay-async-transport.d.ts +0 -4
  127. package/dist/creator3/core/replay-async-transport.d.ts.map +0 -1
  128. package/dist/creator3/core/replay-async-transport.js +0 -16
  129. package/dist/creator3/core/replay-async-transport.js.map +0 -1
  130. package/dist/creator3/core/replay-budget.d.ts +0 -28
  131. package/dist/creator3/core/replay-budget.d.ts.map +0 -1
  132. package/dist/creator3/core/replay-budget.js +0 -105
  133. package/dist/creator3/core/replay-budget.js.map +0 -1
  134. package/dist/creator3/core/replay-diagnostics.d.ts +0 -36
  135. package/dist/creator3/core/replay-diagnostics.d.ts.map +0 -1
  136. package/dist/creator3/core/replay-diagnostics.js +0 -36
  137. package/dist/creator3/core/replay-diagnostics.js.map +0 -1
  138. package/dist/creator3/core/replay-encoding.d.ts +0 -31
  139. package/dist/creator3/core/replay-encoding.d.ts.map +0 -1
  140. package/dist/creator3/core/replay-encoding.js +0 -62
  141. package/dist/creator3/core/replay-encoding.js.map +0 -1
  142. package/dist/creator3/core/replay-file.d.ts +0 -5
  143. package/dist/creator3/core/replay-file.d.ts.map +0 -1
  144. package/dist/creator3/core/replay-file.js +0 -31
  145. package/dist/creator3/core/replay-file.js.map +0 -1
  146. package/dist/creator3/core/replay-pixels.d.ts +0 -3
  147. package/dist/creator3/core/replay-pixels.d.ts.map +0 -1
  148. package/dist/creator3/core/replay-pixels.js +0 -13
  149. package/dist/creator3/core/replay-pixels.js.map +0 -1
  150. package/dist/creator3/core/replay-privacy-nodes.d.ts +0 -14
  151. package/dist/creator3/core/replay-privacy-nodes.d.ts.map +0 -1
  152. package/dist/creator3/core/replay-privacy-nodes.js +0 -15
  153. package/dist/creator3/core/replay-privacy-nodes.js.map +0 -1
  154. package/dist/creator3/core/replay-privacy.d.ts +0 -15
  155. package/dist/creator3/core/replay-privacy.d.ts.map +0 -1
  156. package/dist/creator3/core/replay-privacy.js +0 -33
  157. package/dist/creator3/core/replay-privacy.js.map +0 -1
  158. package/dist/creator3/core/replay.d.ts +0 -99
  159. package/dist/creator3/core/replay.d.ts.map +0 -1
  160. package/dist/creator3/core/replay.js +0 -534
  161. package/dist/creator3/core/replay.js.map +0 -1
  162. package/dist/creator3/creator3/capture.d.ts +0 -17
  163. package/dist/creator3/creator3/capture.d.ts.map +0 -1
  164. package/dist/creator3/creator3/capture.js +0 -112
  165. package/dist/creator3/creator3/capture.js.map +0 -1
  166. package/dist/creator3/creator3/replay-render-cycle.d.ts +0 -9
  167. package/dist/creator3/creator3/replay-render-cycle.d.ts.map +0 -1
  168. package/dist/creator3/creator3/replay-render-cycle.js +0 -12
  169. package/dist/creator3/creator3/replay-render-cycle.js.map +0 -1
  170. package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosReplayImageJobs.java +0 -55
  171. package/native/ios/FTCocosReplayImageJobs.h +0 -11
  172. package/native/ios/FTCocosReplayImageJobs.m +0 -54
  173. package/native/shared/FTReplayFileBridge.h +0 -62
  174. package/native/shared/FTReplayFileWorker.h +0 -88
@@ -145,11 +145,11 @@ function preserveCmakeIntegration(projectFile, project, entry) {
145
145
  if (!fs.existsSync(stateFile) || fs.readFileSync(stateFile, 'utf8') !== serialized) fs.writeFileSync(stateFile, serialized);
146
146
  }
147
147
 
148
- function removeSwiftPackages(projectFile) {
148
+ function removeSwiftPackages(projectFile, productNames = ['FTCocosBridge', 'FTCocosReplayBridge', 'HybridSampleHost']) {
149
149
  const project = readProject(projectFile);
150
150
  const objects = project.objects;
151
151
  const removed = new Set();
152
- for (const productName of ['FTCocosBridge', 'HybridSampleHost']) {
152
+ for (const productName of productNames) {
153
153
  const packageID = identifier(`package:${productName}`);
154
154
  if (!objects[packageID]) continue;
155
155
  removed.add(packageID);
@@ -159,23 +159,31 @@ function removeSwiftPackages(projectFile) {
159
159
  removed.add(identifier(`framework:${id}:${productName}`));
160
160
  }
161
161
  }
162
- if (!removed.size) return;
163
162
  for (const id of removed) delete objects[id];
164
163
  for (const object of Object.values(objects)) {
165
164
  for (const key of ['packageReferences', 'packageProductDependencies', 'files']) {
166
165
  if (Array.isArray(object[key])) object[key] = object[key].filter((id) => !removed.has(id));
167
166
  }
168
- if (object.isa === 'PBXShellScriptBuildPhase') object.shellScript = (object.shellScript || '').replace(restorePattern, '');
167
+
169
168
  }
170
169
  const stateFile = path.join(path.dirname(projectFile), 'cocos-sdk-spm.json');
171
170
  if (fs.existsSync(stateFile)) {
172
171
  const state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
173
- for (const [id, settings] of Object.entries(state.buildLocations)) {
174
- if (objects[id]) Object.assign(objects[id].buildSettings ||= {}, settings);
172
+ state.packages = state.packages.filter(item => !productNames.includes(item.productName));
173
+ if (state.packages.length) {
174
+ fs.writeFileSync(stateFile, `${JSON.stringify(state, null, 2)}\n`);
175
+ } else {
176
+ for (const [id, settings] of Object.entries(state.buildLocations)) {
177
+ if (objects[id]) Object.assign(objects[id].buildSettings ||= {}, settings);
178
+ }
179
+ for (const object of Object.values(objects)) {
180
+ if (object.isa === 'PBXShellScriptBuildPhase') object.shellScript = (object.shellScript || '').replace(restorePattern, '');
181
+ }
182
+ fs.unlinkSync(stateFile);
183
+ fs.rmSync(path.join(path.dirname(projectFile), 'cocos-sdk-spm.cjs'), { force: true });
175
184
  }
176
- fs.unlinkSync(stateFile);
177
- fs.rmSync(path.join(path.dirname(projectFile), 'cocos-sdk-spm.cjs'), { force: true });
178
185
  }
186
+
179
187
  writeProject(projectFile, project);
180
188
  }
181
189
 
@@ -0,0 +1,27 @@
1
+ [
2
+ "058341971ed42ddfde76c28ce19fcc0bba5020fec1f7e1c613c7bda7d2df7677",
3
+ "11ee16e609096ccfe90b17f61d87ab65275a39df4bef6f8c29577e7395aa00f8",
4
+ "15338071a78f1505265cc8efbdc9628e9362f7a2c9fc00989d57461126f8f3f5",
5
+ "1a51af27d68cdf0bf3ce709c9cd60f9b8a2d7defd46d06896ce9a916e1dfc767",
6
+ "2caa0d3d542f5cca0b6b7f3aa2851c7e296b08fce286202a844b52920b1f6dc0",
7
+ "3189144de638b936e14d64ddbf9d4c95e95146ceecc357021473ca8adcc757d1",
8
+ "48ff77a12a7b9b59172f5470a642f23e4c61e9f7e10ee6d9d3f4f41377d696ac",
9
+ "4d2dcd924f1073b8a6fb94d342bee33a281f93c19302104be172e5de9981b3f0",
10
+ "51c71e12df61cfe7e75c3d97080e31a398fbea8719a3e964cec5dd332df1202c",
11
+ "5f33108f27f38836214f2c11badd7bb76ba9ec090f9d5b1490834a9257976939",
12
+ "85ad9622480d954c33a4f9442a391f6d3d9d617a2f1261e5ad769170c6e9cf12",
13
+ "86cf732195aad676898520192ac8aa878267877dc09f85fcf425279d8badc9b8",
14
+ "910792f383c25cd46ddc7d851080a687fa532a93d605fb709b7baff9bb2789cf",
15
+ "95bdc516c4e1b72833af3bec13b18e3c2ac6ae83de284c3f711e97765ed1b461",
16
+ "a748564f0bba03effbf4aa381308f60eedcb618cbd2a37e1c67cdbee596e9ceb",
17
+ "a8a57b5892e7a5063078d561fce790b44d900d2bb3869e43ed4c4de82f1f62ed",
18
+ "cd03df57f7861d19b0a8e0a97e8aff1fa08e5c26d4f43152743968245632535b",
19
+ "d26fb42c6bee416eaf29bc2ed8579edc7a28ca3d0e18433dcb8abea11fac9920",
20
+ "d2d171e4ef1777facdb6fe665105372ea2e6452028d4c32f5e2ccc74dacc8850",
21
+ "d538d9eebaf181687ebf8537fc6ce7c8fae59fa424daeb45c3f900a8e210ecfc",
22
+ "df8e3014e583d60922cd1b7f7f16964c433b260a7e1a7e6c285cb08ce2d9e7e4",
23
+ "e70ca2a537cec56f8424ff4d551c1e97af133938fc7ba863a3944859dcfd194d",
24
+ "f0211acbaaa312bd5a4478bba81fa98293c855692ceca69f141600ff991c5904",
25
+ "f09f9b35ddfb17a7c4e4439384afae93ded6ee0285e778ad013d320cfc880cab",
26
+ "fa88198c5434613ff5ab2d44dce6e7eb8b825085b5b498402810eb144cf81f96"
27
+ ]
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const { createHash } = require('crypto');
5
+ const legacyHashes = new Set(require('./legacy-asset-hashes.json'));
6
+ // Older combined installations predate the ownership manifest. Never leave a
7
+ // locally modified obsolete Replay bridge compiling beside the new bridge.
8
+ const legacyReplayNames = new Set(['FTCocosReplayImageJobs.java', 'FTCocosReplayImageJobs.h', 'FTCocosReplayImageJobs.m', 'FTReplayFileBridge.h', 'FTReplayFileWorker.h']);
9
+ const manifestName = '.cocos-sdk-managed.json';
10
+ const hash = bytes => createHash('sha256').update(bytes).digest('hex');
11
+
12
+ function files(root) {
13
+ const result = [];
14
+ if (!fs.existsSync(root)) return result;
15
+ function visit(directory) {
16
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
17
+ if (entry.name === manifestName || entry.name === '.DS_Store') continue;
18
+ const file = path.join(directory, entry.name);
19
+ if (entry.isSymbolicLink()) throw new Error(`[cocos-sdk] Refusing to copy symbolic link: ${file}`);
20
+ if (entry.isDirectory()) visit(file);
21
+ else result.push(path.relative(root, file).split(path.sep).join('/'));
22
+ }
23
+ }
24
+ visit(root);
25
+ return result;
26
+ }
27
+
28
+ /** Reconciles only files written by the SDK, preserving unrelated project assets. */
29
+ function syncManagedDirectory(destination, sources, overrides = {}) {
30
+ const desired = new Map();
31
+ for (const { root, prefix = '' } of sources) {
32
+ if (!fs.existsSync(root)) throw new Error(`[cocos-sdk] Missing package assets: ${root}`);
33
+ for (const file of files(root)) desired.set(prefix + file, fs.readFileSync(path.join(root, file)));
34
+ }
35
+ for (const [file, content] of Object.entries(overrides)) desired.set(file, Buffer.from(content));
36
+ const manifest = path.join(destination, manifestName);
37
+ const previous = fs.existsSync(manifest) ? JSON.parse(fs.readFileSync(manifest, 'utf8')) : {};
38
+ const existing = files(destination);
39
+ const remove = [];
40
+ // Check every conflict before writing or deleting any managed file.
41
+ for (const file of existing) {
42
+ const digest = hash(fs.readFileSync(path.join(destination, file)));
43
+ const old = previous[file];
44
+ const next = desired.get(file);
45
+ const legacy = legacyHashes.has(digest);
46
+ if (!next && !old && !legacy && legacyReplayNames.has(path.basename(file))) {
47
+ throw new Error(`[cocos-sdk] Preserve or reconcile modified legacy Replay asset before reinstalling: ${path.join(destination, file)}`);
48
+ }
49
+ if ((old || next) && digest !== old && !legacy && (!next || digest !== hash(next))) {
50
+ throw new Error(`[cocos-sdk] Preserve or reconcile modified SDK asset before reinstalling: ${path.join(destination, file)}`);
51
+ }
52
+ if (!next && (old || legacy) && !file.endsWith('.meta')) remove.push(file);
53
+ }
54
+ fs.mkdirSync(destination, { recursive: true });
55
+ for (const file of remove) fs.unlinkSync(path.join(destination, file));
56
+ const nextManifest = {};
57
+ for (const [file, content] of desired) {
58
+ const target = path.resolve(destination, file);
59
+ if (!target.startsWith(path.resolve(destination) + path.sep)) throw new Error('Invalid SDK asset path');
60
+ fs.mkdirSync(path.dirname(target), { recursive: true });
61
+ if (!fs.existsSync(target) || hash(fs.readFileSync(target)) !== hash(content)) fs.writeFileSync(target, content);
62
+ nextManifest[file] = hash(content);
63
+ }
64
+ fs.writeFileSync(manifest, `${JSON.stringify(nextManifest, null, 2)}\n`);
65
+ }
66
+
67
+ module.exports = { syncManagedDirectory };
@@ -0,0 +1,85 @@
1
+ package com.ft.sdk.cocos;
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
+ import java.util.List;
12
+
13
+ /** Shared process routing. Optional modules are selected by the generated allowlist. */
14
+ public final class FTBridgeTransport {
15
+ private FTBridgeTransport() {}
16
+ public static String invoke(String endpoint, String method, String payload) {
17
+ String forwarded = forwardToMainProcess(endpoint, method, payload);
18
+ return forwarded != null ? forwarded : FTCocosBridgeModules.invokeLocal(endpoint, method, payload);
19
+ }
20
+
21
+ private static String forwardToMainProcess(String endpoint, String method, String payload) {
22
+ Activity activity = resolveActivity();
23
+ if (activity == null || !isSecondaryProcess(activity)) return null;
24
+
25
+ try {
26
+ Bundle arguments = new Bundle();
27
+ arguments.putString("endpoint", endpoint);
28
+ arguments.putString(FTCocosBridgeProvider.ARGUMENT_PAYLOAD, payload);
29
+ Uri uri = Uri.parse("content://" + activity.getPackageName()
30
+ + FTCocosBridgeProvider.AUTHORITY_SUFFIX);
31
+ Bundle result = activity.getContentResolver().call(
32
+ uri,
33
+ FTCocosBridgeProvider.METHOD_INVOKE,
34
+ method,
35
+ arguments);
36
+ return result == null
37
+ ? null
38
+ : result.getString(FTCocosBridgeProvider.RESULT_RESPONSE);
39
+ } catch (IllegalArgumentException providerUnavailable) {
40
+ // Existing integrations may not have registered the optional bridge
41
+ // provider yet. Preserve their same-process behavior.
42
+ return null;
43
+ }
44
+ }
45
+
46
+ private static boolean isSecondaryProcess(Context context) {
47
+ String currentProcess = currentProcessName(context);
48
+ String mainProcess = context.getApplicationInfo().processName;
49
+ return currentProcess != null && mainProcess != null && !mainProcess.equals(currentProcess);
50
+ }
51
+
52
+ private static String currentProcessName(Context context) {
53
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
54
+ return Application.getProcessName();
55
+ }
56
+ ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
57
+ if (manager == null) return null;
58
+ List<ActivityManager.RunningAppProcessInfo> processes = manager.getRunningAppProcesses();
59
+ if (processes == null) return null;
60
+ int currentPid = Process.myPid();
61
+ for (ActivityManager.RunningAppProcessInfo process : processes) {
62
+ if (process.pid == currentPid) return process.processName;
63
+ }
64
+ return null;
65
+ }
66
+
67
+ public static Activity resolveActivity() {
68
+ String[] classNames = {"com.cocos.lib.CocosActivity", "org.cocos2dx.lib.Cocos2dxActivity"};
69
+ String[] methodNames = {"getContext", "getActivity"};
70
+ for (String className : classNames) {
71
+ for (String methodName : methodNames) {
72
+ try {
73
+ Object value = Class.forName(className).getMethod(methodName).invoke(null);
74
+ if (value instanceof Activity) return (Activity) value;
75
+ if (value instanceof Context && ((Context) value).getApplicationContext() instanceof Activity) {
76
+ return (Activity) ((Context) value).getApplicationContext();
77
+ }
78
+ } catch (Throwable ignored) {
79
+ }
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+
85
+ }
@@ -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