@jolibox/implement 1.1.12 → 1.1.13-beta.2
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/.rush/temp/package-deps_build.json +20 -34
- package/.rush/temp/shrinkwrap-deps.json +1 -1
- package/dist/common/context/index.d.ts +5 -0
- package/dist/common/context/url-parse.d.ts +8 -1
- package/dist/index.js +3 -3
- package/dist/index.native.js +110 -4
- package/dist/native/api/index.d.ts +1 -0
- package/dist/native/api/keyboard.d.ts +1 -1
- package/dist/native/api/navigate.d.ts +1 -0
- package/dist/native/network/create-fetch.d.ts +1 -0
- package/dist/native/ui/retention.d.ts +1 -0
- package/implement.build.log +2 -2
- package/package.json +5 -3
- package/src/common/context/index.ts +22 -3
- package/src/common/context/url-parse.ts +24 -1
- package/src/native/api/ads.ts +1 -1
- package/src/native/api/get-system-info.ts +1 -1
- package/src/native/api/index.ts +1 -0
- package/src/native/api/keyboard.ts +1 -1
- package/src/native/api/lifecycle.ts +16 -4
- package/src/native/api/login.ts +1 -1
- package/src/native/api/navigate.ts +61 -0
- package/src/native/api/request.ts +19 -10
- package/src/native/api/storage.ts +1 -1
- package/src/native/bootstrap/index.ts +111 -27
- package/src/native/network/create-fetch.ts +2 -1
- package/src/native/network/utils.ts +13 -6
- package/src/native/report/errors/index.ts +1 -1
- package/src/native/report/index.ts +1 -1
- package/src/native/report/task-tracker.ts +1 -1
- package/src/native/ui/retention.ts +152 -0
- package/dist/native/bootstrap/bridge.d.ts +0 -4
- package/dist/native/js-bridge/const.d.ts +0 -5
- package/dist/native/js-bridge/index.d.ts +0 -2
- package/dist/native/js-bridge/invoke.d.ts +0 -21
- package/dist/native/js-bridge/js-bridge.d.ts +0 -6
- package/dist/native/js-bridge/report.d.ts +0 -63
- package/dist/native/js-bridge/subscribe.d.ts +0 -8
- package/dist/native/js-bridge/types.d.ts +0 -14
- package/dist/native/js-bridge/utils.d.ts +0 -17
- package/dist/native/js-core/index.d.ts +0 -3
- package/dist/native/js-core/jolibox-js-core.d.ts +0 -45
- package/dist/native/js-core/message-port.d.ts +0 -12
- package/dist/native/js-core/utils.d.ts +0 -7
- package/src/native/bootstrap/bridge.ts +0 -59
- package/src/native/js-bridge/const.ts +0 -11
- package/src/native/js-bridge/index.ts +0 -2
- package/src/native/js-bridge/invoke.ts +0 -208
- package/src/native/js-bridge/js-bridge.ts +0 -23
- package/src/native/js-bridge/report.ts +0 -311
- package/src/native/js-bridge/subscribe.ts +0 -50
- package/src/native/js-bridge/types.ts +0 -26
- package/src/native/js-bridge/utils.ts +0 -116
- package/src/native/js-core/index.ts +0 -4
- package/src/native/js-core/jolibox-js-core.ts +0 -188
- package/src/native/js-core/message-port.ts +0 -52
- package/src/native/js-core/utils.ts +0 -9
- package/src/native/types/global.d.ts +0 -26
- package/src/native/types/native-method-map.d.ts +0 -300
- package/src/native/types/native-method.d.ts +0 -30
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { On } from './types';
|
|
2
|
-
import { isObject, isString, InternalMetricReportError } from '@jolibox/common';
|
|
3
|
-
|
|
4
|
-
type MetricReporter = (points: unknown) => unknown;
|
|
5
|
-
interface MetricCache {
|
|
6
|
-
[props: string]: MetricCache | (number | string)[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface PVMetricCache {
|
|
10
|
-
[props: string]: PVMetricCache | number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type MetricCacheType = MetricCache | PVMetricCache;
|
|
14
|
-
type MetricType = 'pv' | 'default';
|
|
15
|
-
type Prettier<T> = T extends Record<string, unknown> ? { [K in keyof T]: T[K] } : T;
|
|
16
|
-
type MetricPoint<Tag extends string, Name extends string> = Prettier<
|
|
17
|
-
{
|
|
18
|
-
[k in Tag]: string;
|
|
19
|
-
} & {
|
|
20
|
-
[K in Name]: number | string;
|
|
21
|
-
}
|
|
22
|
-
>;
|
|
23
|
-
|
|
24
|
-
interface PVPoint {
|
|
25
|
-
[props: string]: string | JSON;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const getType = (type: unknown): MetricType => {
|
|
29
|
-
if (type === 'pv') return type;
|
|
30
|
-
return 'default';
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
interface MetricConfig<Tag extends string, Name extends string, Type extends string> {
|
|
34
|
-
reporter: MetricReporter;
|
|
35
|
-
interval?: number;
|
|
36
|
-
eventName: string;
|
|
37
|
-
tagNameOrder: Tag[];
|
|
38
|
-
metricName: Name;
|
|
39
|
-
type?: Type;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export class MetricsMonitor<Tag extends string, Name extends string, Type extends string> {
|
|
43
|
-
reporter: MetricReporter;
|
|
44
|
-
interval = 30;
|
|
45
|
-
lastReportTime = 0;
|
|
46
|
-
cache: MetricCacheType = {};
|
|
47
|
-
eventName: string;
|
|
48
|
-
tagNameOrder: Tag[];
|
|
49
|
-
metricName: Name;
|
|
50
|
-
type: MetricType;
|
|
51
|
-
|
|
52
|
-
constructor(config: MetricConfig<Tag, Name, Type>) {
|
|
53
|
-
const { reporter, interval = 30, eventName, tagNameOrder, metricName, type } = config;
|
|
54
|
-
this.reporter = reporter;
|
|
55
|
-
this.interval = interval;
|
|
56
|
-
this.eventName = eventName;
|
|
57
|
-
this.tagNameOrder = tagNameOrder;
|
|
58
|
-
this.metricName = metricName;
|
|
59
|
-
this.type = getType(type);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
report(point: Type extends 'pv' ? PVPoint : MetricPoint<Tag, Name>) {
|
|
63
|
-
if (this.type === 'pv') {
|
|
64
|
-
this.addPVPoint(point);
|
|
65
|
-
} else {
|
|
66
|
-
this.addPoint(point as MetricPoint<Tag, Name>);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
this.tryReport(false);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
flush() {
|
|
73
|
-
this.tryReport(true);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private tryReport(force: boolean) {
|
|
77
|
-
if (!Object.keys(this.cache).length) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (force) {
|
|
82
|
-
this.reporter(this.processPoints(this.cache));
|
|
83
|
-
this.clearPoints();
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
this.lastReportTime = this.lastReportTime || Date.now();
|
|
88
|
-
|
|
89
|
-
if (Date.now() - this.lastReportTime >= this.interval * 1000) {
|
|
90
|
-
this.reporter(this.processPoints(this.cache));
|
|
91
|
-
this.clearPoints();
|
|
92
|
-
this.lastReportTime = Date.now();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private addPoint(point: MetricPoint<Tag, Name>) {
|
|
97
|
-
const safeSetVal = (
|
|
98
|
-
target: MetricCache,
|
|
99
|
-
props: Tag[],
|
|
100
|
-
metricName: Name,
|
|
101
|
-
point: MetricPoint<Tag, Name>
|
|
102
|
-
) => {
|
|
103
|
-
const currentProp = props.shift();
|
|
104
|
-
if (currentProp) {
|
|
105
|
-
const currentVal = point[currentProp];
|
|
106
|
-
if (!target[currentVal]) target[currentVal] = {};
|
|
107
|
-
|
|
108
|
-
safeSetVal(target[currentVal] as MetricCache, props, metricName, point);
|
|
109
|
-
} else {
|
|
110
|
-
if (!target[metricName]) target[metricName] = [];
|
|
111
|
-
(target[metricName] as unknown[]).push(point[metricName]);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
safeSetVal(this.cache as MetricCache, [...this.tagNameOrder], this.metricName, point);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private addPVPoint(point: PVPoint) {
|
|
119
|
-
const safeSetVal = (
|
|
120
|
-
target: Record<string, unknown>,
|
|
121
|
-
props: Tag[],
|
|
122
|
-
metricName: Name,
|
|
123
|
-
relation: unknown
|
|
124
|
-
) => {
|
|
125
|
-
const currentProp = props.shift();
|
|
126
|
-
|
|
127
|
-
if (!currentProp && isObject(relation)) {
|
|
128
|
-
throw new InternalMetricReportError(
|
|
129
|
-
`report value failed to match tagNameOrder, ${JSON.stringify(originParams)}`
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (currentProp) {
|
|
134
|
-
const keys: string[] = [];
|
|
135
|
-
if (isObject(relation)) {
|
|
136
|
-
keys.push(...Object.keys(relation));
|
|
137
|
-
} else if (isString(relation)) {
|
|
138
|
-
if (props.length > 0) {
|
|
139
|
-
throw new InternalMetricReportError(
|
|
140
|
-
`report value failed to match tagNameOrder, ${JSON.stringify(originParams)}`
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
keys.push(relation);
|
|
145
|
-
} else {
|
|
146
|
-
throw new InternalMetricReportError(
|
|
147
|
-
`expected metric value to be a string, but got a(n) ${typeof relation}, ${JSON.stringify(
|
|
148
|
-
originParams
|
|
149
|
-
)}`
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
keys.forEach((key) => {
|
|
154
|
-
if (!target[key]) target[key] = {};
|
|
155
|
-
const value = isObject(relation) ? relation[key] : relation;
|
|
156
|
-
safeSetVal(target[key] as MetricCache, [...props], metricName, value);
|
|
157
|
-
});
|
|
158
|
-
} else {
|
|
159
|
-
if (!target[metricName]) {
|
|
160
|
-
target[metricName] = 1;
|
|
161
|
-
} else {
|
|
162
|
-
(target[metricName] as number)++;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const originParams = {
|
|
168
|
-
point,
|
|
169
|
-
metricName: this.metricName,
|
|
170
|
-
tagNameOrder: this.tagNameOrder
|
|
171
|
-
};
|
|
172
|
-
safeSetVal(this.cache, [...this.tagNameOrder], this.metricName, point);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private processPoints(points: MetricCacheType) {
|
|
176
|
-
return {
|
|
177
|
-
eventName: this.eventName,
|
|
178
|
-
tagNameOrder: this.tagNameOrder,
|
|
179
|
-
metricName: this.metricName,
|
|
180
|
-
metricAggregateType: this.type === 'pv' ? 'itoa' : 'arr',
|
|
181
|
-
data: points
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
private clearPoints() {
|
|
186
|
-
this.cache = {};
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
interface InvokeMetrics {
|
|
191
|
-
errMsg: string;
|
|
192
|
-
errNo?: number;
|
|
193
|
-
__timing?: {
|
|
194
|
-
receiveJSInvoke: number;
|
|
195
|
-
invokeCallback: number;
|
|
196
|
-
};
|
|
197
|
-
method: string;
|
|
198
|
-
startTime: number;
|
|
199
|
-
args?: Record<string, unknown>;
|
|
200
|
-
isForeground: string;
|
|
201
|
-
|
|
202
|
-
[prop: string]: unknown;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
let monitorHasInitialized = false;
|
|
206
|
-
let invokeMonitor: MetricsMonitor<
|
|
207
|
-
'status' | 'method' | 'errNo' | 'errMsg' | 'isForeground',
|
|
208
|
-
'duration',
|
|
209
|
-
'default'
|
|
210
|
-
>;
|
|
211
|
-
let invokeJSToNativeMonitor: MetricsMonitor<'status' | 'method' | 'isForeground', 'duration', 'default'>;
|
|
212
|
-
let invokeNativeToJSMonitor: MetricsMonitor<'status' | 'method' | 'isForeground', 'duration', 'default'>;
|
|
213
|
-
|
|
214
|
-
export type reportInvokeFn = (invokeMetrics: InvokeMetrics) => void;
|
|
215
|
-
|
|
216
|
-
export function createReportInvokeMetrics(jsCore: jsb.JSCore, onNative: On): reportInvokeFn {
|
|
217
|
-
if (!monitorHasInitialized) {
|
|
218
|
-
/** invoke 埋点 */
|
|
219
|
-
invokeMonitor = new MetricsMonitor({
|
|
220
|
-
eventName: 'jolibox_invoke',
|
|
221
|
-
tagNameOrder: ['status', 'method', 'errNo', 'errMsg', 'isForeground'],
|
|
222
|
-
metricName: 'duration',
|
|
223
|
-
reporter(data) {
|
|
224
|
-
jsCore.invoke('track', JSON.stringify({ event: 'reportMetrics', data }), -1);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
/** invoke js -> native */
|
|
229
|
-
invokeJSToNativeMonitor = new MetricsMonitor({
|
|
230
|
-
eventName: 'jolibox_invoke_js2native',
|
|
231
|
-
tagNameOrder: ['status', 'method', 'isForeground'],
|
|
232
|
-
metricName: 'duration',
|
|
233
|
-
reporter(data) {
|
|
234
|
-
jsCore.invoke('track', JSON.stringify({ event: 'reportMetrics', data }), -1);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
/** invoke native -> js */
|
|
239
|
-
invokeNativeToJSMonitor = new MetricsMonitor({
|
|
240
|
-
eventName: 'jolibox_invoke_native2js',
|
|
241
|
-
tagNameOrder: ['status', 'method', 'isForeground'],
|
|
242
|
-
metricName: 'duration',
|
|
243
|
-
reporter(data) {
|
|
244
|
-
jsCore.invoke('track', JSON.stringify({ event: 'reportMetrics', data }), -1);
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
onNative('onJoliboxEnterBackground', () => {
|
|
249
|
-
invokeMonitor.flush();
|
|
250
|
-
invokeJSToNativeMonitor.flush();
|
|
251
|
-
invokeNativeToJSMonitor.flush();
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
monitorHasInitialized = true;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function report(invokeMetrics: InvokeMetrics) {
|
|
258
|
-
const {
|
|
259
|
-
method,
|
|
260
|
-
args,
|
|
261
|
-
startTime,
|
|
262
|
-
isForeground,
|
|
263
|
-
errMsg = `${method}:fail no errMsg`,
|
|
264
|
-
errNo = 0,
|
|
265
|
-
__timing = {
|
|
266
|
-
receiveJSInvoke: 0,
|
|
267
|
-
invokeCallback: 0
|
|
268
|
-
}
|
|
269
|
-
} = invokeMetrics;
|
|
270
|
-
const { receiveJSInvoke, invokeCallback } = __timing;
|
|
271
|
-
const status = errMsg.match(/\S:(\S+)\s?/)?.[1] ?? 'fail';
|
|
272
|
-
|
|
273
|
-
// report sync
|
|
274
|
-
invokeMonitor.report({
|
|
275
|
-
status,
|
|
276
|
-
method: normalizeMethod(method, args),
|
|
277
|
-
errNo: `${errNo}`,
|
|
278
|
-
errMsg,
|
|
279
|
-
isForeground,
|
|
280
|
-
duration: Date.now() - startTime
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
if (startTime && receiveJSInvoke && invokeCallback) {
|
|
284
|
-
invokeJSToNativeMonitor.report({
|
|
285
|
-
status,
|
|
286
|
-
method,
|
|
287
|
-
isForeground,
|
|
288
|
-
duration: Number((receiveJSInvoke - startTime).toFixed(3))
|
|
289
|
-
});
|
|
290
|
-
invokeNativeToJSMonitor.report({
|
|
291
|
-
status,
|
|
292
|
-
method,
|
|
293
|
-
isForeground,
|
|
294
|
-
duration: Number((Date.now() - invokeCallback).toFixed(3))
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function normalizeMethod(method: string, args?: Record<string, unknown>) {
|
|
300
|
-
// Reserve an interface;
|
|
301
|
-
// an API might be provided later to directly expose client-side methods to users.
|
|
302
|
-
if (method === 'callHostMethod' || method === 'callHostMethodSync') {
|
|
303
|
-
if (args?.method) {
|
|
304
|
-
return `${method}-${args.method}`;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return method;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return report;
|
|
311
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from '@jolibox/common';
|
|
2
|
-
import { DataObj, unpack } from './utils';
|
|
3
|
-
import { Off, On } from './types';
|
|
4
|
-
import { AnyFunction } from '@jolibox/types';
|
|
5
|
-
import { MetricsMonitor } from './report';
|
|
6
|
-
|
|
7
|
-
export interface Subscribes {
|
|
8
|
-
onNative: On;
|
|
9
|
-
offNative: Off;
|
|
10
|
-
subscribeHandler: AnyFunction;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function createSubscribe(jsCore: jsb.JSCore): Subscribes {
|
|
14
|
-
const nativeEmitter = new EventEmitter();
|
|
15
|
-
const publishMonitor = new MetricsMonitor({
|
|
16
|
-
eventName: 'jolibox_publish',
|
|
17
|
-
tagNameOrder: ['type', 'event'],
|
|
18
|
-
metricName: 'duration',
|
|
19
|
-
reporter(data) {
|
|
20
|
-
jsCore.invoke('track', JSON.stringify({ event: 'reportMetrics', data }), -1);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
nativeEmitter.on('onJoliboxEnterBackground', () => {
|
|
25
|
-
publishMonitor.flush();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
onNative: nativeEmitter.on.bind(nativeEmitter),
|
|
30
|
-
offNative: nativeEmitter.off.bind(nativeEmitter),
|
|
31
|
-
subscribeHandler(event, data, webviewId) {
|
|
32
|
-
// ios: jsc 端基于系统方法,前端接受到的 data 总是 string 类型, webview 基于 evaluateJavascript,前端接受到的 data 总是 object 类型
|
|
33
|
-
// android: 传入为 string 则接收到 string,传入为可序列化成功的 object,则接收到 object
|
|
34
|
-
const unpackedData = unpack(data);
|
|
35
|
-
let originalParams: undefined | DataObj;
|
|
36
|
-
if (unpackedData.__extra) {
|
|
37
|
-
originalParams = unpackedData.params;
|
|
38
|
-
const { type, startTime } = unpackedData.__extra;
|
|
39
|
-
publishMonitor.report({
|
|
40
|
-
type,
|
|
41
|
-
event,
|
|
42
|
-
duration: Date.now() - startTime // ms
|
|
43
|
-
});
|
|
44
|
-
} else {
|
|
45
|
-
originalParams = unpackedData;
|
|
46
|
-
}
|
|
47
|
-
nativeEmitter.emit(event, originalParams, webviewId);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2
|
-
export type Listener = (...args: any[]) => any;
|
|
3
|
-
|
|
4
|
-
export type On = <T extends string>(event: T, handler: Listener) => void;
|
|
5
|
-
|
|
6
|
-
export type Off = <T extends string>(event: T, handler: Listener) => void;
|
|
7
|
-
|
|
8
|
-
export type InvokeHandler = (callbackId: string | number, data: string | Record<string, unknown>) => void;
|
|
9
|
-
|
|
10
|
-
export type SubscribeHandler = (
|
|
11
|
-
event: string,
|
|
12
|
-
data: string | Record<string, unknown>,
|
|
13
|
-
webviewId?: number
|
|
14
|
-
) => void;
|
|
15
|
-
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
-
export type AnyFunction = (...args: any[]) => any;
|
|
18
|
-
|
|
19
|
-
export interface JSBridge {
|
|
20
|
-
invokeHandler: InvokeHandler;
|
|
21
|
-
subscribeHandler: SubscribeHandler;
|
|
22
|
-
invokeNative: jsb.service.InvokeNative;
|
|
23
|
-
applyNative: jsb.service.ApplyNative;
|
|
24
|
-
onNative: jsb.service.OnNative;
|
|
25
|
-
offNative: jsb.service.OffNative;
|
|
26
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
export interface DataObj {
|
|
2
|
-
params?: Record<string, unknown>;
|
|
3
|
-
errorCode?: number;
|
|
4
|
-
__extra?: {
|
|
5
|
-
startTime: number;
|
|
6
|
-
type: string;
|
|
7
|
-
};
|
|
8
|
-
__nativeBuffers__?: NativeBufferElement[] | undefined;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface NativeBufferElement {
|
|
12
|
-
key: string;
|
|
13
|
-
value?: ArrayBuffer;
|
|
14
|
-
base64?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function isNativeBuffers(
|
|
18
|
-
x: unknown & { __nativeBuffers__?: NativeBufferElement[] | undefined }
|
|
19
|
-
): x is { __nativeBuffers__?: NativeBufferElement[]; [k: string]: unknown } {
|
|
20
|
-
return Boolean(x?.__nativeBuffers__);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* decodeFromUi8Base64
|
|
25
|
-
*/
|
|
26
|
-
const decodeFromUi8Base64 = (string: string): ArrayBuffer => {
|
|
27
|
-
const base64String = atob(string);
|
|
28
|
-
const len = base64String.length;
|
|
29
|
-
const ui8aReader = new Uint8Array(len);
|
|
30
|
-
for (let i = 0; i < len; i++) {
|
|
31
|
-
ui8aReader[i] = base64String.charCodeAt(i);
|
|
32
|
-
}
|
|
33
|
-
return ui8aReader.buffer;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export function unpack(data: unknown): DataObj {
|
|
37
|
-
if (typeof data === 'string') {
|
|
38
|
-
try {
|
|
39
|
-
data = JSON.parse(data);
|
|
40
|
-
} catch {
|
|
41
|
-
return {};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (typeof data !== 'object' || data === null) {
|
|
45
|
-
return {};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!isNativeBuffers(data)) return data as DataObj;
|
|
49
|
-
|
|
50
|
-
const nativeBuffers = data.__nativeBuffers__;
|
|
51
|
-
delete data.__nativeBuffers__;
|
|
52
|
-
|
|
53
|
-
if (nativeBuffers) {
|
|
54
|
-
for (let i = 0; i < nativeBuffers.length; i++) {
|
|
55
|
-
const item = nativeBuffers[i];
|
|
56
|
-
if (item) {
|
|
57
|
-
let tmp;
|
|
58
|
-
if (item.value) {
|
|
59
|
-
// Arraybuffer
|
|
60
|
-
tmp = item.value;
|
|
61
|
-
} else if (item.base64) {
|
|
62
|
-
tmp = decodeFromUi8Base64(item.base64);
|
|
63
|
-
}
|
|
64
|
-
if (typeof tmp !== 'undefined' && tmp instanceof ArrayBuffer) {
|
|
65
|
-
data[item.key] = tmp;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return data;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const encodeToUi8Base64 = (arrayBuffer: ArrayBuffer): string => {
|
|
75
|
-
let string = '';
|
|
76
|
-
const ui8aReader = new Uint8Array(arrayBuffer);
|
|
77
|
-
const len = ui8aReader.byteLength;
|
|
78
|
-
for (let i = 0; i < len; i++) {
|
|
79
|
-
string += String.fromCharCode(ui8aReader[i]);
|
|
80
|
-
}
|
|
81
|
-
return btoa(string);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export function pack(_data = {}, useArrayBuffer = false): Record<string, unknown> {
|
|
85
|
-
const data = _data as Record<string, unknown>;
|
|
86
|
-
type ArrayBufferType =
|
|
87
|
-
| {
|
|
88
|
-
value: ArrayBuffer;
|
|
89
|
-
key: string;
|
|
90
|
-
base64?: undefined;
|
|
91
|
-
}
|
|
92
|
-
| {
|
|
93
|
-
base64: string;
|
|
94
|
-
key: string;
|
|
95
|
-
value?: undefined;
|
|
96
|
-
};
|
|
97
|
-
const needTransAttrs: ArrayBufferType[] = [];
|
|
98
|
-
for (const [key, item] of Object.entries(data)) {
|
|
99
|
-
if (item !== undefined && item instanceof ArrayBuffer && item.byteLength !== undefined) {
|
|
100
|
-
const obj: ArrayBufferType = useArrayBuffer
|
|
101
|
-
? { value: item, key }
|
|
102
|
-
: {
|
|
103
|
-
base64: encodeToUi8Base64(item),
|
|
104
|
-
key
|
|
105
|
-
};
|
|
106
|
-
needTransAttrs.push(obj);
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
108
|
-
delete data[key];
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (needTransAttrs.length > 0) {
|
|
113
|
-
data.__nativeBuffers__ = needTransAttrs;
|
|
114
|
-
}
|
|
115
|
-
return data;
|
|
116
|
-
}
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { InternalInvokeNativeError } from '@jolibox/common';
|
|
2
|
-
// import { normalizeParams } from './utils';
|
|
3
|
-
import { Env } from '@jolibox/types';
|
|
4
|
-
import { reportError } from '@/common/report/errors/report';
|
|
5
|
-
|
|
6
|
-
declare const globalThis: {
|
|
7
|
-
joliboxJSCore?: JoliboxJSCore;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
interface JoliboxJSCore {
|
|
11
|
-
// publish: (event: string, params: string, webviewIds: string) => void;
|
|
12
|
-
invoke: (method: string, params: string, callbackId: number) => string | void;
|
|
13
|
-
/** 安卓: webview 没有 call, service 有 */
|
|
14
|
-
call?: (method: string, params: Record<string, unknown>, callbackId: number) => string | void;
|
|
15
|
-
onDocumentReady: (path: string) => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export let joliboxJSCore: jsb.JSCore | undefined;
|
|
19
|
-
|
|
20
|
-
declare global {
|
|
21
|
-
interface Window {
|
|
22
|
-
JoliAndroidSDKBridge?: {
|
|
23
|
-
invoke: (invokeString: string) => void;
|
|
24
|
-
onDocumentReady: (paramsstr: string) => void;
|
|
25
|
-
doExit: (uuidString: string) => void;
|
|
26
|
-
};
|
|
27
|
-
webkit?: {
|
|
28
|
-
messageHandlers: {
|
|
29
|
-
invoke: {
|
|
30
|
-
postMessage: (params: { event: string; callbackId: number; paramsString: string }) => void;
|
|
31
|
-
};
|
|
32
|
-
publish: {
|
|
33
|
-
postMessage: (params: { event: string; webviewIds: string; paramsString: string }) => void;
|
|
34
|
-
};
|
|
35
|
-
onDocumentReady: {
|
|
36
|
-
postMessage: (params: { path: string }) => void;
|
|
37
|
-
};
|
|
38
|
-
doExit: {
|
|
39
|
-
postMessage: (params: { uuid: string; shouldInterrupt: boolean }) => void;
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const RuntimeLoader = {
|
|
47
|
-
trigger() {
|
|
48
|
-
// noop
|
|
49
|
-
},
|
|
50
|
-
exit(): boolean {
|
|
51
|
-
//noop
|
|
52
|
-
return false; // 默认不打断退出
|
|
53
|
-
},
|
|
54
|
-
onReady(fn: () => void) {
|
|
55
|
-
RuntimeLoader.trigger = fn;
|
|
56
|
-
},
|
|
57
|
-
doExit(fn: () => boolean) {
|
|
58
|
-
RuntimeLoader.exit = fn;
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const env = (): Env | undefined => {
|
|
63
|
-
const res = window.prompt(
|
|
64
|
-
'invoke',
|
|
65
|
-
JSON.stringify({
|
|
66
|
-
event: 'envSync',
|
|
67
|
-
paramsString: JSON.stringify({})
|
|
68
|
-
})
|
|
69
|
-
);
|
|
70
|
-
if (!res) {
|
|
71
|
-
reportError(new InternalInvokeNativeError(`native env failed`));
|
|
72
|
-
} else {
|
|
73
|
-
const { data } = JSON.parse(res);
|
|
74
|
-
return data ?? undefined;
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
if (window.webkit) {
|
|
79
|
-
const _joliboxJSCore = window.webkit.messageHandlers;
|
|
80
|
-
const onDocumentReady = (path = '') => {
|
|
81
|
-
RuntimeLoader.trigger();
|
|
82
|
-
_joliboxJSCore.onDocumentReady.postMessage({ path });
|
|
83
|
-
};
|
|
84
|
-
const doExit = (uuid: string) => {
|
|
85
|
-
const shouldInterrupt = RuntimeLoader.exit();
|
|
86
|
-
_joliboxJSCore.doExit.postMessage({ uuid, shouldInterrupt });
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
joliboxJSCore = {
|
|
90
|
-
onDocumentReady,
|
|
91
|
-
doExit,
|
|
92
|
-
invoke(method, params, callbackId) {
|
|
93
|
-
_joliboxJSCore.invoke.postMessage({
|
|
94
|
-
event: method,
|
|
95
|
-
paramsString: params,
|
|
96
|
-
callbackId
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
// publish(event, params, webviewIds) {
|
|
100
|
-
// const data = normalizeParams(params as Record<string, unknown>, 'joliboxJSCore');
|
|
101
|
-
// _joliboxJSCore.publish.postMessage({
|
|
102
|
-
// event,
|
|
103
|
-
// paramsString: JSON.stringify(data),
|
|
104
|
-
// webviewIds: JSON.stringify(webviewIds)
|
|
105
|
-
// });
|
|
106
|
-
// },
|
|
107
|
-
call(method: string, params: Record<string, unknown>, callbackId) {
|
|
108
|
-
const res = window.prompt(
|
|
109
|
-
'invoke',
|
|
110
|
-
JSON.stringify({
|
|
111
|
-
event: method,
|
|
112
|
-
paramsString: JSON.stringify(params),
|
|
113
|
-
callbackId
|
|
114
|
-
})
|
|
115
|
-
);
|
|
116
|
-
if (res) {
|
|
117
|
-
return JSON.parse(res);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
// do not expose invoke/ publish to user
|
|
123
|
-
const devCore = { onDocumentReady, env };
|
|
124
|
-
|
|
125
|
-
//eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
126
|
-
// @ts-ignore
|
|
127
|
-
globalThis.joliboxJSCore = {
|
|
128
|
-
...devCore
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Android
|
|
133
|
-
if (window.JoliAndroidSDKBridge) {
|
|
134
|
-
const _joliboxJSCore = window.JoliAndroidSDKBridge;
|
|
135
|
-
const onDocumentReady = (path = '') => {
|
|
136
|
-
RuntimeLoader.trigger();
|
|
137
|
-
_joliboxJSCore.onDocumentReady(JSON.stringify({ path }));
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const doExit = (uuid: string) => {
|
|
141
|
-
const shouldInterrupt = RuntimeLoader.exit();
|
|
142
|
-
_joliboxJSCore.doExit(JSON.stringify({ uuid, shouldInterrupt }));
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
joliboxJSCore = {
|
|
146
|
-
onDocumentReady,
|
|
147
|
-
invoke(method, params, callbackId) {
|
|
148
|
-
_joliboxJSCore.invoke(
|
|
149
|
-
JSON.stringify({
|
|
150
|
-
event: method,
|
|
151
|
-
paramsString: params,
|
|
152
|
-
callbackId
|
|
153
|
-
})
|
|
154
|
-
);
|
|
155
|
-
},
|
|
156
|
-
doExit,
|
|
157
|
-
// publish(event, params, webviewIds) {
|
|
158
|
-
// const data = normalizeParams(params as Record<string, unknown>, 'joliboxJSCore');
|
|
159
|
-
// _joliboxJSCore.publish({
|
|
160
|
-
// event,
|
|
161
|
-
// paramsString: JSON.stringify(data),
|
|
162
|
-
// webviewIds: JSON.stringify(webviewIds)
|
|
163
|
-
// });
|
|
164
|
-
// },
|
|
165
|
-
call(method: string, params: Record<string, unknown>, callbackId) {
|
|
166
|
-
const res = window.prompt(
|
|
167
|
-
'invoke',
|
|
168
|
-
JSON.stringify({
|
|
169
|
-
event: method,
|
|
170
|
-
paramsString: JSON.stringify(params),
|
|
171
|
-
callbackId
|
|
172
|
-
})
|
|
173
|
-
);
|
|
174
|
-
if (res) {
|
|
175
|
-
return JSON.parse(res);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
// do not expose invoke/ publish to user
|
|
181
|
-
const devCore = { onDocumentReady, env };
|
|
182
|
-
|
|
183
|
-
//eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
184
|
-
// @ts-ignore
|
|
185
|
-
globalThis.joliboxJSCore = {
|
|
186
|
-
...devCore
|
|
187
|
-
};
|
|
188
|
-
}
|