OneScript
基础

photos

将图片保存到系统照片图库,以及拍照和录像。

photos.save

将一张图片保存到系统照片图库。Photos 完成保存后 Promise resolve;授权、下载、验证或保存失败时 Promise reject。

type PhotoSaveOptions =
  | {
      url: string | URL;
      headers?: Readonly<Record<string, string>>;
      filename?: string;
    }
  | {
      data: Blob | ArrayBuffer | ArrayBufferView;
      filename?: string;
    };

function photos.save(options: PhotoSaveOptions): Promise<void>;

options 必须指定一种图片来源:

属性类型说明
urlstring | URLHTTP 或 HTTPS 图片地址。
headersRecord<string, string>URL 请求使用的可选请求头。
dataBlob | ArrayBuffer | ArrayBufferView脚本已经持有的图片字节。File 和 Node.js Buffer 均由这些类型覆盖。
filenamestring保存到图库的可选原始文件名。

第一次保存时,系统可能显示照片图库“仅添加”权限提示。API 可在 app、action 和 widget 脚本中调用,系统决定当前环境能否完成 Photos 访问。

成功保存后返回的 Promise resolve,且没有返回值。url 和 data 必须二选一;空数据、非法 URL、非法请求头及原生处理错误会使 Promise reject。

保存 URL 图片

import { photos } from "onescript";

await photos.save({
  url: "https://example.com/photos/original.heic",
  filename: "original.heic"
});

需要身份认证时可以显式传入请求头:

await photos.save({
  url: "https://api.example.com/private/photo.jpg",
  headers: {
    Authorization: `Bearer ${token}`
  }
});

URL 下载使用 GET 和独立的临时会话。请求不会读取或写入 App 的 Cookie、缓存和已保存 HTTP 凭据。通过 headers 显式传入的 Cookie 仅用于当前请求及同源重定向;跨源重定向会移除 Authorization、Cookie 和 Proxy-Authorization。

保存图片数据

const response = await fetch("https://example.com/generated.png");

await photos.save({
  data: await response.blob(),
  filename: "generated.png"
});

省略 filename 时,File 会提供自身文件名:

await photos.save({ data: imageFile });

Node.js Buffer 可以直接传入:

import { readFile } from "node:fs/promises";
import { photos } from "onescript";

const data = await readFile("images/result.png");
await photos.save({ data, filename: "result.png" });

原始文件名按以下顺序推导:显式 filename、File.name、最终 URL 的路径末段、Photos 自动生成。

大图片

URL 响应会直接下载到临时文件。内存数据按 512 KiB 分块传输,每条 Bridge JSON 消息保持在约 700 KiB 以内,并在 Photos 导入前持续写入临时文件。OneScript 不设置固定的图片总大小上限,实际限制由可用存储空间、脚本环境生命周期和 Photos 决定;脚本取消、退出或异常结束时,未完成的下载和临时文件会被清理。

错误处理

使用 try/catch 处理错误。原生错误使用稳定前缀,包括 PHOTO_PERMISSION_DENIED、PHOTO_DOWNLOAD_FAILED、PHOTO_TRANSFER_FAILED、PHOTO_INVALID_IMAGE 和 PHOTO_SAVE_FAILED。

try {
  await photos.save({ data: imageData, filename: "photo.png" });
} catch (error) {
  console.error("保存图片失败:", error);
}

photos.takePhoto

打开系统相机,以 File 返回拍摄的照片。用户取消时 Promise resolve 为 null。

type CameraDevice = "back" | "front";

interface TakePhotoOptions {
  device?: CameraDevice;
}

function photos.takePhoto(options?: TakePhotoOptions): Promise<File | null>;
属性类型说明
device"back" | "front"使用的摄像头,默认 "back"。

返回的 File 是 JPEG(image/jpeg),名称为 IMG_yyyyMMdd_HHmmss.jpg,lastModified 为用户确认照片的时间。像素已按拍摄时的方向转正,不包含 EXIF、位置等元数据。

import { photos } from "onescript";

const photo = await photos.takePhoto();
if (photo) {
  await photos.save({ data: photo });
}

文件可以直接上传:

const photo = await photos.takePhoto({ device: "front" });
if (photo) {
  const form = new FormData();
  form.append("avatar", photo);
  await fetch("https://api.example.com/avatar", { method: "POST", body: form });
}

photos.recordVideo

以录像模式打开系统相机,返回录好的文件的绝对路径。用户取消时 Promise resolve 为 null。

interface RecordVideoOptions {
  device?: CameraDevice;
  maxDuration?: number;
  quality?: "high" | "medium" | "low";
}

function photos.recordVideo(options?: RecordVideoOptions): Promise<string | null>;
属性类型说明
device"back" | "front"使用的摄像头,默认 "back"。
maxDurationnumber最长录制时间(秒),到时自动停止。必须是有限的正数。
quality"high" | "medium" | "low"录制质量,默认 "high"。

视频按录制结果原样保存为 QuickTime 格式(.mov),名称为 VID_yyyyMMdd_HHmmss.mov。视频可能很大,所以保留在磁盘上,只返回路径。

文件存放在本次运行专属的临时目录中,脚本结束时删除。要保留视频,用 fs.rename 把它移走,例如移到项目的持久化数据目录 os.homedir():

import { rename } from "node:fs/promises";
import os from "node:os";
import { join } from "node:path";
import { photos } from "onescript";

const video = await photos.recordVideo({ maxDuration: 30 });
if (video) {
  await rename(video, join(os.homedir(), "clip.mov"));
}

相机的可用范围与权限

相机只在 OneScript App 运行的脚本中可用。Widget 没有界面,iOS 也不允许 App 扩展使用相机,因此在 widget 和 action 脚本中调用会以 PHOTO_CAMERA_UNAVAILABLE reject。设备上没有请求的摄像头时(包括模拟器)也会报告同样的错误。

第一次拍照时系统会显示相机权限提示;第一次录像时还会请求麦克风权限,用于录制声音。同一时间只能打开一个相机界面。相机打开期间脚本停止运行时,相机会关闭,Promise reject。

错误

错误原因
PHOTO_CAMERA_UNAVAILABLE脚本不在 App 中运行,或请求的摄像头不可用。
PHOTO_CAMERA_PERMISSION_DENIED相机或麦克风权限被拒绝,消息中会注明是哪一个。
PHOTO_CAPTURE_BUSY已经有一个相机界面处于打开状态。
PHOTO_CAPTURE_FAILED照片或视频处理失败。
try {
  const photo = await photos.takePhoto();
} catch (error) {
  console.error("拍照失败:", error);
}

How is this guide?

最后更新于

本页目录