diff --git a/.changeset/solid-otters-live.md b/.changeset/solid-otters-live.md new file mode 100644 index 0000000000..2dfe1c5965 --- /dev/null +++ b/.changeset/solid-otters-live.md @@ -0,0 +1,9 @@ +--- +"@lynx-js/web-constants": patch +"@lynx-js/web-core": patch +"@lynx-js/web-worker-runtime": patch +--- + +feat: onNapiModulesCall function add new param: `dispatchNapiModules`, napiModulesMap val add new param: `handleDispatch`. + +Now you can use them to actively communicate to napiModules (background thread) in onNapiModulesCall (ui thread). diff --git a/packages/web-platform/web-constants/src/endpoints.ts b/packages/web-platform/web-constants/src/endpoints.ts index 042fe975aa..22b95327ed 100644 --- a/packages/web-platform/web-constants/src/endpoints.ts +++ b/packages/web-platform/web-constants/src/endpoints.ts @@ -210,3 +210,8 @@ export const dispatchLynxViewEventEndpoint = createRpcEndpoint< ], void >('dispatchLynxViewEvent', false, true); + +export const dispatchNapiModuleEndpoint = createRpcEndpoint< + [data: Cloneable], + void +>('dispatchNapiModule', false, false); diff --git a/packages/web-platform/web-constants/src/types/NapiModules.ts b/packages/web-platform/web-constants/src/types/NapiModules.ts index 201085ac86..6ec56834c8 100644 --- a/packages/web-platform/web-constants/src/types/NapiModules.ts +++ b/packages/web-platform/web-constants/src/types/NapiModules.ts @@ -2,12 +2,15 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. +import type { Cloneable } from './Cloneable.js'; + export type NapiModulesMap = Record; export type NapiModulesCall = ( name: string, data: any, moduleName: string, + dispatchNapiModules: (data: Cloneable) => void, ) => Promise<{ data: unknown; transfer?: unknown[] }> | { data: unknown; transfer?: unknown[]; diff --git a/packages/web-platform/web-core/src/apis/LynxView.ts b/packages/web-platform/web-core/src/apis/LynxView.ts index 79a6251b8d..b5c34cefdd 100644 --- a/packages/web-platform/web-core/src/apis/LynxView.ts +++ b/packages/web-platform/web-core/src/apis/LynxView.ts @@ -21,6 +21,7 @@ export type INapiModulesCall = ( data: any, moduleName: string, lynxView: LynxView, + dispatchNapiModules: (data: Cloneable) => void, ) => Promise<{ data: unknown; transfer?: Transferable[] }> | { data: unknown; transfer?: Transferable[]; @@ -194,8 +195,8 @@ export class LynxView extends HTMLElement { return this.#onNapiModulesCall; } set onNapiModulesCall(handler: INapiModulesCall) { - this.#onNapiModulesCall = (name, data, moduleName) => { - return handler(name, data, moduleName, this); + this.#onNapiModulesCall = (name, data, moduleName, dispatchNapiModules) => { + return handler(name, data, moduleName, this, dispatchNapiModules); }; } diff --git a/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerNapiModulesCallHandler.ts b/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerNapiModulesCallHandler.ts index abb9b18ee3..19e9ffdd4d 100644 --- a/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerNapiModulesCallHandler.ts +++ b/packages/web-platform/web-core/src/uiThread/crossThreadHandlers/registerNapiModulesCallHandler.ts @@ -3,7 +3,9 @@ // LICENSE file in the root directory of this source tree. import type { Rpc } from '@lynx-js/web-worker-rpc'; import { + dispatchNapiModuleEndpoint, napiModulesCallEndpoint, + type Cloneable, type NapiModulesCall, } from '@lynx-js/web-constants'; @@ -11,8 +13,20 @@ export function registerNapiModulesCallHandler( rpc: Rpc, napiModulesCall: NapiModulesCall, ) { + const dispatchNapiModules = rpc.createCall(dispatchNapiModuleEndpoint); rpc.registerHandler( napiModulesCallEndpoint, - napiModulesCall, + ( + name: string, + data: Cloneable, + moduleName: string, + ) => { + return napiModulesCall( + name, + data, + moduleName, + dispatchNapiModules, + ); + }, ); } diff --git a/packages/web-platform/web-tests/shell-project/web-core.ts b/packages/web-platform/web-tests/shell-project/web-core.ts index 9047178999..2158e01305 100644 --- a/packages/web-platform/web-tests/shell-project/web-core.ts +++ b/packages/web-platform/web-tests/shell-project/web-core.ts @@ -31,7 +31,6 @@ const color_environment = URL.createObjectURL( { type: 'text/javascript' }, ), ); - const color_methods = URL.createObjectURL( new Blob( [`export default function(NapiModules, NapiModulesCall) { @@ -45,6 +44,19 @@ const color_methods = URL.createObjectURL( { type: 'text/javascript' }, ), ); +const event_method = URL.createObjectURL( + new Blob( + [`export default function(NapiModules, NapiModulesCall, handleDispatch) { + return { + async bindEvent() { + await NapiModulesCall('bindEvent'); + handleDispatch((data) => console.log(\`bts:\${data}\`)) + }, + }; +};`], + { type: 'text/javascript' }, + ), +); async function run() { const lepusjs = '/resources/web-core.main-thread.json'; @@ -56,13 +68,26 @@ async function run() { lynxView.napiModulesMap = { 'color_environment': color_environment, 'color_methods': color_methods, + 'event_method': event_method, }; - lynxView.onNapiModulesCall = (name, data, moduleName, lynxView) => { + lynxView.onNapiModulesCall = ( + name, + data, + moduleName, + lynxView, + dispatchNapiModules, + ) => { if (name === 'getColor' && moduleName === 'color_methods') { return { data: { color: data.color, tagName: lynxView.tagName }, }; } + if (name === 'bindEvent' && moduleName === 'event_method') { + document.querySelector('lynx-view')?.addEventListener('click', () => { + dispatchNapiModules('lynx-view'); + }); + return; + } }; lynxView.addEventListener('error', () => { lynxView.setAttribute('style', 'display:none'); diff --git a/packages/web-platform/web-tests/tests/web-core.test.ts b/packages/web-platform/web-tests/tests/web-core.test.ts index 57b1b500d2..752b815cad 100644 --- a/packages/web-platform/web-tests/tests/web-core.test.ts +++ b/packages/web-platform/web-tests/tests/web-core.test.ts @@ -298,7 +298,6 @@ test.describe('web core tests', () => { expect(successCallback).toBeTruthy(); expect(successCallback2).toBeTruthy(); }); - test('api-onNapiModulesCall-class', async ({ page, browserName }) => { // firefox dose not support this. test.skip(browserName === 'firefox'); @@ -331,4 +330,34 @@ test.describe('web core tests', () => { expect(successCallback).toBeTruthy(); expect(successCallback2).toBeTruthy(); }); + test('api-onNapiModulesCall-dispatchNapiModules', async ({ page, browserName }) => { + // firefox dose not support this. + test.skip(browserName === 'firefox'); + await goto(page); + const mainWorker = await getMainThreadWorker(page); + await mainWorker.evaluate(() => { + globalThis.runtime.renderPage = () => {}; + }); + await wait(3000); + const backWorker = await getBackgroundThreadWorker(page); + let successDispatchNapiModule = false; + await page.on('console', async (message) => { + if (message.text() === 'bts:lynx-view') { + successDispatchNapiModule = true; + } + }); + await backWorker.evaluate(() => { + const nativeApp = globalThis.runtime.lynx.getNativeApp(); + const eventMethod = globalThis[`napiLoaderOnRT${nativeApp.id}`].load( + 'event_method', + ); + eventMethod.bindEvent(); + }); + await wait(1000); + await page.evaluate(() => { + document.querySelector('lynx-view')?.click(); + }); + await wait(1000); + expect(successDispatchNapiModule).toBeTruthy(); + }); }); diff --git a/packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createNapiLoader.ts b/packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createNapiLoader.ts index d615713304..4227465838 100644 --- a/packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createNapiLoader.ts +++ b/packages/web-platform/web-worker-runtime/src/backgroundThread/background-apis/createNapiLoader.ts @@ -3,6 +3,7 @@ // LICENSE file in the root directory of this source tree. import { + dispatchNapiModuleEndpoint, napiModulesCallEndpoint, type Cloneable, type NapiModulesMap, @@ -25,6 +26,10 @@ export const createNapiLoader = async ( napiModules, (name: string, data: Cloneable) => napiModulesCall(name, data, moduleName), + (func: (data: unknown) => void) => { + rpc.registerHandler(dispatchNapiModuleEndpoint, (data) => + func(data)); + }, ), ) ),