Capacitor Web/PWA 插件指南
Capacitor 利用了一个 Web/原生兼容层,使得构建在原生运行以及以 PWA 方式在 Web 上运行时都具有功能的插件变得容易。
开始入门
首先,按照插件指南的入门部分中所示生成一个插件。
接下来,在您选择的编辑器中打开 echo/src/web.ts。
示例
Capacitor Web 插件的基本结构如下所示:
import { WebPlugin } from '@capacitor/core';
import type { EchoPlugin } from './definitions';
export class EchoWeb extends WebPlugin implements EchoPlugin {
async echo(options: { value: string }) {
console.log('ECHO', options);
return options;
}
}
EchoPlugin 接口定义了您插件的方法签名。在 TypeScript 中,我们可以确保 Web 实现(EchoWeb 类)正确地实现了该接口。
权限
如果您的插件在 Web 上的功能需要最终用户的权限,那么您需要实现权限模式。
别名
您需要开发一个或多 个别名来抽象和分组您的插件所需的权限。这些别名用于传达权限状态。默认情况下,别名可以处于以下状态之一:
granted:此别名中的所有权限已被最终用户授予(或不需要提示)。denied:此别名中的一个或多个权限已被最终用户拒绝。prompt:应该提示最终用户授予权限,因为既未授予也未拒绝。prompt-with-rationale:最终用户之前拒绝过权限,但尚未阻止提示。
这些由从 @capacitor/core 导出的 PermissionState 类型表示。
如果需要,也可以为别名定义自定义状态。例如,官方的 Camera 插件 还为 camera 和 photos 别名定义了 limited 状态。
别名是跨平台的,因此在决定插件的别名时,请务必考虑 iOS、Android 和 Web 的权限。
权限状态定义
在 src/definitions.ts 中,从 Capacitor 导入 PermissionState 并定义一个 PermissionStatus 接口,该接口以您定义的别名作为键,表示插件中权限的状态。
在下面的示例中,权限状态可以完全由一个 location 别名表示,它可以是 granted、denied 等。
import type { PermissionState } from '@capacitor/core';
export interface PermissionStatus {
// TODO:将 'location' 改为您实际别名的名称!
location: PermissionState;
}
然后,在插件接口中添加 checkPermissions() 和 requestPermissions() 的定义。这两个方法都将返回由 PermissionStatus 定义的插件中权限的当前状态。
export interface EchoPlugin {
echo(options: { value: string }): Promise<{ value: string }>;
+ checkPermissions(): Promise<PermissionStatus>;
+ requestPermissions(): Promise<PermissionStatus>;
}
因为这些方法已添加到您的插件接口中,所以必须在您的插件支持的所有平台上实现它们。
实现权限
在 src/web.ts 中,将 checkPermissions() 和 requestPermissions() 方法添加到您的 Web 实现中。
+import { PermissionStatus } from './definitions';
export class EchoWeb extends WebPlugin implements EchoPlugin {
async echo(options: { value: string }) {
...
}
+ async checkPermissions(): Promise<PermissionStatus> {
+ // 待实现
+ }
+ async requestPermissions(): Promise<PermissionStatus> {
+ // 待实现
+ }
}
checkPermissions()
此方法应返回插件中权限的当前状态。这些信息可能直接在特定的 Web API 上可用,或通过 Permissions API 获得。
记住,当使用浏览器支持不稳定的 Web API(如 Permissions API)时,您应该实现特性检测,并在最终用户的浏览器不受支持时抛出适当的错误。
async checkPermissions(): Promise<PermissionStatus> {
+ if (typeof navigator === 'undefined' || !navigator.permissions) {
+ throw this.unavailable('此浏览器不支持 Permissions API。');
+ }
const permission = await navigator.permissions.query( ... );
// 待实现
}
requestPermissions()
此方法应提示最终用户授予使用您的插件所需的平台 API 的权限。然后,它应在提示后返回插件权限的新状态(就像 checkPermissions() 方法一样)。
在 Web 上,有时无法将权限请求与实际调用分离开来。例如,Geolocation API 仅在请求位置时才请求权限。对于这样的情况,我们建议抛出未实现的异常。
async requestPermissions(): Promise<PermissionStatus> {
// TODO:Web 是否支持为我的插件请求权限?
throw this.unimplemented('未在 Web 上实现。');
}
错误处理
Capacitor 的 Web 插件通常与一些尚未被某些浏览器采纳甚至尚未标准化的 API 一起工作。尽管如此,通常采用尽力而为的方式来实现 Web 插件,并在 API 不可用时优雅地失败。这就是为什么错误处理在 Web 上尤其重要!
不可用
应该抛出 此错误以指示该功能目前无法使用。
原因包括:
- 当前缺少先决条件,如网络连接。
- 需要已实现底层 API 的浏览器。
在下面的示例中,我们首先检查 navigator 上是否定义了 geolocation。如果没有,则意味着浏览器不支持 Geolocation,我们应该抛出"不可用"错误。否则,我们可以继续实现。
async getLocation(): Promise<Location> {
if (typeof navigator === 'undefined' || !navigator.geolocation) {
throw this.unavailable('此浏览器不支持 Geolocation API。');
}
// 待实现:实际的 Web 实现
}
未实现
可以抛出此错误以指示该功能尚未实现。您可以使用它来在 Web 上暂存方法以备后续实现,或使用它来指示该功能无法在某个特定平台上实现。
async getLocation(): Promise<Location> {
throw this.unimplemented('未在 Web 上实现。');
}