Skip to main content
除了使用 Web 技术栈进行标准的场景插件开发外,也可在插件根目录增加 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
post() 在页面加载完成前调用时,事件会先被缓存,并在页面就绪后投递。

使用 MN 原生对象

main.js 可访问 JSB 暴露的原生对象,例如 Application、Database、NSFileManager、NSUserDefaults、NSTimer、UIColor、UIViewController 等。 例如:
完整对象、属性与方法请参考 MarginNote 插件开发文档。

面板对象常用方法

创建和加载

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()。