@truewatchtech/cocos-sdk 0.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +51 -0
- package/THIRD_PARTY_NOTICES +5 -0
- package/bin/cli.cjs +130 -0
- package/creator2/package.json +4 -0
- package/creator3/package.json +5 -0
- package/dist/creator2/core/auto-tracking.d.ts +35 -0
- package/dist/creator2/core/auto-tracking.d.ts.map +1 -0
- package/dist/creator2/core/auto-tracking.js +337 -0
- package/dist/creator2/core/auto-tracking.js.map +1 -0
- package/dist/creator2/core/client.d.ts +74 -0
- package/dist/creator2/core/client.d.ts.map +1 -0
- package/dist/creator2/core/client.js +176 -0
- package/dist/creator2/core/client.js.map +1 -0
- package/dist/creator2/core/index.d.ts +3 -0
- package/dist/creator2/core/index.d.ts.map +1 -0
- package/dist/creator2/core/index.js +6 -0
- package/dist/creator2/core/index.js.map +1 -0
- package/dist/creator2/core/modules.d.ts +159 -0
- package/dist/creator2/core/modules.d.ts.map +1 -0
- package/dist/creator2/core/modules.js +319 -0
- package/dist/creator2/core/modules.js.map +1 -0
- package/dist/creator2/core/replay-budget.d.ts +28 -0
- package/dist/creator2/core/replay-budget.d.ts.map +1 -0
- package/dist/creator2/core/replay-budget.js +113 -0
- package/dist/creator2/core/replay-budget.js.map +1 -0
- package/dist/creator2/core/replay-diagnostics.d.ts +36 -0
- package/dist/creator2/core/replay-diagnostics.d.ts.map +1 -0
- package/dist/creator2/core/replay-diagnostics.js +40 -0
- package/dist/creator2/core/replay-diagnostics.js.map +1 -0
- package/dist/creator2/core/replay-encoding.d.ts +31 -0
- package/dist/creator2/core/replay-encoding.d.ts.map +1 -0
- package/dist/creator2/core/replay-encoding.js +63 -0
- package/dist/creator2/core/replay-encoding.js.map +1 -0
- package/dist/creator2/core/replay-pixels.d.ts +3 -0
- package/dist/creator2/core/replay-pixels.d.ts.map +1 -0
- package/dist/creator2/core/replay-pixels.js +16 -0
- package/dist/creator2/core/replay-pixels.js.map +1 -0
- package/dist/creator2/core/replay-privacy.d.ts +15 -0
- package/dist/creator2/core/replay-privacy.d.ts.map +1 -0
- package/dist/creator2/core/replay-privacy.js +36 -0
- package/dist/creator2/core/replay-privacy.js.map +1 -0
- package/dist/creator2/core/replay.d.ts +97 -0
- package/dist/creator2/core/replay.d.ts.map +1 -0
- package/dist/creator2/core/replay.js +578 -0
- package/dist/creator2/core/replay.js.map +1 -0
- package/dist/creator2/core/transport.d.ts +16 -0
- package/dist/creator2/core/transport.d.ts.map +1 -0
- package/dist/creator2/core/transport.js +33 -0
- package/dist/creator2/core/transport.js.map +1 -0
- package/dist/creator2/core/types.d.ts +260 -0
- package/dist/creator2/core/types.d.ts.map +1 -0
- package/dist/creator2/core/types.js +3 -0
- package/dist/creator2/core/types.js.map +1 -0
- package/dist/creator2/core/validation.d.ts +14 -0
- package/dist/creator2/core/validation.d.ts.map +1 -0
- package/dist/creator2/core/validation.js +81 -0
- package/dist/creator2/core/validation.js.map +1 -0
- package/dist/creator2/core/version.d.ts +9 -0
- package/dist/creator2/core/version.d.ts.map +1 -0
- package/dist/creator2/core/version.js +14 -0
- package/dist/creator2/core/version.js.map +1 -0
- package/dist/creator2/creator2/auto.d.ts +9 -0
- package/dist/creator2/creator2/auto.d.ts.map +1 -0
- package/dist/creator2/creator2/auto.js +65 -0
- package/dist/creator2/creator2/auto.js.map +1 -0
- package/dist/creator2/creator2/capture.d.ts +17 -0
- package/dist/creator2/creator2/capture.d.ts.map +1 -0
- package/dist/creator2/creator2/capture.js +175 -0
- package/dist/creator2/creator2/capture.js.map +1 -0
- package/dist/creator2/creator2/index.d.ts +12 -0
- package/dist/creator2/creator2/index.d.ts.map +1 -0
- package/dist/creator2/creator2/index.js +41 -0
- package/dist/creator2/creator2/index.js.map +1 -0
- package/dist/creator2/creator2/transport.d.ts +7 -0
- package/dist/creator2/creator2/transport.d.ts.map +1 -0
- package/dist/creator2/creator2/transport.js +34 -0
- package/dist/creator2/creator2/transport.js.map +1 -0
- package/dist/creator3/core/auto-tracking.d.ts +35 -0
- package/dist/creator3/core/auto-tracking.d.ts.map +1 -0
- package/dist/creator3/core/auto-tracking.js +247 -0
- package/dist/creator3/core/auto-tracking.js.map +1 -0
- package/dist/creator3/core/client.d.ts +74 -0
- package/dist/creator3/core/client.d.ts.map +1 -0
- package/dist/creator3/core/client.js +158 -0
- package/dist/creator3/core/client.js.map +1 -0
- package/dist/creator3/core/index.d.ts +3 -0
- package/dist/creator3/core/index.d.ts.map +1 -0
- package/dist/creator3/core/index.js +2 -0
- package/dist/creator3/core/index.js.map +1 -0
- package/dist/creator3/core/modules.d.ts +159 -0
- package/dist/creator3/core/modules.d.ts.map +1 -0
- package/dist/creator3/core/modules.js +293 -0
- package/dist/creator3/core/modules.js.map +1 -0
- package/dist/creator3/core/replay-budget.d.ts +28 -0
- package/dist/creator3/core/replay-budget.d.ts.map +1 -0
- package/dist/creator3/core/replay-budget.js +105 -0
- package/dist/creator3/core/replay-budget.js.map +1 -0
- package/dist/creator3/core/replay-diagnostics.d.ts +36 -0
- package/dist/creator3/core/replay-diagnostics.d.ts.map +1 -0
- package/dist/creator3/core/replay-diagnostics.js +36 -0
- package/dist/creator3/core/replay-diagnostics.js.map +1 -0
- package/dist/creator3/core/replay-encoding.d.ts +31 -0
- package/dist/creator3/core/replay-encoding.d.ts.map +1 -0
- package/dist/creator3/core/replay-encoding.js +62 -0
- package/dist/creator3/core/replay-encoding.js.map +1 -0
- package/dist/creator3/core/replay-pixels.d.ts +3 -0
- package/dist/creator3/core/replay-pixels.d.ts.map +1 -0
- package/dist/creator3/core/replay-pixels.js +13 -0
- package/dist/creator3/core/replay-pixels.js.map +1 -0
- package/dist/creator3/core/replay-privacy.d.ts +15 -0
- package/dist/creator3/core/replay-privacy.d.ts.map +1 -0
- package/dist/creator3/core/replay-privacy.js +33 -0
- package/dist/creator3/core/replay-privacy.js.map +1 -0
- package/dist/creator3/core/replay.d.ts +97 -0
- package/dist/creator3/core/replay.d.ts.map +1 -0
- package/dist/creator3/core/replay.js +520 -0
- package/dist/creator3/core/replay.js.map +1 -0
- package/dist/creator3/core/transport.d.ts +16 -0
- package/dist/creator3/core/transport.d.ts.map +1 -0
- package/dist/creator3/core/transport.js +27 -0
- package/dist/creator3/core/transport.js.map +1 -0
- package/dist/creator3/core/types.d.ts +260 -0
- package/dist/creator3/core/types.d.ts.map +1 -0
- package/dist/creator3/core/types.js +2 -0
- package/dist/creator3/core/types.js.map +1 -0
- package/dist/creator3/core/validation.d.ts +14 -0
- package/dist/creator3/core/validation.d.ts.map +1 -0
- package/dist/creator3/core/validation.js +75 -0
- package/dist/creator3/core/validation.js.map +1 -0
- package/dist/creator3/core/version.d.ts +9 -0
- package/dist/creator3/core/version.d.ts.map +1 -0
- package/dist/creator3/core/version.js +11 -0
- package/dist/creator3/core/version.js.map +1 -0
- package/dist/creator3/creator3/auto.d.ts +9 -0
- package/dist/creator3/creator3/auto.d.ts.map +1 -0
- package/dist/creator3/creator3/auto.js +73 -0
- package/dist/creator3/creator3/auto.js.map +1 -0
- package/dist/creator3/creator3/capture.d.ts +17 -0
- package/dist/creator3/creator3/capture.d.ts.map +1 -0
- package/dist/creator3/creator3/capture.js +119 -0
- package/dist/creator3/creator3/capture.js.map +1 -0
- package/dist/creator3/creator3/index.d.ts +12 -0
- package/dist/creator3/creator3/index.d.ts.map +1 -0
- package/dist/creator3/creator3/index.js +23 -0
- package/dist/creator3/creator3/index.js.map +1 -0
- package/dist/creator3/creator3/replay-render-cycle.d.ts +9 -0
- package/dist/creator3/creator3/replay-render-cycle.d.ts.map +1 -0
- package/dist/creator3/creator3/replay-render-cycle.js +12 -0
- package/dist/creator3/creator3/replay-render-cycle.js.map +1 -0
- package/dist/creator3/creator3/transport.d.ts +8 -0
- package/dist/creator3/creator3/transport.d.ts.map +1 -0
- package/dist/creator3/creator3/transport.js +24 -0
- package/dist/creator3/creator3/transport.js.map +1 -0
- package/dist/creator3/package.json +1 -0
- package/extensions/creator2/install-native.cjs +333 -0
- package/extensions/creator2/main.js +23 -0
- package/extensions/creator2/package.json +6 -0
- package/extensions/creator3/dist/builder.js +9 -0
- package/extensions/creator3/dist/hooks.js +70 -0
- package/extensions/creator3/dist/main.js +4 -0
- package/extensions/creator3/install-native.cjs +333 -0
- package/extensions/creator3/package.json +10 -0
- package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridge.java +532 -0
- package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridgeProvider.java +70 -0
- package/native/ios/FTCocosBridge.h +10 -0
- package/native/ios/FTCocosBridge.m +470 -0
- package/native/ios/FTCocosBridge.podspec +18 -0
- package/package.json +60 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Camera, Director, EditBox, RenderTexture, UITransform, Vec3, director, native, sys, view } from 'cc';
|
|
2
|
+
import { frameFingerprint } from '../core/replay.js';
|
|
3
|
+
import { projectPrivacyBounds } from '../core/replay-privacy.js';
|
|
4
|
+
import { waitForRenderTextureReadback } from './replay-render-cycle.js';
|
|
5
|
+
export class FTCreator3CanvasCapture {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.privacy = new Map();
|
|
8
|
+
}
|
|
9
|
+
setCamera(camera) {
|
|
10
|
+
this.camera = camera;
|
|
11
|
+
}
|
|
12
|
+
setPrivacy(node, mode) {
|
|
13
|
+
if (mode === 'unmask')
|
|
14
|
+
this.privacy.delete(node);
|
|
15
|
+
else
|
|
16
|
+
this.privacy.set(node, mode);
|
|
17
|
+
}
|
|
18
|
+
getViewportSize() {
|
|
19
|
+
var _a;
|
|
20
|
+
const visible = ((_a = view.getVisibleSizeInPixel) === null || _a === void 0 ? void 0 : _a.call(view)) || view.getVisibleSize();
|
|
21
|
+
return visible ? { width: visible.width, height: visible.height } : undefined;
|
|
22
|
+
}
|
|
23
|
+
async capture(maxImageDimension) {
|
|
24
|
+
var _a, _b;
|
|
25
|
+
const camera = this.camera || ((_a = director.getScene()) === null || _a === void 0 ? void 0 : _a.getComponentInChildren(Camera));
|
|
26
|
+
if (!camera)
|
|
27
|
+
return undefined;
|
|
28
|
+
const visible = this.getViewportSize();
|
|
29
|
+
if (!visible)
|
|
30
|
+
return undefined;
|
|
31
|
+
const scale = Math.min(1, maxImageDimension / Math.max(visible.width, visible.height));
|
|
32
|
+
const width = Math.max(1, Math.round(visible.width * scale));
|
|
33
|
+
const height = Math.max(1, Math.round(visible.height * scale));
|
|
34
|
+
const texture = new RenderTexture();
|
|
35
|
+
texture.reset({ width, height });
|
|
36
|
+
const previous = camera.targetTexture;
|
|
37
|
+
let pixels;
|
|
38
|
+
let privacyRegions = [];
|
|
39
|
+
try {
|
|
40
|
+
camera.targetTexture = texture;
|
|
41
|
+
await waitForRenderTextureReadback(completeDrawCycle);
|
|
42
|
+
pixels = texture.readPixels(0, 0, width, height);
|
|
43
|
+
// worldToScreen uses the active render target dimensions. Keep the
|
|
44
|
+
// capture target attached so projection and pixels share one viewport.
|
|
45
|
+
if (pixels)
|
|
46
|
+
privacyRegions = this.collectPrivacyRegions(camera, width, height);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
camera.targetTexture = previous;
|
|
50
|
+
texture.destroy();
|
|
51
|
+
}
|
|
52
|
+
if (!pixels)
|
|
53
|
+
return undefined;
|
|
54
|
+
// Metal returns top-down pixels on iOS. OpenGL/Vulkan-backed native
|
|
55
|
+
// targets use a bottom-left origin and need row reversal for PNG output.
|
|
56
|
+
if (sys.os !== ((_b = sys.OS) === null || _b === void 0 ? void 0 : _b.IOS))
|
|
57
|
+
flipRows(pixels, width, height);
|
|
58
|
+
return {
|
|
59
|
+
rgba: pixels,
|
|
60
|
+
width,
|
|
61
|
+
height,
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
privacyRegions,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async persist(frame, fingerprint = frameFingerprint(frame.rgba)) {
|
|
67
|
+
const path = `${native.fileUtils.getWritablePath()}cocos-sdk-replay-${fingerprint}.rgba`;
|
|
68
|
+
if (!native.fileUtils.writeDataToFile(frame.rgba, path)) {
|
|
69
|
+
throw new Error(`Unable to persist replay frame: ${path}`);
|
|
70
|
+
}
|
|
71
|
+
return { path, width: frame.width, height: frame.height, timestamp: frame.timestamp, fingerprint };
|
|
72
|
+
}
|
|
73
|
+
disposeStoredFrame(frame) {
|
|
74
|
+
if (native.fileUtils.isFileExist(frame.path))
|
|
75
|
+
native.fileUtils.removeFile(frame.path);
|
|
76
|
+
}
|
|
77
|
+
collectPrivacyRegions(camera, width, height) {
|
|
78
|
+
var _a, _b;
|
|
79
|
+
const nodes = new Map(this.privacy);
|
|
80
|
+
(_b = (_a = director.getScene()) === null || _a === void 0 ? void 0 : _a.getComponentsInChildren(EditBox)) === null || _b === void 0 ? void 0 : _b.forEach((editBox) => {
|
|
81
|
+
if (!nodes.has(editBox.node))
|
|
82
|
+
nodes.set(editBox.node, 'mask');
|
|
83
|
+
});
|
|
84
|
+
const regions = [];
|
|
85
|
+
nodes.forEach((mode, node) => {
|
|
86
|
+
var _a, _b, _c, _d;
|
|
87
|
+
const bounds = (_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.getComponent) === null || _a === void 0 ? void 0 : _a.call(node, UITransform)) === null || _b === void 0 ? void 0 : _b.getBoundingBoxToWorld) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
88
|
+
if (!bounds)
|
|
89
|
+
return;
|
|
90
|
+
const worldZ = ((_d = node.worldPosition) === null || _d === void 0 ? void 0 : _d.z) || 0;
|
|
91
|
+
const projected = projectPrivacyBounds(bounds, width, height, width, height, (x, y) => { var _a; return (_a = camera.worldToScreen) === null || _a === void 0 ? void 0 : _a.call(camera, new Vec3(x, y, worldZ)); });
|
|
92
|
+
if (!projected)
|
|
93
|
+
throw new Error('Unable to project Replay privacy bounds');
|
|
94
|
+
regions.push({ ...projected, mode: mode === 'hide' ? 'hide' : 'mask' });
|
|
95
|
+
});
|
|
96
|
+
return regions;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function completeDrawCycle() {
|
|
100
|
+
// capture() may run after the current frame's render graph has already been
|
|
101
|
+
// prepared. Waiting only for EVENT_AFTER_DRAW can then read the newly bound
|
|
102
|
+
// RenderTexture before the camera has rendered into it, producing a black
|
|
103
|
+
// FullSnapshot at a Native -> Cocos boundary. Start at the next draw boundary
|
|
104
|
+
// so the target texture is guaranteed to participate in a complete frame.
|
|
105
|
+
await new Promise((resolve) => director.once(Director.EVENT_BEFORE_DRAW, resolve));
|
|
106
|
+
await new Promise((resolve) => director.once(Director.EVENT_AFTER_DRAW, resolve));
|
|
107
|
+
}
|
|
108
|
+
function flipRows(bytes, width, height) {
|
|
109
|
+
const rowSize = width * 4;
|
|
110
|
+
const swap = new Uint8Array(rowSize);
|
|
111
|
+
for (let top = 0, bottom = height - 1; top < bottom; top += 1, bottom -= 1) {
|
|
112
|
+
const topOffset = top * rowSize;
|
|
113
|
+
const bottomOffset = bottom * rowSize;
|
|
114
|
+
swap.set(bytes.subarray(topOffset, topOffset + rowSize));
|
|
115
|
+
bytes.copyWithin(topOffset, bottomOffset, bottomOffset + rowSize);
|
|
116
|
+
bytes.set(swap, bottomOffset);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../../../../src/creator3/capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FTCocosSDK } from '../core/client.js';
|
|
2
|
+
/** Shared SDK entry point for Cocos Creator 3.x applications. */
|
|
3
|
+
export declare const truewatchSdk: FTCocosSDK;
|
|
4
|
+
/**
|
|
5
|
+
* Selects the Cocos Creator 3 camera used to capture Session Replay frames.
|
|
6
|
+
* Call this after the camera is available and before starting Replay.
|
|
7
|
+
*
|
|
8
|
+
* @param camera - Active Cocos `Camera` component.
|
|
9
|
+
*/
|
|
10
|
+
export declare function setReplayCamera(camera: unknown): void;
|
|
11
|
+
export * from '../core/index.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/creator3/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAgB/C,iEAAiE;AACjE,eAAO,MAAM,YAAY,YAA0D,CAAC;AAEpF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAErD;AAED,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FTDefaultAutoTracking } from '../core/auto-tracking.js';
|
|
2
|
+
import { FTCocosSDK } from '../core/client.js';
|
|
3
|
+
import { FTLogger, FTRUM, FTTrace } from '../core/modules.js';
|
|
4
|
+
import { FTCreator3TrackingHooks } from './auto.js';
|
|
5
|
+
import { FTCreator3CanvasCapture } from './capture.js';
|
|
6
|
+
import { FTCreator3Transport } from './transport.js';
|
|
7
|
+
const transport = new FTCreator3Transport();
|
|
8
|
+
const capture = new FTCreator3CanvasCapture();
|
|
9
|
+
const hooks = new FTCreator3TrackingHooks();
|
|
10
|
+
const autoTracking = new FTDefaultAutoTracking(new FTRUM(transport), new FTLogger(transport), new FTTrace(transport), hooks);
|
|
11
|
+
/** Shared SDK entry point for Cocos Creator 3.x applications. */
|
|
12
|
+
export const truewatchSdk = new FTCocosSDK(transport, capture, autoTracking, hooks);
|
|
13
|
+
/**
|
|
14
|
+
* Selects the Cocos Creator 3 camera used to capture Session Replay frames.
|
|
15
|
+
* Call this after the camera is available and before starting Replay.
|
|
16
|
+
*
|
|
17
|
+
* @param camera - Active Cocos `Camera` component.
|
|
18
|
+
*/
|
|
19
|
+
export function setReplayCamera(camera) {
|
|
20
|
+
capture.setCamera(camera);
|
|
21
|
+
}
|
|
22
|
+
export * from '../core/index.js';
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/creator3/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,SAAS,GAAG,IAAI,mBAAmB,EAAE,CAAC;AAC5C,MAAM,OAAO,GAAG,IAAI,uBAAuB,EAAE,CAAC;AAC9C,MAAM,KAAK,GAAG,IAAI,uBAAuB,EAAE,CAAC;AAC5C,MAAM,YAAY,GAAG,IAAI,qBAAqB,CAC5C,IAAI,KAAK,CAAC,SAAS,CAAC,EACpB,IAAI,QAAQ,CAAC,SAAS,CAAC,EACvB,IAAI,OAAO,CAAC,SAAS,CAAC,EACtB,KAAK,CACN,CAAC;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAe;IAC7C,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waits until a newly attached native RenderTexture is safe to read back.
|
|
3
|
+
*
|
|
4
|
+
* Creator 3 can submit the first draw while the target attachment is still
|
|
5
|
+
* being applied by the native renderer. Keeping the target attached for a
|
|
6
|
+
* second complete draw prevents an empty first Session Replay snapshot.
|
|
7
|
+
*/
|
|
8
|
+
export declare function waitForRenderTextureReadback(drawCycle: () => Promise<void>): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=replay-render-cycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-render-cycle.d.ts","sourceRoot":"","sources":["../../../../../src/creator3/replay-render-cycle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waits until a newly attached native RenderTexture is safe to read back.
|
|
3
|
+
*
|
|
4
|
+
* Creator 3 can submit the first draw while the target attachment is still
|
|
5
|
+
* being applied by the native renderer. Keeping the target attached for a
|
|
6
|
+
* second complete draw prevents an empty first Session Replay snapshot.
|
|
7
|
+
*/
|
|
8
|
+
export async function waitForRenderTextureReadback(drawCycle) {
|
|
9
|
+
await drawCycle();
|
|
10
|
+
await drawCycle();
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=replay-render-cycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-render-cycle.js","sourceRoot":"","sources":["../../../../../src/creator3/replay-render-cycle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,SAA8B;IAC/E,MAAM,SAAS,EAAE,CAAC;IAClB,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type FTNativeTransport } from '../core/transport.js';
|
|
2
|
+
import type { FTValue } from '../core/types.js';
|
|
3
|
+
export declare class FTCreator3Transport implements FTNativeTransport {
|
|
4
|
+
readonly platform: 'android' | 'ios' | 'unsupported';
|
|
5
|
+
constructor();
|
|
6
|
+
invoke<T = FTValue>(method: string, payload?: unknown): T | undefined;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../../src/creator3/transport.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,KAAK,GAAG,aAAa,CAAC;;IAYrD,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,GAAG,SAAS;CActE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { native, sys } from 'cc';
|
|
2
|
+
import { NATIVE } from 'cc/env';
|
|
3
|
+
import { parseTransportResponse } from '../core/transport.js';
|
|
4
|
+
export class FTCreator3Transport {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.platform = !NATIVE
|
|
7
|
+
? 'unsupported'
|
|
8
|
+
: sys.os === sys.OS.ANDROID
|
|
9
|
+
? 'android'
|
|
10
|
+
: sys.os === sys.OS.IOS
|
|
11
|
+
? 'ios'
|
|
12
|
+
: 'unsupported';
|
|
13
|
+
}
|
|
14
|
+
invoke(method, payload) {
|
|
15
|
+
if (this.platform === 'unsupported')
|
|
16
|
+
return undefined;
|
|
17
|
+
const json = payload === undefined ? '{}' : JSON.stringify(payload);
|
|
18
|
+
const raw = this.platform === 'android'
|
|
19
|
+
? native.reflection.callStaticMethod('com/ft/sdk/cocos/FTCocosBridge', 'invoke', '(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;', method, json)
|
|
20
|
+
: native.reflection.callStaticMethod('FTCocosBridge', 'invoke:payload:', method, json);
|
|
21
|
+
return parseTransportResponse(raw);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../../src/creator3/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,sBAAsB,EAA0B,MAAM,sBAAsB,CAAC;AAGtF,MAAM,OAAO,mBAAmB;IAG9B;QACE,IAAI,CAAC,QAAQ,GAAG,CAAC,MAAM;YACrB,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,OAAO;gBACzB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG;oBACrB,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,aAAa,CAAC;IACxB,CAAC;IAED,MAAM,CAAc,MAAc,EAAE,OAAiB;QACnD,IAAI,IAAI,CAAC,QAAQ,KAAK,aAAa;YAAE,OAAO,SAAS,CAAC;QACtD,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,KAAK,SAAS;YACrC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAChC,gCAAgC,EAChC,QAAQ,EACR,0DAA0D,EAC1D,MAAM,EACN,IAAI,CACL;YACH,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,eAAe,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACzF,OAAO,sBAAsB,CAAI,GAAG,CAAC,CAAC;IACxC,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execFileSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const BEGIN = '/* COCOS_SDK_BEGIN */';
|
|
8
|
+
const END = '/* COCOS_SDK_END */';
|
|
9
|
+
const POD_BEGIN = '# COCOS_SDK_BEGIN';
|
|
10
|
+
const POD_END = '# COCOS_SDK_END';
|
|
11
|
+
const XCCONFIG_BEGIN = '// COCOS_SDK_BEGIN';
|
|
12
|
+
const XCCONFIG_END = '// COCOS_SDK_END';
|
|
13
|
+
const LEGACY_BEGIN = '/* FT_COCOS_SDK_BEGIN */';
|
|
14
|
+
const LEGACY_END = '/* FT_COCOS_SDK_END */';
|
|
15
|
+
const LEGACY_POD_BEGIN = '# FT_COCOS_SDK_BEGIN';
|
|
16
|
+
const LEGACY_POD_END = '# FT_COCOS_SDK_END';
|
|
17
|
+
const LEGACY_XCCONFIG_BEGIN = '// FT_COCOS_SDK_BEGIN';
|
|
18
|
+
const LEGACY_XCCONFIG_END = '// FT_COCOS_SDK_END';
|
|
19
|
+
|
|
20
|
+
function installNative(buildRoot, extensionRoot, logger = console) {
|
|
21
|
+
if (!buildRoot) return;
|
|
22
|
+
buildRoot = path.resolve(buildRoot);
|
|
23
|
+
extensionRoot = path.resolve(extensionRoot);
|
|
24
|
+
if (!fs.existsSync(buildRoot)) return;
|
|
25
|
+
const nativeSource = path.join(extensionRoot, 'native');
|
|
26
|
+
if (!fs.existsSync(nativeSource)) {
|
|
27
|
+
logger.warn(`[cocos-sdk] Native bridge not found at ${nativeSource}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const buildNative = path.join(buildRoot, 'cocos-sdk-native');
|
|
31
|
+
copyDirectory(nativeSource, buildNative);
|
|
32
|
+
const files = findFiles(buildRoot, 7);
|
|
33
|
+
const gradlePropertiesFiles = files.filter((file) => path.basename(file) === 'gradle.properties');
|
|
34
|
+
const gradleFiles = uniqueFiles([
|
|
35
|
+
...files.filter((file) => /(?:^|\/)app\/build\.gradle$/.test(normalize(file))),
|
|
36
|
+
...gradlePropertiesFiles.flatMap(findNativeAppGradleFiles),
|
|
37
|
+
]);
|
|
38
|
+
const podfiles = files.filter((file) => path.basename(file) === 'Podfile');
|
|
39
|
+
const xcodeProjects = files.filter((file) => (
|
|
40
|
+
path.basename(file) === 'project.pbxproj' && path.extname(path.dirname(file)) === '.xcodeproj'
|
|
41
|
+
));
|
|
42
|
+
const iosApplicationProjects = xcodeProjects
|
|
43
|
+
.map((projectFile) => ({ projectFile, target: findIosApplicationTarget(projectFile) }))
|
|
44
|
+
.filter((project) => project.target);
|
|
45
|
+
if (podfiles.length === 0) {
|
|
46
|
+
iosApplicationProjects.forEach(({ projectFile, target }) => {
|
|
47
|
+
const projectDirectory = path.dirname(path.dirname(projectFile));
|
|
48
|
+
const podfile = path.join(projectDirectory, 'Podfile');
|
|
49
|
+
if (!fs.existsSync(podfile)) createPodfile(podfile, projectFile, target);
|
|
50
|
+
podfiles.push(podfile);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
iosApplicationProjects.forEach(({ projectFile, target }) => {
|
|
54
|
+
patchCocos2IosConfiguration(projectFile, target);
|
|
55
|
+
});
|
|
56
|
+
gradleFiles.forEach((file) => patchGradle(file, buildNative));
|
|
57
|
+
gradlePropertiesFiles.forEach(patchGradleProperties);
|
|
58
|
+
podfiles.forEach((file) => patchPodfile(file, buildNative));
|
|
59
|
+
logger.info(
|
|
60
|
+
`[cocos-sdk] Installed native bridge (${gradleFiles.length} Android, ${podfiles.length} iOS project files).`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function patchCocos2IosConfiguration(projectFile, target) {
|
|
65
|
+
const projectDirectory = path.dirname(path.dirname(projectFile));
|
|
66
|
+
const iosDirectory = path.join(projectDirectory, 'ios');
|
|
67
|
+
const configurations = ['debug', 'release'];
|
|
68
|
+
const configFiles = configurations.map((configuration) => ({
|
|
69
|
+
configuration,
|
|
70
|
+
file: path.join(iosDirectory, `UserConfigIOS.${configuration}.xcconfig`),
|
|
71
|
+
}));
|
|
72
|
+
if (!configFiles.some(({ file }) => fs.existsSync(file))) return;
|
|
73
|
+
|
|
74
|
+
configFiles.forEach(({ configuration, file }) => {
|
|
75
|
+
if (!fs.existsSync(file)) return;
|
|
76
|
+
replaceMarkedBlock(file, [
|
|
77
|
+
XCCONFIG_BEGIN,
|
|
78
|
+
`#include? "../Pods/Target Support Files/Pods-${target}/Pods-${target}.${configuration}.xcconfig"`,
|
|
79
|
+
`OTHER_LDFLAGS = $(inherited) ${cocos2CompatibilityLinkerFlags()}`,
|
|
80
|
+
XCCONFIG_END,
|
|
81
|
+
].join('\n'), XCCONFIG_BEGIN, XCCONFIG_END, [
|
|
82
|
+
[LEGACY_XCCONFIG_BEGIN, LEGACY_XCCONFIG_END],
|
|
83
|
+
]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const original = fs.readFileSync(projectFile, 'utf8');
|
|
87
|
+
let next = quoteWhitespaceProductNames(original).replace(
|
|
88
|
+
/(\b(?:HEADER|LIBRARY)_SEARCH_PATHS\s*=\s*)"([^"]*)";/g,
|
|
89
|
+
(line, prefix, value) => value.includes('$(inherited)')
|
|
90
|
+
? line
|
|
91
|
+
: `${prefix}"${`$(inherited) ${value}`.trim()}";`,
|
|
92
|
+
);
|
|
93
|
+
next = next.replace(
|
|
94
|
+
/(\bIPHONEOS_DEPLOYMENT_TARGET\s*=\s*)(\d+(?:\.\d+)*)(\s*;)/g,
|
|
95
|
+
(line, prefix, version, suffix) => compareVersions(version, '12.0') < 0
|
|
96
|
+
? `${prefix}12.0${suffix}`
|
|
97
|
+
: line,
|
|
98
|
+
);
|
|
99
|
+
if (next !== original) fs.writeFileSync(projectFile, next);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function quoteWhitespaceProductNames(contents) {
|
|
103
|
+
return contents.replace(
|
|
104
|
+
/^([ \t]*productName[ \t]*=)([^;\r\n]*)(;)$/gm,
|
|
105
|
+
(line, prefix, value, suffix) => {
|
|
106
|
+
const productName = value.trim();
|
|
107
|
+
if (!/[ \t]/.test(productName) || (productName.startsWith('"') && productName.endsWith('"'))) {
|
|
108
|
+
return line;
|
|
109
|
+
}
|
|
110
|
+
const spacing = value.match(/^[ \t]*/)?.[0] || ' ';
|
|
111
|
+
return `${prefix}${spacing}"${productName.replace(/"/g, '\\"')}"${suffix}`;
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function cocos2CompatibilityLinkerFlags() {
|
|
117
|
+
const flags = ['-lwebp'];
|
|
118
|
+
if (process.platform !== 'darwin') return flags.join(' ');
|
|
119
|
+
try {
|
|
120
|
+
const version = execFileSync('xcodebuild', ['-version'], { encoding: 'utf8' });
|
|
121
|
+
const major = Number((version.match(/^Xcode\s+(\d+)/m) || [])[1]);
|
|
122
|
+
if (major >= 15) flags.push('-Wl,-ld_classic');
|
|
123
|
+
} catch {
|
|
124
|
+
// Xcode is optional when only generating or testing non-iOS projects.
|
|
125
|
+
}
|
|
126
|
+
return flags.join(' ');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function patchGradleProperties(file) {
|
|
130
|
+
let contents = fs.readFileSync(file, 'utf8');
|
|
131
|
+
contents = raiseNumericProperty(contents, 'PROP_COMPILE_SDK_VERSION', 34);
|
|
132
|
+
contents = raiseNumericProperty(contents, 'PROP_MIN_SDK_VERSION', 21);
|
|
133
|
+
contents = raiseNumericProperty(contents, 'PROP_TARGET_SDK_VERSION', 34);
|
|
134
|
+
contents = raiseVersionProperty(contents, 'PROP_BUILD_TOOLS_VERSION', '34.0.0');
|
|
135
|
+
contents = enableBooleanProperty(contents, 'android.useAndroidX');
|
|
136
|
+
if (contents !== fs.readFileSync(file, 'utf8')) fs.writeFileSync(file, contents);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function findNativeAppGradleFiles(propertiesFile) {
|
|
140
|
+
const contents = fs.readFileSync(propertiesFile, 'utf8');
|
|
141
|
+
const nativeDirectoryValue = readProperty(contents, 'NATIVE_DIR');
|
|
142
|
+
if (!nativeDirectoryValue) return [];
|
|
143
|
+
const nativeDirectory = path.isAbsolute(nativeDirectoryValue)
|
|
144
|
+
? nativeDirectoryValue
|
|
145
|
+
: path.resolve(path.dirname(propertiesFile), nativeDirectoryValue);
|
|
146
|
+
const gradleFile = path.join(nativeDirectory, 'app', 'build.gradle');
|
|
147
|
+
return fs.existsSync(gradleFile) ? [gradleFile] : [];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function readProperty(contents, key) {
|
|
151
|
+
const match = contents.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*(.+?)\\s*$`, 'm'));
|
|
152
|
+
return match && match[1] ? match[1].trim() : null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function uniqueFiles(files) {
|
|
156
|
+
return [...new Set(files.map((file) => path.resolve(file)))];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function enableBooleanProperty(contents, key) {
|
|
160
|
+
const pattern = new RegExp(`^(\\s*${escapeRegExp(key)}\\s*=\\s*)(?:true|false)(\\s*)$`, 'mi');
|
|
161
|
+
if (pattern.test(contents)) {
|
|
162
|
+
return contents.replace(pattern, (line, prefix, suffix) => `${prefix}true${suffix}`);
|
|
163
|
+
}
|
|
164
|
+
return `${contents.replace(/\s*$/, '')}\n${key}=true\n`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function raiseNumericProperty(contents, key, minimum) {
|
|
168
|
+
const pattern = new RegExp(`^(\\s*${escapeRegExp(key)}\\s*=\\s*)(-?\\d+)(\\s*)$`, 'm');
|
|
169
|
+
return contents.replace(pattern, (line, prefix, value, suffix) => (
|
|
170
|
+
Number(value) < minimum ? `${prefix}${minimum}${suffix}` : line
|
|
171
|
+
));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function raiseVersionProperty(contents, key, minimum) {
|
|
175
|
+
const pattern = new RegExp(`^(\\s*${escapeRegExp(key)}\\s*=\\s*)(\\d+(?:\\.\\d+)*)(\\s*)$`, 'm');
|
|
176
|
+
return contents.replace(pattern, (line, prefix, value, suffix) => (
|
|
177
|
+
compareVersions(value, minimum) < 0 ? `${prefix}${minimum}${suffix}` : line
|
|
178
|
+
));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function compareVersions(left, right) {
|
|
182
|
+
const leftParts = left.split('.').map(Number);
|
|
183
|
+
const rightParts = right.split('.').map(Number);
|
|
184
|
+
const length = Math.max(leftParts.length, rightParts.length);
|
|
185
|
+
for (let index = 0; index < length; index += 1) {
|
|
186
|
+
const difference = (leftParts[index] || 0) - (rightParts[index] || 0);
|
|
187
|
+
if (difference !== 0) return difference;
|
|
188
|
+
}
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function patchGradle(file, nativeRoot) {
|
|
193
|
+
const javaDir = normalize(path.join(nativeRoot, 'android', 'src', 'main', 'java'));
|
|
194
|
+
replaceMarkedBlock(file, [
|
|
195
|
+
BEGIN,
|
|
196
|
+
'android {',
|
|
197
|
+
` sourceSets { main.java.srcDirs += ['${escapeGroovy(javaDir)}'] }`,
|
|
198
|
+
'}',
|
|
199
|
+
'repositories {',
|
|
200
|
+
" maven { url 'https://mvnrepo.truewatch.com/repository/maven-releases' }",
|
|
201
|
+
'}',
|
|
202
|
+
'dependencies {',
|
|
203
|
+
" implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-sdk:1.7.6-alpha02'",
|
|
204
|
+
" implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-native:1.1.3'",
|
|
205
|
+
" implementation 'com.truewatch.ft.mobile.sdk.tracker.agent:ft-session-replay:0.1.9-alpha02'",
|
|
206
|
+
" implementation 'com.google.code.gson:gson:2.10.1'",
|
|
207
|
+
" implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.22')",
|
|
208
|
+
" implementation 'androidx.appcompat:appcompat:1.1.0'",
|
|
209
|
+
" implementation 'androidx.fragment:fragment:1.8.0'",
|
|
210
|
+
'}',
|
|
211
|
+
END,
|
|
212
|
+
].join('\n'), BEGIN, END, [[LEGACY_BEGIN, LEGACY_END]]);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function patchPodfile(file, nativeRoot) {
|
|
216
|
+
const iosDir = normalize(path.join(nativeRoot, 'ios'));
|
|
217
|
+
const block = [
|
|
218
|
+
POD_BEGIN,
|
|
219
|
+
`pod 'FTCocosBridge', :path => '${escapeRuby(iosDir)}'`,
|
|
220
|
+
POD_END,
|
|
221
|
+
].join('\n');
|
|
222
|
+
const original = fs.readFileSync(file, 'utf8');
|
|
223
|
+
const currentPattern = markedPattern(POD_BEGIN, POD_END);
|
|
224
|
+
const legacyPodPattern = markedPattern(LEGACY_POD_BEGIN, LEGACY_POD_END);
|
|
225
|
+
const legacyPattern = markedPattern(LEGACY_BEGIN, LEGACY_END);
|
|
226
|
+
let next;
|
|
227
|
+
if (currentPattern.test(original)) {
|
|
228
|
+
next = replaceIndentedMarkedBlock(original, POD_BEGIN, POD_END, block);
|
|
229
|
+
} else if (legacyPodPattern.test(original)) {
|
|
230
|
+
next = replaceIndentedMarkedBlock(original, LEGACY_POD_BEGIN, LEGACY_POD_END, block);
|
|
231
|
+
} else if (legacyPattern.test(original)) {
|
|
232
|
+
next = replaceIndentedMarkedBlock(original, LEGACY_BEGIN, LEGACY_END, block);
|
|
233
|
+
} else {
|
|
234
|
+
const targetPattern = /(^[ \t]*target\s+['"][^'"]+['"]\s+do\s*$)/m;
|
|
235
|
+
next = targetPattern.test(original)
|
|
236
|
+
? original.replace(targetPattern, `$1\n ${block.replace(/\n/g, '\n ')}`)
|
|
237
|
+
: `${original.replace(/\s*$/, '')}\n\n${block}\n`;
|
|
238
|
+
}
|
|
239
|
+
if (next !== original) fs.writeFileSync(file, next);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function replaceIndentedMarkedBlock(contents, begin, end, block) {
|
|
243
|
+
const pattern = new RegExp(`(^[\\t ]*)${escapeRegExp(begin)}[\\s\\S]*?${escapeRegExp(end)}`, 'm');
|
|
244
|
+
return contents.replace(pattern, (match, indent) => `${indent}${block.replace(/\n/g, `\n${indent}`)}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function findIosApplicationTarget(projectFile) {
|
|
248
|
+
const contents = fs.readFileSync(projectFile, 'utf8');
|
|
249
|
+
const nativeTarget = /\/\* ([^*]+) \*\/ = \{\s*isa = PBXNativeTarget;([\s\S]*?)\n\s*\};/g;
|
|
250
|
+
const targets = [];
|
|
251
|
+
let match;
|
|
252
|
+
while ((match = nativeTarget.exec(contents))) {
|
|
253
|
+
if (!/productType = ["']?com\.apple\.product-type\.application["']?;/.test(match[2])) continue;
|
|
254
|
+
const nameMatch = match[2].match(/\n\s*name = ("(?:[^"\\]|\\.)*"|[^;]+);/);
|
|
255
|
+
targets.push(unquotePbxValue(nameMatch ? nameMatch[1] : match[1]));
|
|
256
|
+
}
|
|
257
|
+
return targets.find((target) => /(?:^|[-_.])mobile$/i.test(target))
|
|
258
|
+
|| targets.find((target) => /(?:^|[-_.])ios(?:$|[-_.])/i.test(target))
|
|
259
|
+
|| targets[0]
|
|
260
|
+
|| null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function unquotePbxValue(value) {
|
|
264
|
+
const trimmed = value.trim();
|
|
265
|
+
return trimmed.startsWith('"') && trimmed.endsWith('"')
|
|
266
|
+
? trimmed.slice(1, -1).replace(/\\"/g, '"')
|
|
267
|
+
: trimmed;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function createPodfile(file, projectFile, target) {
|
|
271
|
+
const projectName = path.basename(path.dirname(projectFile));
|
|
272
|
+
fs.writeFileSync(file, [
|
|
273
|
+
"platform :ios, '12.0'",
|
|
274
|
+
`project '${escapeRuby(projectName)}'`,
|
|
275
|
+
'',
|
|
276
|
+
`target '${escapeRuby(target)}' do`,
|
|
277
|
+
'end',
|
|
278
|
+
'',
|
|
279
|
+
].join('\n'));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function replaceMarkedBlock(file, block, begin = BEGIN, end = END, legacyMarkers = []) {
|
|
283
|
+
const original = fs.readFileSync(file, 'utf8');
|
|
284
|
+
const pattern = markedPattern(begin, end);
|
|
285
|
+
let next;
|
|
286
|
+
if (pattern.test(original)) {
|
|
287
|
+
next = original.replace(pattern, block);
|
|
288
|
+
} else {
|
|
289
|
+
const legacy = legacyMarkers.find(([legacyBegin, legacyEnd]) => (
|
|
290
|
+
markedPattern(legacyBegin, legacyEnd).test(original)
|
|
291
|
+
));
|
|
292
|
+
next = legacy
|
|
293
|
+
? original.replace(markedPattern(legacy[0], legacy[1]), block)
|
|
294
|
+
: `${original.replace(/\s*$/, '')}\n\n${block}\n`;
|
|
295
|
+
}
|
|
296
|
+
if (next !== original) fs.writeFileSync(file, next);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function markedPattern(begin, end) {
|
|
300
|
+
return new RegExp(`${escapeRegExp(begin)}[\\s\\S]*?${escapeRegExp(end)}`, 'm');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function copyDirectory(source, destination) {
|
|
304
|
+
fs.mkdirSync(destination, { recursive: true });
|
|
305
|
+
for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
|
|
306
|
+
const from = path.join(source, entry.name);
|
|
307
|
+
const to = path.join(destination, entry.name);
|
|
308
|
+
if (entry.isDirectory()) copyDirectory(from, to);
|
|
309
|
+
else fs.copyFileSync(from, to);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function findFiles(root, maxDepth) {
|
|
314
|
+
const result = [];
|
|
315
|
+
function visit(directory, depth) {
|
|
316
|
+
if (depth > maxDepth) return;
|
|
317
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
318
|
+
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
319
|
+
const child = path.join(directory, entry.name);
|
|
320
|
+
if (entry.isDirectory()) visit(child, depth + 1);
|
|
321
|
+
else result.push(child);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
visit(root, 0);
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function normalize(value) { return value.split(path.sep).join('/'); }
|
|
329
|
+
function escapeGroovy(value) { return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); }
|
|
330
|
+
function escapeRuby(value) { return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); }
|
|
331
|
+
function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
|
|
332
|
+
|
|
333
|
+
module.exports = { installNative };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { installNative } = require('./install-native.cjs');
|
|
5
|
+
|
|
6
|
+
function onBuildFinished(options, callback) {
|
|
7
|
+
try {
|
|
8
|
+
installNative(options && (options.dest || options.buildPath), __dirname, Editor);
|
|
9
|
+
callback();
|
|
10
|
+
} catch (error) {
|
|
11
|
+
Editor.error(`[cocos-sdk] ${error && error.stack ? error.stack : error}`);
|
|
12
|
+
callback(error);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
load() {
|
|
18
|
+
Editor.Builder.on('build-finished', onBuildFinished);
|
|
19
|
+
},
|
|
20
|
+
unload() {
|
|
21
|
+
Editor.Builder.removeListener('build-finished', onBuildFinished);
|
|
22
|
+
},
|
|
23
|
+
};
|