Skip to content

JSWidget JavaScript 运行时 API 文档

JSWidget JS 运行时暴露给 JavaScript 的所有 API。


概述

JSWidget 使用 JavaScriptCore 框架,在 Swift 端通过 JSExport 协议将原生 API 暴露给 JavaScript 环境。

入口脚本(如 main.jsx):直接编写顶层语句,可使用顶层 await桌面小组件在脚本中调用 $render 输出界面;灵动岛 / Live Activity 等场景调用 $dynamic_island(见下文「灵动岛 API」),同一入口脚本只取其一作为输出方式。通过 $import 加载的其它文件按模块方式编译执行,多用于导出变量、函数或 JSX 片段,与入口脚本的装载方式不同,详见「文件导入 API」章节。

在 JS 上下文中可用的全局对象包括:

  • $http - HTTP 请求
  • $fetch / fetch - 简化的 GET 请求
  • $console / console - 日志输出
  • $device - 设备信息
  • $file - 脚本包内文件读写
  • $system - 系统信息
  • $health - HealthKit 健康数据
  • $location - 位置服务
  • $storage - 本地存储
  • $getenv - 环境变量
  • $import - 导入其他文件
  • $render - 渲染组件
  • $dynamic_island - 灵动岛配置
  • $element - 元素构造函数
  • $component - 组件定义
  • $error - 错误处理
  • Promise - Promise 支持

1. HTTP 请求 API

$http

完整的 RESTful HTTP 请求支持。

方法列表

方法参数返回值说明
get(url, params?)url: string, params?: HttpParamsPromise<string>发送 GET 请求
post(url, params?)url: string, params?: HttpParamsPromise<string>发送 POST 请求
put(url, params?)url: string, params?: HttpParamsPromise<string>发送 PUT 请求
patch(url, params?)url: string, params?: HttpParamsPromise<string>发送 PATCH 请求
delete(url, params?)url: string, params?: HttpParamsPromise<string>发送 DELETE 请求

HttpParams 字段见下文「$fetch / fetch」章节。

使用示例

jsx
// GET 请求
const result = await $http.get("https://api.example.com/data");

// GET 请求带 header
const data = await $http.get("https://api.github.com/users", {
  headers: {
    Accept: "application/json"
  }
});

// POST 请求带 JSON body
const response = await $http.post("https://api.example.com/posts", {
  body: {
    title: "Hello",
    content: "World"
  }
});

// POST 请求带字符串 body
const response = await $http.post("https://api.example.com/login", {
  headers: {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  body: "username=admin&password=123"
});

$fetch / fetch

$http.get 等效的 fetch API 封装(params 类型同 HttpParams)。

函数参数返回值说明
$fetch(url, params?)url: string, params?: HttpParamsPromise<string>发送 GET 请求
fetch(url, params?)url: string, params?: HttpParamsPromise<string>$fetch 相同

HttpParams

字段类型说明
headersRecord<string, string>可选,HTTP 请求头
bodystring | Record<string, any>可选,请求体(对象会序列化为 JSON)
timeoutIntervalnumber可选,超时时间(秒)
jsx
const result = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const data = JSON.parse(result);

const withHeaders = await $fetch("https://api.example.com/data", {
  headers: { Accept: "application/json" },
  timeoutInterval: 30,
});

2. 控制台 API

$console / console

用于输出日志和错误信息。$consoleconsole 等价。

支持多个参数,会格式化为单行文本(对象自动 JSON.stringify)。在 App 预览控制台中,log / info / warn / error 会以不同颜色显示。

方法参数返回值说明
log(...args)任意参数void普通日志
info(...args)任意参数void信息日志
warn(...args)任意参数void警告日志
error(...args)任意参数void错误日志
jsx
console.log("Hello JSWidget");
console.log("Value:", someVariable);
console.info("Fetched", { count: 3 });
console.warn("Rate limited");
console.error("Something went wrong!");

3. 设备信息 API

$device

提供设备相关信息。

方法参数返回值说明
name()-string设备名称(如 "iPhone 15 Pro")
model()-string设备型号(如 "iPhone")
language()-string当前语言代码(如 "zh"、"en")
systemVersion()-string系统版本(如 "17.0")
screen()-{ scale: number, width: number, height: number }屏幕信息
battery()-{ level: number, state: string }电池信息
isdarkmode()-boolean是否深色模式
totalDiskSpace()-number磁盘总空间(字节)
freeDiskSpace()-number磁盘可用空间(字节)

battery() 返回值说明

  • level: 电池电量,0-1
  • state: 电池状态
state 值说明
unknown未知
charging充电中
full已充满
unplugged未充电
jsx
console.log($device.name());           // "iPhone 15 Pro"
console.log($device.model());           // "iPhone"
console.log($device.language());        // "zh"
console.log($device.systemVersion());   // "17.0"
console.log(JSON.stringify($device.screen()));
// { "scale": 3, "width": 393, "height": 852 }
console.log(JSON.stringify($device.battery()));
// { "level": 0.85, "state": "charging" }
console.log($device.isdarkmode());      // true

4. 文件操作 API

$file

操作当前脚本包根目录内的文件(与 main.jsx 同级或其子路径)。路径为包内相对路径;list("") 表示列出包根目录。不支持 .. 或绝对路径越出包外。

方法参数返回值说明
readString(path)path: stringstring读取文件为 UTF-8 字符串;失败返回 ""
writeString(path, content)path: string, content: stringboolean写入文件(自动创建父目录);只读包返回 false
remove(path)path: stringboolean删除文件;不可删除 main.jsx
list(path)path: stringstring[]列出目录下一层条目(文件名与子目录名,非递归)
jsx
const raw = $file.readString("data.json");
const json = JSON.parse(raw);
console.log(json.name);

$file.writeString("notes.txt", "hello");
console.log($file.list("")); // 包根目录
console.log($file.remove("notes.txt"));

5. 系统信息 API

$system

提供系统相关信息。

方法参数返回值说明
appInfo()-{ name, bundleId, version, build }应用信息
locale()-string当前区域设置
preferredLanguages()-[string]首选语言列表
timeZone()-{ identifier, abbreviation, offsetSeconds }时区信息
is24HourClock()-boolean是否为 24 小时制
calendarInfo()-{ identifier, firstWeekday, minimumDaysInFirstWeek }日历信息
systemUptime()-double系统运行时间(秒)
memory()-{ physical: number }物理内存(字节)
thermalState()-"nominal" | "fair" | "serious" | "critical" | "unknown"热状态
lowPowerMode()-boolean低电量模式
brightness()-number屏幕亮度:iOS 为 01;macOS 为 -1
reduceMotionEnabled()-boolean减弱动态效果
platform()-"ios" | "macos"平台类型
hostName()-string主机名
processName()-string进程名
osVersionString()-stringOS 版本字符串
processorCount()-number处理器数量
activeProcessorCount()-number活跃处理器数量

thermalState 返回值

说明
nominal正常
fair轻微发热
serious发热严重
critical过热
unknown未知
jsx
const app = $system.appInfo();
const tz = $system.timeZone();
const memory = $system.memory();
const cpuCount = $system.processorCount();

$render(
  <col>
    <text font="title">{app.name}</text>
    <text font="caption">Version: {app.version} ({app.build})</text>
    <text font="caption">Platform: {$system.platform()}</text>
    <text font="caption">Timezone: {tz.identifier}</text>
  </col>
);

6. 健康数据 API

$health

读取 HealthKit 健康数据(仅 iOS,仅读操作)。

方法参数返回值说明
isAvailable()-booleanHealthKit 是否可用
requestAuthorization()-Promise<boolean>请求健康数据授权
stepCountToday()-Promise<HealthSample>今日步数
activeEnergyToday()-Promise<HealthSample>今日活动能量
heartRateLatest()-Promise<HealthSample>最新心率

HealthSample

字段类型说明
valuenumber数值
unitstring单位
startstring区间开始时间
endstring区间结束时间
jsx
if (!$health.isAvailable()) {
  $render(
    <col>
      <text font="title3" color="#f87171">HealthKit Unavailable</text>
    </col>
  );
} else {
  const granted = await $health.requestAuthorization();

  if (!granted) {
    $render(
      <col>
        <text font="title3" color="#fbbf24">Permission Needed</text>
      </col>
    );
  } else {
    const steps = await $health.stepCountToday();
    const energy = await $health.activeEnergyToday();
    const heart = await $health.heartRateLatest();

    $render(
      <col>
        <text font="title3">Steps: {steps.value.toFixed(0)}</text>
        <text font="caption">Active Energy: {energy.value.toFixed(0)} kcal</text>
        <text font="caption">Latest HR: {heart.value.toFixed(0)} bpm</text>
      </col>
    );
  }
}

7. 位置服务 API

$location

获取设备位置(仅 iOS)。

方法参数返回值说明
isAvailable()-boolean位置服务是否可用
authorizationStatus()-LocationAuthorizationStatus授权状态
requestAuthorization(options?)options?: LocationRequestOptionsPromise<boolean>请求位置授权
current(options?)options?: LocationCurrentOptionsPromise<LocationPayload>获取当前位置

LocationAuthorizationStatus

说明
notDetermined未决定
restricted受限制
denied被拒绝
authorizedAlways始终授权
authorizedWhenInUse使用时授权
disabled定位服务关闭(iOS)
unknown未知
unavailable不可用(非 iOS stub)

LocationRequestOptions

字段类型说明
timeoutnumber可选,超时(秒)
timeoutMsnumber可选,超时(毫秒)

LocationCurrentOptions

继承 LocationRequestOptions,并额外支持:

字段类型说明
maxAgenumber可选,可接受缓存位置的最大年龄(秒)
maxAgeMsnumber可选,同上(毫秒)
accuracy"full" | "reduced"可选,精度
purposeKeystring可选,用途键(iOS)

LocationPayload

字段类型说明
latitudenumber纬度
longitudenumber经度
altitudenumber海拔
accuracynumber水平精度(米)
verticalAccuracynumber垂直精度
speednumber速度
coursenumber航向
timestampstringISO8601 时间戳
accuracyAuthorization"full" | "reduced" | "unknown"精度授权
agenumber缓存年龄(秒)
isStaleboolean是否过期
jsx
if (!$location.isAvailable()) {
  $render(
    <col>
      <text font="title3" color="#f87171">Location Unavailable</text>
    </col>
  );
} else {
  const status = $location.authorizationStatus();
  let granted = status === "authorizedWhenInUse" || status === "authorizedAlways";

  if (!granted) {
    granted = await $location.requestAuthorization({ timeout: 10 });
  }

  if (!granted) {
    $render(
      <col>
        <text font="title3" color="#fbbf24">Permission Needed</text>
      </col>
    );
  } else {
    const location = await $location.current({
      timeout: 10,
      accuracy: "full",
      purposeKey: "JSWidgetLocation"
    });

    $render(
      <col>
        <text font="title3">
          {location.latitude.toFixed(5)}, {location.longitude.toFixed(5)}
        </text>
        <text font="caption">
          Accuracy: {Math.round(location.accuracy)}m ({location.accuracyAuthorization})
        </text>
      </col>
    );
  }
}

8. 本地存储 API

$storage

使用 UserDefaults 存储数据。

方法参数返回值说明
getString(key)key: stringstring获取字符串值
setString(key, value)key: string, value: stringboolean存储字符串
getJSON(key)key: stringRecord<string, unknown>获取 JSON 对象
setJSON(key, value)key: string, value: Record<string, unknown>boolean存储 JSON 对象
remove(key)key: stringboolean删除指定键
keys()-[string]获取所有键
clear()-boolean清空所有数据
jsx
// 存储字符串
$storage.setString("greeting", "Hello JSWidget");
const greeting = $storage.getString("greeting");

// 存储 JSON
$storage.setJSON("profile", {
  name: "Alex",
  city: "Shanghai",
  updatedAt: new Date().toISOString()
});
const profile = $storage.getJSON("profile");

// 获取所有键
const allKeys = $storage.keys();

$render(
  <col>
    <text font="title">{greeting}</text>
    <text font="caption">Name: {profile.name}</text>
    <text font="caption">Keys: {allKeys.join(", ")}</text>
  </col>
);

9. 环境变量 API

$getenv

获取运行时的环境变量(按 key 重载返回值类型)。

调用参数返回值
$getenv("widget-size")字面量 "widget-size"JSWidgetSize | ""
$getenv("widget-param")字面量 "widget-param"string
$getenv("script-dir")字面量 "script-dir"string
$getenv(key)其它 stringstring

JSWidgetSize(widget-size 的可能值)

"small" | "medium" | "large" | "extraLarge" | "accessoryInline" | "accessoryCircular" | "accessoryRectangular" | "live-activity" | "dynamic-island" | "function"

变量名说明
widget-param用户配置的参数字符串
script-dir当前脚本包目录的绝对路径
jsx
const widget_size = $getenv("widget-size");
const widget_param = $getenv("widget-param");

$render(
  <col>
    <text font="title">Widget Size: {widget_size}</text>
    <text font="caption">Parameter: {widget_param}</text>
  </col>
);

10. 文件导入 API

$import

导入并执行同包内.js / .jsx 文件(包内相对路径)。被导入文件的顶层变量/函数会进入当前 JS 上下文的全局作用域

函数参数返回值说明
$import(relativePath)relativePath: stringboolean文件是否存在;执行是否成功需自行保证(调用为同步,编译/执行为异步调度)
jsx
// util.jsx — 顶层定义
const textItems = [<text>Item 1</text>, <text>Item 2</text>];
const sum = (a, b) => a + b;

// main.jsx
$import("util.jsx");

$render(
  <col>
    <text font="title">test</text>
    {textItems}
    <text font="title">{sum(1, 2)}</text>
  </col>
);

11. 渲染 API

$render

将 JSX 元素树渲染为小组件。

方法参数返回值说明
$render(element)element: unknownvoid渲染 JSX 元素树
jsx
$render(
  <col size="max" backgroundColor="#0f172a">
    <text font="title" color="#e2e8f0">Hello JSWidget</text>
    <spacer />
    <text font="caption" color="#94a3b8">Welcome!</text>
  </col>
);

12. 灵动岛 API

$dynamic_island

灵动岛入口脚本使用 $dynamic_island(config) 输出布局(与桌面小组件的 $render 互斥)。

函数参数返回值
$dynamic_island(config)config: DynamicIslandConfigvoid

DynamicIslandConfig

字段类型说明
expandedDynamicIslandExpandedConfig展开态(必填)
compactLeadingunknown紧凑态左侧
compactTrailingunknown紧凑态右侧
minimalunknown最小态

DynamicIslandExpandedConfig

字段类型说明
leadingunknown可选
trailingunknown可选
centerunknown可选
bottomunknown可选
jsx
$dynamic_island({
  expanded: {
    leading: <text>Left</text>,
    trailing: <text>Right</text>,
    center: <text>Center</text>,
    bottom: <text>Bottom</text>,
  },
  compactLeading: <text>Lead</text>,
  compactTrailing: <text>Trail</text>,
  minimal: <text>...</text>
});

13. 组件定义 API

$component

定义可复用的组件。

函数参数返回值说明
$component(name, builder)name: string, builder: (...args: unknown[]) => unknownvoid注册命名组件
jsx
$component("MyCard", (title, content) => {
  return (
    <col backgroundColor="#f1f5f9" cornerRadius={12}>
      <text font="headline">{title}</text>
      <text font="body">{content}</text>
    </col>
  );
});

14. 元素构造函数

$element

创建 JSX 元素(与 JSWidget.createElement 等价)。

属性 / 方法类型说明
createElement(tag, props?, ...children)tag: string | ((...args: unknown[]) => unknown), props?: Record<string, unknown> | null, ...children: unknown[]unknown
jsx
const textElement = $element.createElement("text", { font: "title" }, ["Hello"]);

15. 错误处理 API

$error

报告错误信息。

方法参数返回值说明
$error(message)message: stringvoid报告错误
jsx
try {
  // some code
} catch(e) {
  $error(`${e}`);
}

16. 全局 Promise 支持

Promise

内置 Promise 支持,可用于 async/await 模式。

jsx
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

await delay(1000);
const result = await $http.get("https://api.example.com/data");

$render(
  <col>
    <text>{result}</text>
  </col>
);

附录:API 汇总表

API说明平台
$httpHTTP 请求iOS / macOS
$fetch / fetch简化的 GET 请求iOS / macOS
$console / console日志输出iOS / macOS
$device设备信息iOS / macOS
$file脚本包内文件读写iOS / macOS
$system系统信息iOS / macOS
$healthHealthKit 健康数据iOS
$location位置服务iOS
$storage本地存储iOS / macOS
$getenv环境变量iOS / macOS
$import文件导入iOS / macOS
$render渲染组件iOS / macOS
$dynamic_island灵动岛配置iOS
$component组件定义iOS / macOS
$element元素构造函数iOS / macOS
$error错误处理iOS / macOS

Released under the MIT License.