Appearance
MainPageController 与相关 API(鸿蒙)
本文详细介绍与 JSViewMainPage 配套的公开控制与扩展能力:
MainPageControllerAppLauncher/DefaultAppLauncherJSBridge- 加载状态监听回调中的
JSViewItem,以及控制用的JSViewItemController
均从 @shijiu/jsview-app 引入。页面级放置方式见 鸿蒙集成指南。
1. 关系总览
text
宿主页面
└── JSViewMainPage
├── controller: MainPageController ← 宿主持有并操控
└── appLauncher?: AppLauncher ← JS 侧拉起应用时回调宿主
MainPageController
├── loadParams / addJavascriptInterface / addListener ...
└── getTopJSViewItem() → JSViewItemController ← 运行时控制当前小程序
JSViewRunTimeListener
├── onStartLoad(item: JSViewItem)
├── onLoadSuccess(item: JSViewItem)
└── onLoadFail(item?: JSViewItem)
└── item.getParams() → 当前 MiniAppParams注意两类对象不要混用:
| 类型 | 常见来源 | 用途 |
|---|---|---|
JSViewItem | 加载状态监听回调参数 | 组件实例,主要查 getParams() |
JSViewItemController | controller.getTopJSViewItem(),以及 JSBridge.onJsViewBind | 控制向 JS 发事件、按键、evalJavaScript 等 |
2. MainPageController
MainPageController 继承 JSViewContainController,是宿主操作 JSViewMainPage 的入口。
typescript
import { MainPageController } from '@shijiu/jsview-app';
const controller = new MainPageController();须在 JSViewMainPage({ controller }) 中传入后,再调用下列能力(组件 aboutToAppear 会把内部实现挂到该实例上)。
2.1 API 一览
| 方法 | 说明 |
|---|---|
loadParams(params: string | MiniAppParams) | 解析并加载 / 切换小程序 |
addJavascriptInterface(bridge: JSBridge) | 注册公开 Bridge(按 bridgeName 去重) |
getBridges(): JSBridge[] | 已注册 Bridge 列表 |
addListener(listener: JSViewRunTimeListener) | 增加加载状态监听 |
removeListener(listener: JSViewRunTimeListener) | 移除监听 |
getTopJSViewItem(): JSViewItemController | undefined | 当前顶层小程序控制器 |
sendKeyCodeToJs(keyEvent: KeyEvent): boolean | 将按键转给 JS |
onAbilityForeground() | Ability 回到前台时调用 |
onAbilityBackground() | Ability 退到后台时调用 |
openMiniApp(params: MiniAppParams) | 内部打开(由容器挂接;一般宿主用 loadParams 即可) |
2.2 loadParams
typescript
// URL(可带 query)
controller.loadParams('https://example.com/js/main.jsv.mjs?startImg=https://cdn/.../s.png');
// MiniAppParams
import { MiniAppParams } from '@shijiu/jsview-app';
const p = new MiniAppParams();
p.url = 'https://example.com/js/main.jsv.mjs';
p.appName = 'demo.app';
p.startUpImg = 'https://example.com/startup.png';
controller.loadParams(p);要点:
- 传入
string时按默认 Parser 解析;传入MiniAppParams时会在解析结果上appendParams。 - 与上次相同的
url:跳过加载。 launchMode === 1且appName与当前相同:不重载页面,向当前实例emitEvent("onNewIntent", { url })。- 须在
JSViewMainPage已挂载(aboutToAppear之后)调用;首屏也可改用组件的defaultParams。
string 形态(含 jsvconfig / jsvappid 等)与 Want 转 MiniAppParams 详见: MiniAppParams 入口与解析。
2.3 前后台
typescript
// Ability.onForeground
controller.onAbilityForeground();
// Ability.onBackground
controller.onAbilityBackground();内部转发到当前 JSViewItemController,用于 Surface / 引擎暂停与恢复。
2.4 其它控制
typescript
// 顶层控制器(加载成功后再取更稳妥)
const itemCtrl = controller.getTopJSViewItem();
itemCtrl?.evalJavaScript('console.log("from native")');
itemCtrl?.emitEvent('customEvent', { foo: 'bar' });
itemCtrl?.sendKeyCodeToJs(keyEvent);3. AppLauncher
小程序通过内置运行时 Bridge(如 openMiniApp / openMiniAppInNewTab)请求拉起其它应用时,会回调宿主提供的 AppLauncher。
接口定义(源码):
typescript
export interface AppLauncher {
openMiniApp(params: MiniAppParams): boolean
openMiniAppInNewTab(params: MiniAppParams): Promise<boolean>
openNativeApp(want: Want): boolean
}包导出为 DefaultAppLauncher。业务侧请 继承 DefaultAppLauncher 覆盖需要的方法,再传给 JSViewMainPage:
typescript
import { DefaultAppLauncher, MiniAppParams, MainPageController } from '@shijiu/jsview-app';
import { Want, common } from '@kit.AbilityKit';
class MyAppLauncher extends DefaultAppLauncher {
constructor(controller?: MainPageController) {
super(controller);
}
// 当前页内打开(Default 实现会转调 openMiniAppInNewTab)
openMiniApp(params: MiniAppParams): boolean {
// 例如:本页复用 controller.loadParams
// this.mainPageController?.loadParams(params);
return true;
}
// 新 Ability / 新窗口打开
async openMiniAppInNewTab(params: MiniAppParams): Promise<boolean> {
const want: Want = {
bundleName: 'com.example.app',
abilityName: 'SubAbility',
parameters: {
URL: params.url ?? '',
},
};
if (params.startUpImg) {
want.parameters!['STARTIMG'] = params.startUpImg;
}
const context = getContext(this) as common.UIAbilityContext;
await context.startAbility(want);
return true;
}
openNativeApp(want: Want): boolean {
// 打开任意原生 Ability;默认实现返回 false
return false;
}
}挂到页面:
typescript
JSViewMainPage({
controller: this.controller,
defaultParams: '...',
appLauncher: new MyAppLauncher(this.controller),
})不传时,JSViewMainPage 会创建 DefaultAppLauncher:
| 方法 | 默认行为 |
|---|---|
openMiniApp | 转调 openMiniAppInNewTab,并返回 true |
openMiniAppInNewTab | 返回 false(不实际打开) |
openNativeApp | 返回 false |
因此若业务需要「JS 里开第二个小程序 / 原生页」,必须自行实现 AppLauncher,否则对应 JS API 会失败。
调用链简图:
text
JS: jJsvRuntimeBridge.openMiniApp / openMiniAppInNewTab / ...
→ RuntimeBridge
→ JSViewAppPlayer(callback)
→ AppLauncher.openMiniApp / openMiniAppInNewTab / openNativeApp4. JSBridge
宿主向当前小程序注入可被 JS 调用的原生对象。公开注册入口:
typescript
controller.addJavascriptInterface(bridge: JSBridge)4.1 接口字段
typescript
export interface JSBridge {
bridgeName: string
syncMethodList: string[]
asyncMethodList?: string[]
onJsViewBind: (jsView: JSViewItemController) => object
onJsViewUnbind?: (jsView: JSViewItemController) => void
}| 字段 | 必填 | 说明 |
|---|---|---|
bridgeName | 是 | JS 侧对象名;同名重复注册会被忽略并打日志 |
syncMethodList | 是 | 同步方法名。JS 调用会等待返回值,适合立刻能算出结果的接口 |
asyncMethodList | 否 | 异步方法名。JS 侧按异步调度,实现应为 async 并返回 Promise(或引擎可识别的异步结果),不要写成普通同步 return |
onJsViewBind | 是 | 小程序绑定前调用,返回要挂到 JS 的对象;参数为当前 JSViewItemController |
onJsViewUnbind | 否 | 卸载 / 重新加载前调用,用于释放监听、定时器等 |
方法名必须写进对应列表,且与 onJsViewBind 返回对象上的函数名一致。同步方法放 syncMethodList,异步方法放 asyncMethodList,不要混用。
4.2 注册时机
在 loadParams / defaultParams 触发加载 之前 注册,例如在页面 aboutToAppear:
typescript
aboutToAppear() {
this.controller.addJavascriptInterface(this.buildBridge());
}每次真正加载时,容器会把已注册列表 setBridges 到 JSViewItem,再对每个 bridge 调用 onJsViewBind,把返回对象注入引擎。重新 loadParams 会先 onJsViewUnbind(若有),再重新 bind。
4.3 示例
typescript
import {
JSBridge,
JSViewItemController,
MainPageController,
} from '@shijiu/jsview-app';
function buildDemoBridge(): JSBridge {
return {
bridgeName: 'demoBridge',
syncMethodList: ['ping', 'getToken'],
asyncMethodList: ['fetchData'],
onJsViewBind: (jsView: JSViewItemController): object => {
return {
// syncMethodList
ping: (): string => 'pong',
getToken: (): string => 'native-token',
// asyncMethodList:用 async / Promise,不要写成同步 return
fetchData: async (): Promise<string> => {
// 模拟异步(网络、磁盘等)
// 需要时也可 jsView.emitEvent(...) 主动推给 JS
return '{"ok":true}';
},
};
},
onJsViewUnbind: (_jsView: JSViewItemController): void => {
// 清理
},
};
}
controller.addJavascriptInterface(buildDemoBridge());JS 侧通过 bridgeName 访问(具体全局挂载名以运行时约定为准,一般为注入的 Bridge 名)。
4.4 与内置 RuntimeBridge 的区别
引擎已内置 jJsvRuntimeBridge(设备信息、开窗、关页等),宿主无需也无法用本文 JSBridge 去替换它。 JSBridge 只用于业务自定义扩展。拉起其它应用请走上一节 AppLauncher,不要在自定义 Bridge 里重复造未公开的底层接口。
5. 加载状态监听与 JSViewItem
5.1 JSViewRunTimeListener
typescript
export interface JSViewRunTimeListener {
onStartLoad: (item: JSViewItem) => void
onLoadSuccess: (item: JSViewItem) => void
onLoadFail: (item?: JSViewItem) => void
}| 回调 | 时机 | item |
|---|---|---|
onStartLoad | 开始 setSrc / start 前 | 有,当前 JSViewItem |
onLoadSuccess | 小程序加载成功(含 JS 通知 page loaded) | 有 |
onLoadFail | 加载超时等失败;解析失败时也可能无 item | 可能为 undefined |
typescript
import {
JSViewItem,
JSViewRunTimeListener,
MainPageController,
} from '@shijiu/jsview-app';
const listener: JSViewRunTimeListener = {
onStartLoad: (item: JSViewItem): void => {
const params = item.getParams();
console.info('start', params?.url, params?.appName);
},
onLoadSuccess: (item: JSViewItem): void => {
const params = item.getParams();
console.info('success', params?.url);
},
onLoadFail: (item?: JSViewItem): void => {
console.error('fail', item?.getParams()?.url);
},
};
controller.addListener(listener);
// 页面销毁:
controller.removeListener(listener);JSViewMainPage 内部也会注册自己的 listener(启动图、失败弹窗)。业务 listener 与之并存,互不替代。
5.2 回调里的 JSViewItem
监听拿到的是 组件实例 JSViewItem,公开能力主要是:
| 方法 | 说明 |
|---|---|
getParams(): MiniAppParams | undefined | 当前加载使用的参数(含 url、启动图、appName 等) |
不要把它当成页面控制器去调 loadParams / evalJavaScript。需要控制运行中的小程序时,用:
typescript
const itemCtrl = controller.getTopJSViewItem(); // JSViewItemController5.3 JSViewItemController(控制面)
由 getTopJSViewItem() 或 JSBridge.onJsViewBind(jsView) 获得。
| 方法 | 说明 |
|---|---|
getParams() | 同组件侧,取当前 MiniAppParams |
emitEvent(key, event) | 向 JS 派发事件 |
evalJavaScript(script) | 执行一段 JS |
sendKeyCodeToJs(keyEvent) | 转发按键 |
loadParams(params) | 底层直接加载(通常走 MainPageController.loadParams,带解析与去重) |
示例:加载成功后再 eval:
typescript
onLoadSuccess: (item: JSViewItem): void => {
const url = item.getParams()?.url;
controller.getTopJSViewItem()?.evalJavaScript(
`console.log("native saw load success: ${url}")`
);
},6. 推荐接入顺序
const controller = new MainPageController()controller.addJavascriptInterface(...)(如有 Bridge)controller.addListener(...)(如需状态)- 构建页面:
JSViewMainPage({ controller, appLauncher?, defaultParams? }) - 需要动态切换时:
controller.loadParams(...) - Ability 前后台:
onAbilityForeground/onAbilityBackground - 页面销毁:
removeListener
7. 相关文档
| 文档 | 内容 |
|---|---|
| 鸿蒙集成指南 | HAR 依赖、权限、JSViewMainPage 放置与参数 |
| MiniAppParams 入口与解析 | loadParams(string) 的 scheme、Want → MiniAppParams |
| 本文 | MainPageController、AppLauncher、JSBridge、JSViewItem / JSViewItemController 细节 |