From 02bd6357435724a1ca0f33dd1cd4a476314af0a8 Mon Sep 17 00:00:00 2001 From: Martin Donadieu Date: Sun, 16 Aug 2026 15:30:12 +0300 Subject: [PATCH] docs(plugins): map return types to TypeScript method-types listed native return types but used `never`, which cannot be implemented in definitions.ts or web.ts. Co-authored-by: Cursor --- .../plugins/creating-plugins/android-guide.md | 2 +- docs/plugins/creating-plugins/ios-guide.md | 2 +- docs/plugins/creating-plugins/method-types.md | 34 +++++++++++++++++-- .../plugins/creating-plugins/android-guide.md | 2 +- .../plugins/creating-plugins/ios-guide.md | 2 +- .../plugins/creating-plugins/method-types.md | 34 +++++++++++++++++-- 6 files changed, 68 insertions(+), 8 deletions(-) diff --git a/docs/plugins/creating-plugins/android-guide.md b/docs/plugins/creating-plugins/android-guide.md index 92db9de2b..1044a91b3 100644 --- a/docs/plugins/creating-plugins/android-guide.md +++ b/docs/plugins/creating-plugins/android-guide.md @@ -29,7 +29,7 @@ After generating a plugin, right click the Java plugin class in Android Studio a ## Plugin Basics A Capacitor plugin for Android is a simple Java class that extends `com.getcapacitor.Plugin` and has a `@CapacitorPlugin()` annotation. -It has some methods with `@PluginMethod()` annotation that will be callable from JavaScript. +It has some methods with `@PluginMethod()` annotation that will be callable from JavaScript. See [Method Types](/plugins/method-types) for each return type and the matching TypeScript signature to declare in `src/definitions.ts`. Once your plugin is generated, you can start editing it by opening the file with the Plugin class name you choose on the generator. diff --git a/docs/plugins/creating-plugins/ios-guide.md b/docs/plugins/creating-plugins/ios-guide.md index 195fd218e..70cfd6096 100644 --- a/docs/plugins/creating-plugins/ios-guide.md +++ b/docs/plugins/creating-plugins/ios-guide.md @@ -145,7 +145,7 @@ public let pluginMethods: [CAPPluginMethod] = [ This makes the `echo` method available to the Capacitor web runtime, indicating to Capacitor that the echo method will return a Promise. -To add more methods to your plugin, create them in the `.swift` plugin class with the `@objc` before the `func` keyword and add a new `CAPPluginMethod` entry in the `pluginMethods` array. +To add more methods to your plugin, create them in the `.swift` plugin class with the `@objc` before the `func` keyword and add a new `CAPPluginMethod` entry in the `pluginMethods` array. See [Method Types](/plugins/method-types) for each `returnType` and the matching TypeScript signature to declare in `src/definitions.ts`. ## Permissions diff --git a/docs/plugins/creating-plugins/method-types.md b/docs/plugins/creating-plugins/method-types.md index 63cd19308..cf68d4d84 100644 --- a/docs/plugins/creating-plugins/method-types.md +++ b/docs/plugins/creating-plugins/method-types.md @@ -3,6 +3,7 @@ title: Method Types description: Capacitor Plugin Method Types contributors: - ikeith + - riderx sidebar_label: Method Types slug: /plugins/method-types --- @@ -11,6 +12,14 @@ slug: /plugins/method-types When developing plugins, there are three different types of method signatures that can be used. All are asynchronous and promise-based. +Declare the TypeScript signatures in `src/definitions.ts`. That interface is the contract for your web implementation (`src/web.ts`) and for app code. Android and iOS must use the matching native `returnType`. + +| TypeScript (`src/definitions.ts`) | Android | iOS | +| --------------------------------- | ------- | --- | +| `method1(): Promise` | `PluginMethod.RETURN_NONE` | `CAPPluginReturnNone` | +| `method2(): Promise` | `PluginMethod.RETURN_PROMISE` (default) | `CAPPluginReturnPromise` | +| `method3(callback: MyPluginCallback): Promise` | `PluginMethod.RETURN_CALLBACK` | `CAPPluginReturnCallback` | + Let's consider a plugin definition that includes all three types: ```typescript @@ -23,7 +32,7 @@ export interface MyData { export type MyPluginCallback = (message: MyData | null, err?: any) => void; export interface MyPlugin { - method1(): never; + method1(): Promise; method2(): Promise; method3(callback: MyPluginCallback): Promise; } @@ -31,7 +40,11 @@ export interface MyPlugin { ## Void Return -`method1()` is the simplest case that is expected to return no data. +`method1()` is the simplest case that is expected to return no data. In TypeScript, declare it as `Promise` so the web class can implement the interface and callers can `await` the method. Do not use `never`: a function typed as `never` cannot be implemented in `src/web.ts`. + +```typescript +method1(): Promise; +``` For android, you would annotate the method like this: @@ -57,10 +70,18 @@ CAP_PLUGIN(MyPlugin, "MyPlugin", ) ``` +Use `RETURN_NONE` / `CAPPluginReturnNone` when native should not keep a promise open. If the method returns no data but native should still `resolve()` or `reject()` when finished (for example `Toast.show()` or `Preferences.set()`), use the [promise return type](#value-return) instead and still declare `Promise` in TypeScript. + ## Value Return `method2()` is the most common case: A promise that resolves, usually with some value. +In TypeScript, declare a `Promise` of the value you resolve with. Use `Promise` when native calls `resolve()` with no payload. + +```typescript +method2(): Promise; +``` + For Android, this method type is the default and specifying the return type is optional: ```java @@ -89,6 +110,15 @@ CAP_PLUGIN(MyPlugin, "MyPlugin", `method3()` is the most complex type but also the least common in practice. It is used when your plugin needs to return data repeatedly, such as when monitoring the device's location via the geolocation API. +In TypeScript, the method takes a callback that native may invoke many times, and returns a `Promise` that resolves with a callback identifier: + +```typescript +export type CallbackID = string; +export type MyPluginCallback = (message: MyData | null, err?: any) => void; + +method3(callback: MyPluginCallback): Promise; +``` + For android, you would annotate the method like this: ```java diff --git a/versioned_docs/version-v8/plugins/creating-plugins/android-guide.md b/versioned_docs/version-v8/plugins/creating-plugins/android-guide.md index 92db9de2b..1044a91b3 100644 --- a/versioned_docs/version-v8/plugins/creating-plugins/android-guide.md +++ b/versioned_docs/version-v8/plugins/creating-plugins/android-guide.md @@ -29,7 +29,7 @@ After generating a plugin, right click the Java plugin class in Android Studio a ## Plugin Basics A Capacitor plugin for Android is a simple Java class that extends `com.getcapacitor.Plugin` and has a `@CapacitorPlugin()` annotation. -It has some methods with `@PluginMethod()` annotation that will be callable from JavaScript. +It has some methods with `@PluginMethod()` annotation that will be callable from JavaScript. See [Method Types](/plugins/method-types) for each return type and the matching TypeScript signature to declare in `src/definitions.ts`. Once your plugin is generated, you can start editing it by opening the file with the Plugin class name you choose on the generator. diff --git a/versioned_docs/version-v8/plugins/creating-plugins/ios-guide.md b/versioned_docs/version-v8/plugins/creating-plugins/ios-guide.md index 195fd218e..70cfd6096 100644 --- a/versioned_docs/version-v8/plugins/creating-plugins/ios-guide.md +++ b/versioned_docs/version-v8/plugins/creating-plugins/ios-guide.md @@ -145,7 +145,7 @@ public let pluginMethods: [CAPPluginMethod] = [ This makes the `echo` method available to the Capacitor web runtime, indicating to Capacitor that the echo method will return a Promise. -To add more methods to your plugin, create them in the `.swift` plugin class with the `@objc` before the `func` keyword and add a new `CAPPluginMethod` entry in the `pluginMethods` array. +To add more methods to your plugin, create them in the `.swift` plugin class with the `@objc` before the `func` keyword and add a new `CAPPluginMethod` entry in the `pluginMethods` array. See [Method Types](/plugins/method-types) for each `returnType` and the matching TypeScript signature to declare in `src/definitions.ts`. ## Permissions diff --git a/versioned_docs/version-v8/plugins/creating-plugins/method-types.md b/versioned_docs/version-v8/plugins/creating-plugins/method-types.md index 63cd19308..cf68d4d84 100644 --- a/versioned_docs/version-v8/plugins/creating-plugins/method-types.md +++ b/versioned_docs/version-v8/plugins/creating-plugins/method-types.md @@ -3,6 +3,7 @@ title: Method Types description: Capacitor Plugin Method Types contributors: - ikeith + - riderx sidebar_label: Method Types slug: /plugins/method-types --- @@ -11,6 +12,14 @@ slug: /plugins/method-types When developing plugins, there are three different types of method signatures that can be used. All are asynchronous and promise-based. +Declare the TypeScript signatures in `src/definitions.ts`. That interface is the contract for your web implementation (`src/web.ts`) and for app code. Android and iOS must use the matching native `returnType`. + +| TypeScript (`src/definitions.ts`) | Android | iOS | +| --------------------------------- | ------- | --- | +| `method1(): Promise` | `PluginMethod.RETURN_NONE` | `CAPPluginReturnNone` | +| `method2(): Promise` | `PluginMethod.RETURN_PROMISE` (default) | `CAPPluginReturnPromise` | +| `method3(callback: MyPluginCallback): Promise` | `PluginMethod.RETURN_CALLBACK` | `CAPPluginReturnCallback` | + Let's consider a plugin definition that includes all three types: ```typescript @@ -23,7 +32,7 @@ export interface MyData { export type MyPluginCallback = (message: MyData | null, err?: any) => void; export interface MyPlugin { - method1(): never; + method1(): Promise; method2(): Promise; method3(callback: MyPluginCallback): Promise; } @@ -31,7 +40,11 @@ export interface MyPlugin { ## Void Return -`method1()` is the simplest case that is expected to return no data. +`method1()` is the simplest case that is expected to return no data. In TypeScript, declare it as `Promise` so the web class can implement the interface and callers can `await` the method. Do not use `never`: a function typed as `never` cannot be implemented in `src/web.ts`. + +```typescript +method1(): Promise; +``` For android, you would annotate the method like this: @@ -57,10 +70,18 @@ CAP_PLUGIN(MyPlugin, "MyPlugin", ) ``` +Use `RETURN_NONE` / `CAPPluginReturnNone` when native should not keep a promise open. If the method returns no data but native should still `resolve()` or `reject()` when finished (for example `Toast.show()` or `Preferences.set()`), use the [promise return type](#value-return) instead and still declare `Promise` in TypeScript. + ## Value Return `method2()` is the most common case: A promise that resolves, usually with some value. +In TypeScript, declare a `Promise` of the value you resolve with. Use `Promise` when native calls `resolve()` with no payload. + +```typescript +method2(): Promise; +``` + For Android, this method type is the default and specifying the return type is optional: ```java @@ -89,6 +110,15 @@ CAP_PLUGIN(MyPlugin, "MyPlugin", `method3()` is the most complex type but also the least common in practice. It is used when your plugin needs to return data repeatedly, such as when monitoring the device's location via the geolocation API. +In TypeScript, the method takes a callback that native may invoke many times, and returns a `Promise` that resolves with a callback identifier: + +```typescript +export type CallbackID = string; +export type MyPluginCallback = (message: MyData | null, err?: any) => void; + +method3(callback: MyPluginCallback): Promise; +``` + For android, you would annotate the method like this: ```java