应用之间及主线程与渲染线程之间的通信

本文最后更新于:2021年11月11日 中午

场景

之前,我们提供了主线程与系统通信的能力,并且基于 EventEmitter 封装了一系列的系统 API。但实际使用时,我们还发现需要支持应用的主线程与渲染线程的通信、多个应用之间的通信。

通信图

由于目前主线程与渲染线程分离的设计,所以通信流程变得相当长。

渲染线程与主线程通信.drawio.svg

应用之间的通信.drawio.svg

多个应用渲染层之间的通信.drawio.svg

通信相关类图.drawio.svg

通信的三层设计

  1. EventEmitter: 简单的双向通信
  2. MessageChannel: 支持返回值的双向通信
  3. wrap/expose: 通过接口定义契约的双向通信

参考: 基于 EventEmitter 封装更上层的 api

渲染线程与主线程通信

定义接口

export interface IMainHelloApi extends BaseDefine<"hello"> {
  hello(name: string): string;
}

在服务端注册

class MainHelloApi implements IMainHelloApi {
  namespace: "hello" = "hello";

  hello(name: string): string {
    return `hello ${name}`;
  }
}

const { iframeMessageChannel } = MainApiFactory.createAll();
expose(iframeMessageChannel, new MainHelloApi(), ["hello"]);

在客户端使用

export const { vmMessageChannel } = RendererApiFactory.createAll();
const mainHelloApi = wrap<IMainHelloApi>(vmMessageChannel, "hello");
const res = await mainHelloApi.hello("liuli");
console.log("res: ", res);

渲染线程与主线程之间通信的示例在 app-features-trainer 模块中

应用之间的通信

定义接口

export interface IVSCodeCommand extends BaseDefine<"vscode"> {
  hello(name: string): string;
}

在服务端注册

class VSCodeCommand implements IVSCodeCommand {
  namespace: "vscode" = "vscode";

  hello(name: string): string {
    return `hello ${name}`;
  }
}

const { appCommandMessageChannel } = MainApiFactory.createAll();
expose(appCommandMessageChannel, new VSCodeCommand(), ["hello"]);

在客户端使用

const { appCommandEventEmitter } = MainApiFactory.createAll();
const vscodeCommandClient = wrap<IVSCodeCommand>(
  new AppCommandClient(appCommandEventEmitter, "com.ms.vscode"),
  "vscode"
);
const res = await vscodeCommandClient.hello("liuli");
console.log("res: ", res);

应用之间通信示例在 scripts 模块中的 src/hello.tssrc/vscode.ts