流星雨模块框架文档中心

示例集

四个覆盖不同能力面的完整例子。参考实现是仓库里的 modules/手机状态监测/,实际生产代码可以直接翻它。

最小模块

一个方法 + 一个页面,验证环境用。

text
hello/
├── manifest.json
├── main.py
└── ui/index.html
json
{ "name": "hello", "version": "1.0.0", "entry": "main",
  "description": "最小示例", "ui": "ui/index.html" }
python
from jade_framework import JadeModule


class Hello(JadeModule):
    def setup(self, ctx):
        ctx.register_handler("hi", self._hi)

    def _hi(self, who: str = "world") -> str:
        return f"你好,{who}!"


MODULE = Hello
html
<script src="/jade-bridge.js"></script>
<button onclick="alert(await jade.call('hello', 'hi', '模块'))">点我</button>

轮询推送模块(无界面)

不写页面,纯后台轮询,数据全靠卡片和底部字段条展示。这个形态适合监控类模块。

python
import threading
from jade_framework import JadeModule


class Counter(JadeModule):
    def setup(self, ctx):
        ctx.register_handler("stats", self._stats)

    def on_enable(self):
        self._interval = max(1.0, float(self.ctx.config.get("interval", 2.0)))
        self._stop = threading.Event()
        self._thread = threading.Thread(target=self._loop, daemon=True)
        self._thread.start()
        self._last = {}

    def on_disable(self):
        self._stop.set()
        self._thread.join(timeout=self._interval + 5)
        self.ctx.set_card(None)          # 清卡片
        self.ctx.push_fields({})         # 清底部字段

    def _loop(self):
        while not self._stop.is_set():
            try:
                self._last = self._collect()
                # 卡片:摘要;字段条:两三个关键指标
                self.ctx.set_card(self._last)
                self.ctx.push_fields({"轮询间隔": f"{self._interval}s",
                                      "状态": "运行中"})
            except Exception as e:
                self.ctx.log.warning("轮询异常: %s", e)
            self._stop.wait(self._interval)          # 可被立即唤醒

    def _collect(self) -> dict:
        # 真实逻辑放这里:调外部命令、读接口……
        return {"样本": 1}

    def _stats(self) -> dict:
        return self._last


MODULE = Counter

要点:线程可停(Event + join)、循环异常不退出、停用时清干净推送。

带标题栏按钮的操作模块

在轮询的基础上给标题栏注册按钮,用户不用打开页面就能执行操作:

python
def on_enable(self):
    ...
    self.ctx.push_titlebar({
        "设备": self._count,
        "_buttons": [
            {"label": "刷新", "rpc": {"module": "counter", "method": "refresh"}},
            {"label": "清零", "rpc": {"module": "counter", "method": "reset"}},
        ],
    })

def on_disable(self):
    ...
    self.ctx.push_titlebar({})       # 记得清

按钮点击直接执行对应方法,和页面无关。所有 rpc.method 指向的方法都要在 setup 里注册过。

数据存储模块

用 KV 存状态、SQL 存记录、事务合并写:

python
def on_enable(self):
    self.ctx.store.execute(
        "CREATE TABLE IF NOT EXISTS records ("
        " id INTEGER PRIMARY KEY, tag TEXT, ts REAL)")
    # 上次运行的状态从 KV 恢复
    self._last_tag = self.ctx.store.get("last_tag", "")

def _save(self, tag: str):
    with self.ctx.store.transaction():        # KV 与 SQL 合并一次落盘
        self.ctx.store.set("last_tag", tag)
        self.ctx.store.execute("INSERT INTO records(tag, ts) VALUES(?, ?)",
                               (tag, time.time()))

数据结构跨版本变更的迁移写法见 持久化存储

Vue 3 界面模块

页面技术栈不限,Vue 完整写法(含离线打包 vendor 的注意事项)见 界面开发。React 的 UMD 写法也在那一页。

打包验证

每个示例交付前都跑一遍同一套流程:

bash
python tools/encrypt_module.py encrypt --in modules/hello --out modules/hello.jmod --key-id default
python tools/encrypt_module.py inspect --in modules/hello.jmod

然后把 .jmod 放进宿主 modules/ 重启,重复验证一遍。完整规则见 打包与交付