main.js,以融合场景插件和经典插件的方式进行插件开发。
使用该方式进行开发的场景包括但不限于:
- 需要访问 MN 的原生对象
- 注册生命周期方法
- 调整面板属性
- 持久化存储(如插件设置)
- 绕开 Web 安全限制
main.js 运行在插件的 JavaScriptCore 环境里,通过 JSB 调用 MN 暴露的原生对象。
文件结构
最小结构如下:project
mnaddon.json
index.html
main.js
mnaddon.json 仍然用 panel 指定 HTML 面板入口:
mnaddon.json
main.js 需要放在插件根目录。MN 加载插件时会立即执行该文件,并调用其中的 JSB.newAddon(mainPath)。该函数需要返回一个继承自 JSExtension 的类。
插件入口
加入main.js 后,插件入口将变为 main.js。下面是一种经典写法:
main.js
在
JSB.defineClass定义的实例成员中,使用self而非this来引用 JSB 定义的类(如JSExtension)的实例。关于 JSB 定义的类的可用成员详见使用 MN 原生对象手动控制面板
加入main.js 后,点击插件按钮将不再自动打开面板,面板的创建、加载、显示和清理都要由插件自己完成。
例如下面定义了一个打开面板并设置最大高度的函数。
main.js
studyController实例,而studyController实例又需要通过插件实例获取,因此该函数需要为 context 参数传入在 JSB 定义的类的实例成员方法中的 self 。
双向通信
从面板调用 main.js
面板调用mn.call(name, payload) 时会触发 main.js的 panel.onMessage(name, payload)。
onMessage 的返回值会进行序列化作为 mn.call() 的结果返回页面。
下面是具体例子:
main.js
index.html
mn.call的 Promise 返回值在包括但不限于下列情形时会进入失败分支:
- 未注册
onMessage - 插件被禁用或暂停
- 回调抛出异常
- 返回值无法序列化
从 main.js 调用面板
main.js 可以通过调用 panel.post(event, data) 向已经加载的面板发送事件。面板通过 window.addEventListener("mn:<event>", handler) 接收事件,并从 event.detail 读取数据。
下面是具体例子:
main.js
index.html
使用 MN 原生对象
main.js 可访问 JSB 暴露的原生对象,例如 Application、Database、NSFileManager、NSUserDefaults、NSTimer、UIColor、UIViewController 等。
例如:
面板对象常用方法
创建和加载
AddonWebPanel.panel()
创建一个新的面板对象。
panel.loadPanel()
按 mnaddon.json 的 panel 字段读取包内 HTML 文件。文件不存在、未声明 panel 或路径越界时返回 false。这是加载面板的推荐方式。
panel.loadHTML(html)
直接加载一段 HTML 字符串作为面板的源代码。
双向通信
panel.onMessage = function (name, payload) { ... }
接收面板侧 mn.call(name, payload) 的入口。
panel.post(event, data)
从 main.js 向面板页面以 mn:<event> 的命名格式发送事件。
媒体数据
panel.putMedia(key, data, type)
将二进制图片数据交给面板。页面通过 /media/<key> 引用该数据。data 为空时,宿主会删除对应 key。
panel.clearMedia()
清空当前面板的媒体缓存。较大的图片数据建议通过媒体缓存传递,避免放入 JSON 或 post() 数据。
显示和隐藏
panel.showFloatingIn(studyController)
将面板作为常驻浮层显示到学习集控制器中。面板已经显示时,再次调用会将面板置于前台并刷新布局。
panel.showFloatingInMode(studyController, mode)
按指定形态显示面板。mode 可使用 "mini" 或 "workspace"。
panel.hideFloating()
收起浮层,并触发面板清理。插件主动关闭面板时,优先调用该方法。
资源清理
panel.teardown()
显式断开面板、WebView、回调和未完成请求之间的引用关系,避免旧面板继续占用资源。hideFloating() 会一并执行清理。插件通过其他展示方式关闭面板时,应主动调用 teardown()。