@jolibox/implement 1.1.12 → 1.1.13-beta.10

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 (85) hide show
  1. package/.rush/temp/package-deps_build.json +35 -41
  2. package/.rush/temp/shrinkwrap-deps.json +1 -1
  3. package/dist/common/ads/anti-cheating.d.ts +5 -0
  4. package/dist/common/context/index.d.ts +5 -0
  5. package/dist/common/context/url-parse.d.ts +8 -1
  6. package/dist/common/rewards/__tests__/can-use-jolicoin.test.d.ts +1 -0
  7. package/dist/common/rewards/fetch-reward.d.ts +2 -0
  8. package/dist/common/rewards/index.d.ts +18 -0
  9. package/dist/common/rewards/registers/use-ads.d.ts +3 -0
  10. package/dist/common/rewards/registers/use-jolicoin.d.ts +9 -0
  11. package/dist/common/rewards/registers/utils/index.d.ts +2 -0
  12. package/dist/common/rewards/reward-helper.d.ts +14 -0
  13. package/dist/common/rewards/type.d.ts +23 -0
  14. package/dist/common/utils/index.d.ts +7 -0
  15. package/dist/index.js +3 -3
  16. package/dist/index.native.js +131 -4
  17. package/dist/native/api/index.d.ts +1 -0
  18. package/dist/native/api/keyboard.d.ts +1 -1
  19. package/dist/native/api/navigate.d.ts +1 -0
  20. package/dist/native/network/create-fetch.d.ts +1 -0
  21. package/dist/native/ui/retention.d.ts +1 -0
  22. package/implement.build.log +2 -2
  23. package/package.json +5 -3
  24. package/src/common/ads/anti-cheating.test.ts +4 -2
  25. package/src/common/ads/anti-cheating.ts +12 -4
  26. package/src/common/ads/index.ts +51 -33
  27. package/src/common/context/index.ts +22 -3
  28. package/src/common/context/url-parse.ts +24 -1
  29. package/src/common/rewards/__tests__/can-use-jolicoin.test.ts +94 -0
  30. package/src/common/rewards/fetch-reward.ts +33 -0
  31. package/src/common/rewards/index.ts +20 -0
  32. package/src/common/rewards/registers/use-ads.ts +9 -0
  33. package/src/common/rewards/registers/use-jolicoin.ts +89 -0
  34. package/src/common/rewards/registers/utils/index.ts +11 -0
  35. package/src/common/rewards/reward-helper.ts +56 -0
  36. package/src/common/rewards/type.ts +25 -0
  37. package/src/common/utils/index.ts +7 -0
  38. package/src/h5/api/ads.ts +20 -1
  39. package/src/h5/api/get-system-info.ts +1 -1
  40. package/src/h5/http/utils/__tests__/xua.test.ts +1 -1
  41. package/src/native/api/ads.ts +31 -3
  42. package/src/native/api/get-system-info.ts +2 -2
  43. package/src/native/api/index.ts +1 -0
  44. package/src/native/api/keyboard.ts +1 -1
  45. package/src/native/api/lifecycle.ts +16 -4
  46. package/src/native/api/login.ts +1 -1
  47. package/src/native/api/navigate.ts +61 -0
  48. package/src/native/api/request.ts +19 -10
  49. package/src/native/api/storage.ts +1 -1
  50. package/src/native/bootstrap/index.ts +111 -27
  51. package/src/native/network/create-fetch.ts +7 -2
  52. package/src/native/network/utils.ts +13 -6
  53. package/src/native/report/errors/index.ts +1 -1
  54. package/src/native/report/index.ts +1 -1
  55. package/src/native/report/task-tracker.ts +1 -1
  56. package/src/native/ui/retention.ts +153 -0
  57. package/dist/native/bootstrap/bridge.d.ts +0 -4
  58. package/dist/native/js-bridge/const.d.ts +0 -5
  59. package/dist/native/js-bridge/index.d.ts +0 -2
  60. package/dist/native/js-bridge/invoke.d.ts +0 -21
  61. package/dist/native/js-bridge/js-bridge.d.ts +0 -6
  62. package/dist/native/js-bridge/report.d.ts +0 -63
  63. package/dist/native/js-bridge/subscribe.d.ts +0 -8
  64. package/dist/native/js-bridge/types.d.ts +0 -14
  65. package/dist/native/js-bridge/utils.d.ts +0 -17
  66. package/dist/native/js-core/index.d.ts +0 -3
  67. package/dist/native/js-core/jolibox-js-core.d.ts +0 -45
  68. package/dist/native/js-core/message-port.d.ts +0 -12
  69. package/dist/native/js-core/utils.d.ts +0 -7
  70. package/src/native/bootstrap/bridge.ts +0 -59
  71. package/src/native/js-bridge/const.ts +0 -11
  72. package/src/native/js-bridge/index.ts +0 -2
  73. package/src/native/js-bridge/invoke.ts +0 -208
  74. package/src/native/js-bridge/js-bridge.ts +0 -23
  75. package/src/native/js-bridge/report.ts +0 -311
  76. package/src/native/js-bridge/subscribe.ts +0 -50
  77. package/src/native/js-bridge/types.ts +0 -26
  78. package/src/native/js-bridge/utils.ts +0 -116
  79. package/src/native/js-core/index.ts +0 -4
  80. package/src/native/js-core/jolibox-js-core.ts +0 -188
  81. package/src/native/js-core/message-port.ts +0 -52
  82. package/src/native/js-core/utils.ts +0 -9
  83. package/src/native/types/global.d.ts +0 -26
  84. package/src/native/types/native-method-map.d.ts +0 -300
  85. package/src/native/types/native-method.d.ts +0 -30
@@ -0,0 +1,153 @@
1
+ import { context } from '@/common/context';
2
+ import { invokeNative, subscribe } from '@jolibox/native-bridge';
3
+ import { Deferred } from '@jolibox/common';
4
+ import { createRecommendModal, IGame, IRecommendationButton, RecommendModalOnCloseParams } from '@jolibox/ui';
5
+ import { innerFetch as fetch } from '../network';
6
+
7
+ let exitRecommendationsCache: {
8
+ code: string;
9
+ data: {
10
+ gameListInfo: {
11
+ games: IGame[];
12
+ };
13
+ title: string;
14
+ buttons: IRecommendationButton[];
15
+ };
16
+ } | null = null;
17
+
18
+ /**
19
+ * Fetches exit recommendations data from the API
20
+ */
21
+ async function fetchExitRecommendations() {
22
+ if (exitRecommendationsCache) {
23
+ return exitRecommendationsCache;
24
+ }
25
+ const host = context.testMode ? `https://stg-game.jolibox.com` : `https://game.jolibox.com`;
26
+ const url = `${host}/api/user-retention/exit-recommendations?objectId=${context.mpId}&from=GAME_DETAIL`;
27
+ const {
28
+ response: { data }
29
+ } = await fetch<{
30
+ code: string;
31
+ data: {
32
+ gameListInfo: {
33
+ games: IGame[];
34
+ };
35
+ title: string;
36
+ buttons: IRecommendationButton[];
37
+ };
38
+ }>(url);
39
+
40
+ exitRecommendationsCache = data;
41
+ return data;
42
+ }
43
+
44
+ //prefetch
45
+ fetchExitRecommendations();
46
+
47
+ const openGameSchema = (game: IGame) => {
48
+ const { data } = invokeNative('envSync');
49
+
50
+ // Parse the original URL to preserve its structure
51
+
52
+ const url = new URL(data.schema);
53
+ const originalPath = url.pathname;
54
+ const originalSearch = new URLSearchParams(url.search);
55
+
56
+ // Set or replace gameId and joliSource parameters
57
+ originalSearch.set('gameId', context.mpId);
58
+ originalSearch.set(
59
+ 'joliSource',
60
+ context.encodeJoliSourceQuery({
61
+ __mpType: 'game',
62
+ __orientation: game.orientation ?? 'VERTICAL'
63
+ })
64
+ );
65
+
66
+ const host = `https://${game.gameId}.content.jolibox.com/`;
67
+ // Construct the final schema URL
68
+ const schema = `${host}${originalPath}?${originalSearch.toString()}`;
69
+
70
+ invokeNative('openSchemaSync', {
71
+ schema
72
+ });
73
+ };
74
+
75
+ export async function openRetentionSchema() {
76
+ // const { data } = invokeNative('envSync');
77
+ // const { orientation, webviewId } = data;
78
+ // let joliPayload: Record<string, unknown> = {
79
+ // __mpType: 'miniApp',
80
+ // __transparent: true,
81
+ // // set entryPath
82
+ // __orientation: orientation ?? 'VERTICAL', // 默认竖屏
83
+ // __showStatusBar: false,
84
+ // __shouldInterupt: false,
85
+ // __showCapsuleButton: false
86
+ // };
87
+ // if (webviewId) {
88
+ // joliPayload = {
89
+ // ...joliPayload,
90
+ // __from: webviewId
91
+ // };
92
+ // }
93
+
94
+ // const joliSource = context.encodeJoliSourceQuery(joliPayload);
95
+
96
+ // const host = context.testMode
97
+ // ? `https://G32115508989327465281365749294.app.jolibox.com`
98
+ // : `https://G32115508989327465281365749294.app.jolibox.com`;
99
+ // const retentionSchema = `${host}/recommended-guide/${context.mpId}?appId=${context.mpId}&joliSource=${joliSource}&navigationStyle=present`;
100
+
101
+ const quitResultDeffer = new Deferred<boolean>();
102
+ // 小程序不走挽留逻辑
103
+ if (context.mpType !== 'game') {
104
+ quitResultDeffer.resolve(false);
105
+ return quitResultDeffer.promise;
106
+ }
107
+
108
+ const data = await fetchExitRecommendations();
109
+
110
+ if (data.code !== 'SUCCESS') {
111
+ quitResultDeffer.resolve(false);
112
+ return quitResultDeffer.promise;
113
+ }
114
+
115
+ const { gameListInfo, title, buttons } = data.data;
116
+
117
+ const modal = createRecommendModal({
118
+ games: gameListInfo.games,
119
+ title,
120
+ buttons,
121
+ onClose: (params: RecommendModalOnCloseParams) => {
122
+ switch (params.type) {
123
+ case 'quit':
124
+ quitResultDeffer.resolve(false);
125
+ break;
126
+ case 'dismiss':
127
+ quitResultDeffer.resolve(true);
128
+ modal.hide();
129
+ break;
130
+ case 'navigate':
131
+ // TODO: 跳转游戏
132
+ if (params.data?.game) {
133
+ openGameSchema(params.data.game);
134
+ } else {
135
+ quitResultDeffer.resolve(true);
136
+ }
137
+ modal.hide();
138
+ break;
139
+ default:
140
+ // 关闭弹框,留在当前游戏
141
+ quitResultDeffer.resolve(true);
142
+ break;
143
+ }
144
+ }
145
+ });
146
+ // // 异步
147
+ // setTimeout(() => {
148
+ // invokeNative('openSchemaSync', {
149
+ // schema: retentionSchema
150
+ // });
151
+ // }, 0);
152
+ return quitResultDeffer.promise;
153
+ }
@@ -1,4 +0,0 @@
1
- import { On } from '../js-bridge';
2
- export declare const applyNative: jsb.service.ApplyNative, invokeNative: jsb.service.InvokeNative, onNative: jsb.service.OnNative, offNative: jsb.service.OnNative, subscribeHandler: import("../js-bridge").SubscribeHandler;
3
- export declare const onNativeWithError: On;
4
- export { RuntimeLoader } from '../js-core';
@@ -1,5 +0,0 @@
1
- export declare const CUSTOM_EVENT_PREFIX = "custom_event_";
2
- export declare const HOST_EVENT_PREFIX = "host_event_";
3
- export declare const BUFFER_METHODS: string[];
4
- export declare const BACKGROUND_FORBIDDEN_METHODS: string[];
5
- export declare const SYNC_METHODS: string[];
@@ -1,2 +0,0 @@
1
- export { createBridge } from './js-bridge';
2
- export * from './types';
@@ -1,21 +0,0 @@
1
- import { InvokeHandler, On } from './types';
2
- interface Invokes {
3
- /** 暴露给宿主, 触发调用的方法 */
4
- invokeHandler: InvokeHandler;
5
- /** 基础库内部, 调用宿主的方法, 返回 native 返回对象 */
6
- invokeNative: (method: string, args?: Record<string, unknown>, webviewId?: number) => any;
7
- /** 基础库内部, 调用宿主的方法, 会根据 errMsg throwError */
8
- applyNative: (method: string, args?: Record<string, unknown>, webviewId?: number) => any;
9
- }
10
- export declare function createInvoke(jsCore: jsb.JSCore, onNative: On): Invokes;
11
- export declare function ifThrowError(method: string, res: {
12
- errMsg?: string;
13
- errNo?: number;
14
- errorType?: string;
15
- errorCode?: number;
16
- }): {} | undefined;
17
- export declare class ApplyNativeError extends Error {
18
- readonly errNo?: number | undefined;
19
- constructor(message: string, errNo?: number | undefined);
20
- }
21
- export {};
@@ -1,6 +0,0 @@
1
- import { JSBridge } from './types';
2
- /**
3
- * build js-bridge
4
- * @param jsCore jsCore function inject by native
5
- */
6
- export declare function createBridge(jsCore: jsb.JSCore): JSBridge;
@@ -1,63 +0,0 @@
1
- import { On } from './types';
2
- type MetricReporter = (points: unknown) => unknown;
3
- interface MetricCache {
4
- [props: string]: MetricCache | (number | string)[];
5
- }
6
- interface PVMetricCache {
7
- [props: string]: PVMetricCache | number;
8
- }
9
- type MetricCacheType = MetricCache | PVMetricCache;
10
- type MetricType = 'pv' | 'default';
11
- type Prettier<T> = T extends Record<string, unknown> ? {
12
- [K in keyof T]: T[K];
13
- } : T;
14
- type MetricPoint<Tag extends string, Name extends string> = Prettier<{
15
- [k in Tag]: string;
16
- } & {
17
- [K in Name]: number | string;
18
- }>;
19
- interface PVPoint {
20
- [props: string]: string | JSON;
21
- }
22
- interface MetricConfig<Tag extends string, Name extends string, Type extends string> {
23
- reporter: MetricReporter;
24
- interval?: number;
25
- eventName: string;
26
- tagNameOrder: Tag[];
27
- metricName: Name;
28
- type?: Type;
29
- }
30
- export declare class MetricsMonitor<Tag extends string, Name extends string, Type extends string> {
31
- reporter: MetricReporter;
32
- interval: number;
33
- lastReportTime: number;
34
- cache: MetricCacheType;
35
- eventName: string;
36
- tagNameOrder: Tag[];
37
- metricName: Name;
38
- type: MetricType;
39
- constructor(config: MetricConfig<Tag, Name, Type>);
40
- report(point: Type extends 'pv' ? PVPoint : MetricPoint<Tag, Name>): void;
41
- flush(): void;
42
- private tryReport;
43
- private addPoint;
44
- private addPVPoint;
45
- private processPoints;
46
- private clearPoints;
47
- }
48
- interface InvokeMetrics {
49
- errMsg: string;
50
- errNo?: number;
51
- __timing?: {
52
- receiveJSInvoke: number;
53
- invokeCallback: number;
54
- };
55
- method: string;
56
- startTime: number;
57
- args?: Record<string, unknown>;
58
- isForeground: string;
59
- [prop: string]: unknown;
60
- }
61
- export type reportInvokeFn = (invokeMetrics: InvokeMetrics) => void;
62
- export declare function createReportInvokeMetrics(jsCore: jsb.JSCore, onNative: On): reportInvokeFn;
63
- export {};
@@ -1,8 +0,0 @@
1
- import { Off, On } from './types';
2
- import { AnyFunction } from '@jolibox/types';
3
- export interface Subscribes {
4
- onNative: On;
5
- offNative: Off;
6
- subscribeHandler: AnyFunction;
7
- }
8
- export declare function createSubscribe(jsCore: jsb.JSCore): Subscribes;
@@ -1,14 +0,0 @@
1
- export type Listener = (...args: any[]) => any;
2
- export type On = <T extends string>(event: T, handler: Listener) => void;
3
- export type Off = <T extends string>(event: T, handler: Listener) => void;
4
- export type InvokeHandler = (callbackId: string | number, data: string | Record<string, unknown>) => void;
5
- export type SubscribeHandler = (event: string, data: string | Record<string, unknown>, webviewId?: number) => void;
6
- export type AnyFunction = (...args: any[]) => any;
7
- export interface JSBridge {
8
- invokeHandler: InvokeHandler;
9
- subscribeHandler: SubscribeHandler;
10
- invokeNative: jsb.service.InvokeNative;
11
- applyNative: jsb.service.ApplyNative;
12
- onNative: jsb.service.OnNative;
13
- offNative: jsb.service.OffNative;
14
- }
@@ -1,17 +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
- interface NativeBufferElement {
11
- key: string;
12
- value?: ArrayBuffer;
13
- base64?: string;
14
- }
15
- export declare function unpack(data: unknown): DataObj;
16
- export declare function pack(_data?: {}, useArrayBuffer?: boolean): Record<string, unknown>;
17
- export {};
@@ -1,3 +0,0 @@
1
- export { joliboxJSCore, RuntimeLoader } from './jolibox-js-core';
2
- export { messagePort, initMessagePort } from './message-port';
3
- export { normalizeParams } from './utils';
@@ -1,45 +0,0 @@
1
- export declare let joliboxJSCore: jsb.JSCore | undefined;
2
- declare global {
3
- interface Window {
4
- JoliAndroidSDKBridge?: {
5
- invoke: (invokeString: string) => void;
6
- onDocumentReady: (paramsstr: string) => void;
7
- doExit: (uuidString: string) => void;
8
- };
9
- webkit?: {
10
- messageHandlers: {
11
- invoke: {
12
- postMessage: (params: {
13
- event: string;
14
- callbackId: number;
15
- paramsString: string;
16
- }) => void;
17
- };
18
- publish: {
19
- postMessage: (params: {
20
- event: string;
21
- webviewIds: string;
22
- paramsString: string;
23
- }) => void;
24
- };
25
- onDocumentReady: {
26
- postMessage: (params: {
27
- path: string;
28
- }) => void;
29
- };
30
- doExit: {
31
- postMessage: (params: {
32
- uuid: string;
33
- shouldInterrupt: boolean;
34
- }) => void;
35
- };
36
- };
37
- };
38
- }
39
- }
40
- export declare const RuntimeLoader: {
41
- trigger(): void;
42
- exit(): boolean;
43
- onReady(fn: () => void): void;
44
- doExit(fn: () => boolean): void;
45
- };
@@ -1,12 +0,0 @@
1
- interface MessageEvent {
2
- data: string;
3
- ports: MessagePort[];
4
- }
5
- interface MessagePort {
6
- onmessage: (msg: MessageEvent) => void;
7
- postMessage: (msg: string) => void;
8
- publish: (event: string, data: Record<string, unknown>) => void;
9
- }
10
- export declare let messagePort: MessagePort | undefined;
11
- export declare function initMessagePort(): void;
12
- export {};
@@ -1,7 +0,0 @@
1
- export declare function normalizeParams(params: Record<string, unknown>, type: string): {
2
- params: Record<string, unknown>;
3
- __extra: {
4
- startTime: number;
5
- type: string;
6
- };
7
- };
@@ -1,59 +0,0 @@
1
- import { createBridge, On } from '../js-bridge';
2
-
3
- import { joliboxJSCore, initMessagePort } from '../js-core';
4
-
5
- import { formatErrorCode } from '../../common/report/errors';
6
- import { AnyFunction } from '@jolibox/types';
7
- import { InternalJSCoreNotFoundError } from '@jolibox/common';
8
-
9
- declare const globalThis: {
10
- joliboxJSBridge?: {
11
- callHandler: AnyFunction;
12
- invokeHandler: AnyFunction;
13
- subscribeHandler: AnyFunction;
14
- };
15
- };
16
-
17
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
18
- const jsCore = joliboxJSCore!;
19
-
20
- if (!jsCore) {
21
- throw new InternalJSCoreNotFoundError('No joliboxJScore is found, native bridge not found.');
22
- }
23
-
24
- initMessagePort();
25
-
26
- const core: jsb.JSCore = {
27
- ...jsCore
28
- // publish(event: string, params: Record<string, unknown>, webviewIds: number[]) {
29
- // if (messagePort) {
30
- // messagePort.publish(event, params);
31
- // return;
32
- // }
33
- // jsCore.publish(event, params, webviewIds);
34
- // }
35
- };
36
-
37
- const bridge = createBridge(core);
38
-
39
- const { invokeHandler } = bridge;
40
-
41
- export const { applyNative, invokeNative, onNative, offNative, subscribeHandler } = bridge;
42
-
43
- export const onNativeWithError: On = (event, handler) => {
44
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
- onNative(event as keyof jsb.service.NativeEventMap, (...rest: any) => {
46
- if (rest[0]?.errorCode) {
47
- rest[0].errorCode = formatErrorCode(event, rest[0].errorCode);
48
- }
49
- handler(...rest);
50
- });
51
- };
52
-
53
- globalThis.joliboxJSBridge = {
54
- callHandler: invokeHandler,
55
- invokeHandler,
56
- subscribeHandler
57
- };
58
-
59
- export { RuntimeLoader } from '../js-core';
@@ -1,11 +0,0 @@
1
- export const CUSTOM_EVENT_PREFIX = 'custom_event_';
2
-
3
- export const HOST_EVENT_PREFIX = 'host_event_';
4
-
5
- //TODO: add buffer supported method
6
- export const BUFFER_METHODS: string[] = [];
7
-
8
- // TODO: add method cannot invoke background
9
- export const BACKGROUND_FORBIDDEN_METHODS: string[] = [];
10
-
11
- export const SYNC_METHODS: string[] = ['env', 'createRequestTask', 'login'];
@@ -1,2 +0,0 @@
1
- export { createBridge } from './js-bridge';
2
- export * from './types';
@@ -1,208 +0,0 @@
1
- import { pack, unpack } from './utils';
2
- import { Deferred, isObject, isPromiseLike, InternalApplyNativeError, logger } from '@jolibox/common';
3
- import { formatErrorCode } from '../../common/report/errors';
4
- import { BACKGROUND_FORBIDDEN_METHODS, BUFFER_METHODS, SYNC_METHODS } from './const';
5
- import { createReportInvokeMetrics } from './report';
6
- import { InvokeHandler, On } from './types';
7
-
8
- import { AnyFunction } from '@jolibox/types';
9
-
10
- interface Invokes {
11
- /** 暴露给宿主, 触发调用的方法 */
12
- invokeHandler: InvokeHandler;
13
- /** 基础库内部, 调用宿主的方法, 返回 native 返回对象 */
14
- invokeNative: (method: string, args?: Record<string, unknown>, webviewId?: number) => any;
15
- /** 基础库内部, 调用宿主的方法, 会根据 errMsg throwError */
16
- applyNative: (method: string, args?: Record<string, unknown>, webviewId?: number) => any;
17
- }
18
-
19
- type Response = {
20
- errMsg: string;
21
- errNo?: number;
22
- __timing?: {
23
- receiveJSInvoke: number;
24
- invokeCallback: number;
25
- };
26
- } & Record<string, unknown>;
27
-
28
- // 后台期间积压的请求
29
- const asyncInvokes: {
30
- method: string;
31
- args?: Record<string, unknown>;
32
- resolve: AnyFunction;
33
- }[] = [];
34
-
35
- //TODO: support arrayBuffer
36
- const NOT_SUPPORT_ARRAY_BUFFER = false;
37
-
38
- export function createInvoke(jsCore: jsb.JSCore, onNative: On): Invokes {
39
- let resolveId = 0;
40
- let IS_FOREGROUND = true;
41
-
42
- const resolveMap = new Map<number, AnyFunction>();
43
- const reportInvokeMetrics = createReportInvokeMetrics(jsCore, onNative);
44
-
45
- onNative('onJoliboxEnterBackground', () => {
46
- IS_FOREGROUND = false;
47
- });
48
-
49
- onNative('onJoliboxEnterForeground', () => {
50
- IS_FOREGROUND = true;
51
- // 从后台进入前台后, 处理之前在后台挤压的任务
52
- asyncInvokes.forEach(async ({ method, args, resolve }) => {
53
- const res = await invokeNative(method, args);
54
- resolve(res);
55
- });
56
- // 清空积压
57
- asyncInvokes.length = 0;
58
- });
59
-
60
- const invokeHandler: InvokeHandler = (resolveId, data): void => {
61
- /**
62
- * Android resolveId 是 `string`
63
- * iOS 上待确认, IDE 上是 `number`
64
- */
65
- const resolve = resolveMap.get(Number(resolveId));
66
- if (!resolve) return;
67
- const response = unpack(data);
68
- resolve(response);
69
- resolveMap.delete(Number(resolveId));
70
- };
71
-
72
- const invokeNative = (
73
- method: string,
74
- args?: Record<string, unknown>
75
- ): Record<string, unknown> | Promise<Record<string, unknown>> => {
76
- const startTime = Date.now();
77
- const isForeground = `${IS_FOREGROUND}`;
78
-
79
- resolveId += 1;
80
-
81
- const deferred = new Deferred<Response>();
82
- resolveMap.set(resolveId, deferred.resolve);
83
-
84
- if (!IS_FOREGROUND && BACKGROUND_FORBIDDEN_METHODS.includes(method)) {
85
- // `FOREGROUND_FORBIDDEN_EVENTS` all async API
86
- return new Promise<Record<string, unknown>>((resolve) => {
87
- asyncInvokes.push({ method, args, resolve });
88
- });
89
- }
90
-
91
- const basicReportParam = {
92
- method,
93
- startTime,
94
- args,
95
- isForeground
96
- };
97
-
98
- const invokeReportParam = {
99
- ...basicReportParam,
100
- invokeType: 'js-bridge'
101
- } as const;
102
-
103
- const useArrayBuffer = !NOT_SUPPORT_ARRAY_BUFFER && BUFFER_METHODS.includes(method);
104
-
105
- const payload = pack(args, useArrayBuffer);
106
- const params = useArrayBuffer ? payload : JSON.stringify(payload);
107
-
108
- /** 调用结果 */
109
- let response;
110
-
111
- if (method.endsWith('Sync') || SYNC_METHODS.includes(method)) {
112
- response = jsCore.call?.(method, payload, resolveId);
113
- } else {
114
- if (typeof params === 'string') {
115
- response = jsCore.invoke(method, params, resolveId);
116
- } else {
117
- response = jsCore.call?.(method, params, resolveId);
118
- }
119
- }
120
-
121
- /**
122
- * 如果 invoke 返回了结果,则为同步调用
123
- * - iOS 返回 `undefined`
124
- * - Android 返回空字符串 `""`
125
- */
126
- if (response) {
127
- try {
128
- if (typeof response === 'string') {
129
- response = JSON.parse(response);
130
- }
131
- response = unpack(response);
132
- } catch (error) {
133
- logger.error(error);
134
- }
135
- resolveMap.delete(resolveId);
136
- if (response.errorCode) {
137
- response.errorCode = formatErrorCode(method, response.errorCode);
138
- }
139
- reportInvokeMetrics({ ...invokeReportParam, ...response });
140
-
141
- return response;
142
- }
143
-
144
- if (method.endsWith('Sync')) {
145
- resolveMap.delete(resolveId);
146
- }
147
-
148
- return deferred.promise.then((response) => {
149
- if (response.errorCode) {
150
- response.errorCode = formatErrorCode(method, response.errorCode as number | undefined);
151
- }
152
- reportInvokeMetrics({ ...invokeReportParam, ...response });
153
- return response;
154
- });
155
- };
156
-
157
- const applyNative = (method: string, arg?: Record<string, unknown>) => {
158
- const res = invokeNative(method, arg);
159
- if (isPromiseLike(res)) {
160
- return res.then((r) =>
161
- ifThrowError(
162
- method,
163
- r as {
164
- errMsg?: string;
165
- errNo?: number;
166
- errorType?: string;
167
- errorCode?: number;
168
- }
169
- )
170
- );
171
- }
172
- return ifThrowError(method, res);
173
- };
174
-
175
- return {
176
- invokeNative,
177
- applyNative,
178
- invokeHandler
179
- };
180
- }
181
-
182
- export function ifThrowError(
183
- method: string,
184
- res: {
185
- errMsg?: string;
186
- errNo?: number;
187
- errorType?: string;
188
- errorCode?: number;
189
- }
190
- ) {
191
- if (!isObject(res)) {
192
- logger.warn(`[Jolibox SDK]${method} no response value`);
193
- return;
194
- }
195
- const { errMsg, errNo, errorType, errorCode, ...data } = res;
196
-
197
- if (errMsg && errMsg !== `${method}:ok`) {
198
- throw new InternalApplyNativeError(errMsg, errNo, errorType, errorCode);
199
- }
200
-
201
- return data;
202
- }
203
-
204
- export class ApplyNativeError extends Error {
205
- constructor(message: string, readonly errNo?: number) {
206
- super(message);
207
- }
208
- }
@@ -1,23 +0,0 @@
1
- import { createInvoke } from './invoke';
2
- import { createSubscribe } from './subscribe';
3
- import { JSBridge } from './types';
4
-
5
- /**
6
- * build js-bridge
7
- * @param jsCore jsCore function inject by native
8
- */
9
- export function createBridge(jsCore: jsb.JSCore): JSBridge {
10
- const { subscribeHandler, onNative, offNative } = createSubscribe(jsCore);
11
-
12
- const { invokeNative, invokeHandler, applyNative } = createInvoke(jsCore, onNative);
13
-
14
- return {
15
- // 宿主调用
16
- invokeHandler,
17
- subscribeHandler,
18
- applyNative,
19
- invokeNative,
20
- onNative,
21
- offNative
22
- };
23
- }