跳转至正文
移动端 Capacitor

用于 Capacitor 和 Capgo 的 TypeScript API 示例

探索 Capacitor 插件与 Capgo 更新的实用 TypeScript API 示例。掌握类型化接口、监听器模式及实现策略。

用于 Capacitor 和 Capgo 的 TypeScript API 示例

每个靠谱的 TypeScript API 示例 对于 Capacitor 来说,起点是一样的:一个类型化的插件接口。明确定义你的方法、选项和 Promise 结果,这样你的 Web code 和原生层就能共享一份由 TypeScript 真正强制执行的契约。

目录

构建强类型的 Capacitor 插件接口

该接口描述了你的 Web code 所看到的 API。底层原生实现必须遵守这个契约——TypeScript 会在应用运行前检查方法名、参数和返回值。

import { registerPlugin } from ‘@capacitor/core’;

export interface DeviceStatus {\nonline: boolean;\nbatteryLevel?: number;\n}

export interface DevicePlugin {\ngetStatus(): Promise};\nsetLabel(options: { label: string }): Promise<{ saved: boolean }>;\n}

export const Device = registerPlugin(‘Device’);

这几行代码包含了很多关键点:

  • 显式返回类型 确保每个结果都可预测。
  • 类型化的 options 对象 在编译时捕获缺失或拼写错误的属性。
  • 基于 Promise 的方法 用于建模异步完成的原生操作。
  • 一个通用的 registerPlugin 呼叫 是将 Web API 连接到原生桥接的组件。
  • 接口 记录契约,而不增加一字节运行时 code。

每个调用点都同样处理:

const status = await Device.getStatus(); console.log(status.online);

await Device.setLabel({ label: ‘Production’ });

替换 { label: 'Production' } 来实现 { name: 'Production' } 编译器会当场标记出来。这比移动端发布后才发现不匹配强多了。

接口也是你对可选值和失败情况建模的地方。如果一个原生方法并不总能返回电池读数, batteryLevel?: number 告诉每个调用方处理 undefined.

下图展示了类型化方法、选项、返回值、桥接定义和编译时检查如何在 Capacitor API 内部连接起来。

图示展示了强类型 TypeScript 插件接口对移动开发框架的关键优势。

核心思路: 类型定义从面向 Web 的接口流向原生平台逻辑,编译时检查则在每个调用点把关。

API 设计速查

元素 用途 示例
方法签名 定义可调用行为 getStatus()
Options 类型 控制输入结构 { label: string }
Promise 结果 表示异步任务 Promise<DeviceStatus>
Result 接口 定义返回数据 online: boolean

如需更深入的参考,请阅读 使用 TypeScript 构建 API 的指南。有两个习惯值得保持:不要把密钥和签名凭据放进客户端 code,并在发布前针对各平台的实现测试接口。

移动端团队需要同时处理 JavaScript、原生 code、设备权限以及各种异步平台服务。一份 强大的 TypeScript 契约 在这些边界处就像一份共享清单,让所有预期在任何 code 落到 iOS 或 Android 设备之前就明确下来。

一个人坐在桌前用笔记本电脑写代码,屏幕上显示着 code,旁边放着一个咖啡杯。

来看一个具体的 TypeScript API 示例,对比一个返回类型化数据的方法 Promise<DeviceStatus> 与另一个返回未类型化数据的方法。类型化版本让编辑器和每位审查者都确切知道有哪些字段。未类型化版本则把这种摸索工作推给运行时日志、手动测试,最坏情况下还会变成生产事故。

采用信号

TypeScript 早已走出前端小众领域。采用率已攀升至 2024 年开发者中的 35%,而此前仅为 2017 年为 12%,并且超过 一百万 GitHub 贡献者 到 2025 年将其列为首要语言。深入了解完整的 TypeScript 采用情况调查结果, 如果你想查看原始数据。

这种趋势对移动端团队有实际影响。招聘、onboarding 和 code 审查越来越围绕共享类型展开。新成员加入 Capacitor 项目时,只要读一下 interface,就能理解预期的原生行为,无需追踪每个实现。

类型化 API 也让发布工作更容易理解。当方法要求特定的 options 对象时,属性改名或字段缺失会在编译时报错,而不是静默生成一个不完整的原生请求。

强类型让关键反馈左移,修复只需几分钟,而不用紧急发布 hotfix。

Capacitor 团队的优势

跨平台应用通常会在多个原生实现之上提供一个面向 Web 的 API。TypeScript 无法证明每个原生细节的行为都完全一致,但可以让你的调用在整个应用中保持一致。

为以下内容显式指定类型:

  • 方法入参,包括必填和可选项
  • Promise 结果,确保成功返回的数据结构始终可预测
  • 事件与监听器,确保回调能处理已知的 payload
  • 错误与状态值,让回退路径保持可见

这种结构在集成设备插件或运营服务时很有价值。它也能帮助审查更新自动化的团队——错误的 channel、bundle identifier 或兼容性字段可能会波及大量用户。

想深入了解相关模式,请阅读 我们关于使用 OpenAPI 生成类型化 API 的指南。它介绍了共享定义如何减少 API 文档与应用 code 之间通常逐渐产生的手动偏差。

论证商业价值

严格类型确实需要一些前期投入,尤其是当旧的 JavaScript code 包含不一致的数据结构时。回报会随时间显现:更小的重构、更清晰的职责划分,以及更少的集成意外。

从风险最高的边界开始:

  1. 为原生和远程调用定义响应接口。
  2. 为选项对象和事件负载添加类型。
  3. 逐步启用严格编译器检查。
  4. 发布任何更新前,要求通过类型检查。

对企业移动团队来说,这个基础能让跨平台、跨版本和跨贡献者的维护保持可预测。

Capacitor 的 ScreenOrientationPlugin 是一个很好的 TypeScript API 示例 因为它把几个简单的 Web 方法映射到各平台的设备行为。公共契约在各平台保持一致,而 iOS 和 Android 各自在底层处理自己的原生细节。

import { registerPlugin } from ‘@capacitor/core’;

export type OrientationType = | ‘portrait-primary’ | ‘portrait-secondary’ | ‘landscape-primary’ | ‘landscape-secondary’;

export interface OrientationData { type: OrientationType; angle: number; }

export interface LockOptions { orientation: OrientationType; }

export interface ScreenOrientationPlugin { orientation(): Promise;\nlock(options: LockOptions): Promise;\nunlock(): Promise;\naddListener(\neventName: ‘screenOrientationChange’,\nlistenerFunc: (data: OrientationData) => void,\n): Promise<{ remove: () => Promise }>; }

export const ScreenOrientation = registerPlugin(‘ScreenOrientation’);

以下是每个签名的快速参考:

  • orientation() — 异步读取当前屏幕方向
  • lock() — 仅接受已知的方向值
  • unlock() — 将控制权交还给设备的正常行为
  • addListener() — 方向变化时触发带类型的 payload

由于每个方法都返回 Promise,你可以对原生 bridge 和浏览器实现使用相同的调用模式。无需分支,无需特殊处理。

const current = await ScreenOrientation.orientation();

if (current.type.startsWith(‘landscape’)) {\nconsole.log("}Angle: ${current.angle}); }

await ScreenOrientation.lock({ orientation: 'landscape-primary', });

输入一个拼错的值,例如 landscape-main 构建会立即失败。这是一个几秒钟就能修复的编译错误,而不是要在设备 logs 里苦苦追踪的平台相关运行时 bug。

正确标注 Listener 参数类型

Listener 也应像普通方法一样严谨。避免 any 在这里,因为这会掩盖事件 payload 与 orientation() 返回结果之间的差异。

const handleChange = (data: OrientationData) => {\ndocument.body.dataset.orientation = data.type;\n};

const subscription = await ScreenOrientation.addListener( ‘screenOrientationChange’, handleChange, );

await subscription.remove();

只共享单一 OrientationData 类型,前提是两个原生实现都保证字段相同。如果其中一个平台省略了 angle,就将其标记为可选,并强制调用方处理 undefined.

设计选择 更安全的模式
输入 具名选项接口
评测结果 显式 Promise 类型
事件 字面量事件名称
清理 返回可移除的订阅

接口是桥接契约,而非原生实现。 保持小巧、可预测且易于测试。

关于平台行为、权限和安装步骤,请阅读 Capacitor 屏幕方向插件指南。最后一个值得养成的习惯:在严格的 TypeScript 设置下,同时测试有效调用和被拒绝的调用。这种组合能在打包移动应用之前,尽早发现错误的方法名、缺失的字段以及不兼容的监听器负载。

Capgo 让 Capacitor 团队无需等待应用商店审核,即可推送 JavaScript、CSS、配置和资源修复。关键在于将其更新 pipeline 视为其他类型化的 API 边界,从而在 bundle 到达用户设备之前,明确渠道、发布规则、兼容性检查和回滚决策。

一个人拿着智能手机,展示竖屏和横屏两种屏幕方向模式的区别。

定义更新契约

先明确你的自动化到底接受哪些值。字面量联合类型能避免误部署到错误的 channel,而 interface 则让 bundle 与其所需原生版本之间的关系自文档化。

type Channel = ‘beta’ | ‘staging’ | ‘production’;

interface UpdateRequest {\nchannel: Channel;\nbundleVersion: string;\nminNativeVersion: string;\nrolloutPercent: number;\nsigned: boolean;\n}

interface UpdateResult {\naccepted: boolean;\nappliedOnNextLaunch: boolean;\nrollbackEnabled: boolean;\n}

一个简单直接的 TypeScript API 示例 函数会先校验请求,再交给 Capgo 客户端:

async function publishUpdate(\nrequest: UpdateRequest,\n): Promise {\nif (!request.signed || request.rolloutPercent < 0 ||\nrequest.rolloutPercent > 100) {\nthrow new Error(‘Unsafe update request’);\n}\n}

return capgo.publish(request);\n}

Capgo SDK 各版本之间,客户端方法名会发生变化,所以请把它封装在自己的 interface 后面。每次升级时这种隔离都会带来回报,也能避免厂商特定细节泄漏到整个代码库。

守住 Channel 与兼容性

选择 Channel 不能随意。生产发布需要比 Beta 试验更严格的检查,尤其是当 Web bundle 调用旧版 App 中不存在的原生能力时。

function canDeploy(\nrequest: UpdateRequest,\ninstalledNativeVersion: string,\n): boolean {\nreturn request.signed &&\ninstalledNativeVersion >= request.minNativeVersion;\n}

不要直接用普通字符串比较版本号。引入一个靠谱的 semantic-version 库,以便 1.10.0 排在……之后 1.9.0。在任何内容进入 Channel 之前,先过一遍检查清单:

  1. 确认 bundle 已签名。
  2. 核对目标 Channel 是否符合预期。
  3. 对比原生与 bundle 的兼容性范围。
  4. 先向小范围用户发布。
  5. 关注失败信号,并随时准备回滚。

类型化的更新流水线会把发布策略变成评审人员和 CI 真正能检查的 code。

Capgo 的差分交付和 Channel 控制能很好地融入这一模式,其设备级可观测性还能让团队事后追踪采用情况或失败信号。关于事件埋点,请参阅 这份使用 Capgo 进行自定义事件追踪的指南.

签名密钥和管理员凭据应保存在服务器或 CI 系统中,而不是已发布的 App 里。在下次启动时应用更新,用一个故意被拒绝的 bundle 测试回滚,并用类型化结果记录每一次决策。这种组合让快速交付与规范的移动端发布控制兼得。

类型化监听器(Typed listeners)是让异步 API 值得信赖的关键。无论 callback 追踪的是屏幕方向,还是 Capgo 的更新事件,它在每个平台上都应收到相同的 payload 结构——而且应该由编译器来强制保证这一点。

interface UpdateEvent {\nversion: string;\nchannel: ‘beta’ | ‘production’;\navailable: boolean;\n}

类型 Listener = (payload: T) => void;

interface UpdateService {\naddListener(\nevent: ‘updateAvailable’,\ncallback: Listener"}, ): Promise<{ remove: () => Promise }> removeAllListeners(): Promise; }

此项 TypeScript API 示例 将事件名固定为字面量,并把回调绑定到带类型的 payload。你的编辑器会自动补全 version ,而且免费;编译器会拒绝任何期望不相关数据的回调。只需少量配置,每当 API 变化时都能受益。

想看看实际效果?观看演示:

安全注册监听器

在组件内保留订阅句柄,让清理保持显式。同样的模式可直接用于 Angular 生命周期钩子、React effects 和 Vue 的 mount 钩子,无需改动。

let orientationHandle: { remove: () => Promise } | undefined;

async function start() { orientationHandle = await ScreenOrientation.addListener( 'screenOrientationChange', ({ type, angle }) => { console.log(type, angle); }, ); }

async function stop() {\nawait orientationHandle?.remove();\norientationHandle = undefined;\n}

在页面消失时执行清理,而不只是在整个 App 关闭时。忽略这一步,页面跳转后回调仍会挂在原生事件源上,最终导致重复工作和过期的状态更新,排查起来非常痛苦。

每个框架都提供了对应的钩子:

  • Angular — 从……触发清理 ngOnDestroy
  • React — 从……返回异步安全的清理函数 useEffect
  • Vue — 在……中移除订阅 onBeforeUnmount

每次 addListener 调用都应该有对应的移除路径。

选择正确的清理方法

当一个组件拥有单个订阅时,返回 handle 是最佳选择。 removeAllListeners() 当一个 service 持有多个监听器并需要完全重置时,这种方式表现出色。

async function resetUpdates(service: UpdateService) {\nawait service.removeAllListeners();\n}

当其他页面仍依赖该服务时,不要在共享组件里触发全局方法。如果所有权在本地,就继续使用单独的 remove() 句柄。

场景 建议操作
单个组件订阅 调用 handle.remove()
服务关闭 调用 removeAllListeners()
重复注册 守卫初始化
未知 payload 使用前校验

对于 Capgo 通知,请将更新 payload 与设备事件分开处理。然后分别测试注册、送达和清理 —— Capgo 自定义事件追踪指南 在集成方面有更多内容。

发布前,请检查三件事:卸载时是否真的移除了 handler、被拒绝的 promise 是否被捕获,以及回调是否可能更新已销毁的组件。这种规范能让基于 Angular、React 和 Vue 的响应式 Capacitor 应用保持流畅。

一名专业的软件开发人员戴着耳机,在双显示器环境下开发 code。

一个构建良好的 TypeScript API 示例 应从能表达意图的命名开始。方法用动词,接口用名词,并沿用一致的后缀,例如 Options, Result,以及 Event。清晰的命名能缩短 onboarding 时间,因为开发者无需打开实现代码就能理解契约。

保持公共接口精简。通过职责明确的方法暴露能力,而不是把关系松散的操作都堆到一个对象上。

  • getStatus() 读取状态。
  • updateConfig(options) 更改配置。
  • addListener(event, callback) 订阅变更。

精确定义输入与输出类型

当参数可能增加时,请使用命名选项接口:

interface PublishOptions { channel: ‘beta’ | ‘production’; rolloutPercent: number; }

interface PublishResult { version: string; accepted: boolean; }

async function publish( options: PublishOptions, ): Promise { return client.publish(options); }

当 API 封装不同的 payload 但需要保留其具体类型时,泛型才真正发挥作用:

interface ApiResponse { data: T; requestId: string; }

async function request(path: string): Promise<ApiResponse> { return fetchJson<ApiResponse>(path); }

但别为了显得灵活而滥用泛型。泛型应表达输入与输出之间的真实关系——否则,具体的 interface 反而更易读、更易维护。

让无效状态难以表示,尤其是在原生、网络和更新边界处。

紧挨着契约记录行为。涵盖权限、单位、被拒绝的 promise、可选字段,以及方法是否立即生效或在下一次启动时生效。行内注释应解释决策,而非复述方法名。

组织 Code 以应对变更

将类型、客户端逻辑、平台适配器和测试分离到可预测的文件中。从一个入口点导出公共类型,并保持实现细节私有。

关注点 推荐位置
公共接口 types.ts
API 方法 client.ts
Native 适配器 platform/
兼容性测试 tests/

对于破坏性的插件变更,引入新的主版本接口或兼容层,暂时保留已弃用的方法,并记录迁移步骤。 了解更多 API 版本策略 在更改调用方之前。

在发布前,在 CI 中运行严格的类型检查和契约测试。对于 Capgo 工作流,把 channel 值、Native 兼容性、已签名 bundle 和回滚行为作为类型化发布规则来验证——这样随着团队、平台和集成增长,快速更新也能保持可控。

如何为动态 Native 结果定义类型?

不要让 any 当 Native 方法返回不可预测的数据时,不要让其泄露到你的 code 中。相反,应明确列出你可以依赖的字段,并用 ?标记真正可选的值,并在下游逻辑触达之前,在边界处清洗不确定的输入。

interface NativeResult {\nsuccess: boolean;\nvalue?: string;\n}

async function readValue(): Promise { const result = await NativePlugin.read(); return { success: Boolean(result.success), value: typeof result.value === ‘string’ ? result.value : undefined, }; }

这种方法在让调用方保持安全的同时,在类型本身中明确表达了不确定性。若要更广泛地了解此接口模式,请回顾 使用 TypeScript 构建 API 的指南.

监听器如何避免未处理的 rejection?

异步回调在设计上必须具有防御性。应在监听器内部捕获失败,而不是依赖事件系统静默地吞掉被拒绝的 Promise。

const handleUpdate = (event: UpdateEvent): void => { void applyUpdate(event).catch((error: unknown) => { console.error('Update failed', error); }); };

保留订阅引用,并在组件卸载时移除它。这样可以避免重复回调和过期的状态更新——监听器生命周期一节会详细讲解。

每个异步监听器都需要错误处理路径和清理路径。

如何保护 Capgo 更新?

签名密钥和管理凭据只留在你的服务器或 CI 系统中。绝无例外。客户端只应接收已签名的 bundle,并用类型化结果来显示状态——绝不能用来创建签名。

发布之前,请设置独立的 channel 联合类型,执行兼容性检查,配置 rollout 限制,并规划好回滚路径。 Capgo 为 Capacitor 和 Electron 应用处理签名分发、channel 控制、下次启动时应用以及回滚保护。其文档展示了类型化发布工作流如何让你的更新 pipeline 更严谨。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。