capacitor icon indicating copy to clipboard operation
capacitor copied to clipboard

feat: plugin method with callback and custom return type

Open matthiasschwarz opened this issue 3 years ago • 0 comments

Feature Request

Description

I want to be able to have a custom return type with a plugin method that has a callback. According to the documentation about plugin method types the return type is a string which represents the callback id, but i want to be able to change this type when i don't need the callback id. For my use case i want to call a method which runs a task and gives status updates about it via the callback, after some time the task is expected to finish with a result which i want to receive via the resolved promise.

Platform(s)

Android

Preferred Solution

@CapacitorPlugin(name = "Example")
public class ExamplePlugin extends Plugin {
    @PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
    public void example(PluginCall call) {
        String v = call.getString("v");
        call.setKeepAlive(true);
        call.resolve(new JSObject().put("n", 1));
        call.resolve(new JSObject().put("n", 2));
        call.resolve(new JSObject().put("n", 3));
        call.setKeepAlive(false);
        call.resolve(new JSObject().put("i", 42).put("r", v));
    }
}

I would expect when i set keep alive to true to return values via the callback and when i set it again to false the promise is resolved with my custom type.

Alternatives

@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK_WITH_PROMISE)
public void example(PluginCall call) {/* ... */}

Introduce a new method type which could be called RETURN_CALLBACK_WITH_PROMISE to allow a custom return type in the promise.

Additional Context

Web

On the web this is already possible:

import { WebPlugin } from "@capacitor/core";

interface ExampleOptions {
  v: string
}

interface ExampleCallbackValue {
  n: number
}

type ExampleCallback = (value: ExampleCallbackValue) => void;

interface ExampleReturnValue {
  i: number,
  r: string
}

interface ExamplePlugin {
  example(options: ExampleOptions, callback: ExampleCallback): Promise<ExampleReturnValue>;
}

export class ExampleWeb
  extends WebPlugin
  implements ExamplePlugin
{
  async example(options: ExampleOptions, callback: ExampleCallback): Promise<ExampleReturnValue> {
    return new Promise(resolve => {
      callback({ n: 1 });
      callback({ n: 2 });
      callback({ n: 3 });
      resolve({ i: 42, r: options.v })
    });
  }
}

Calling the example method with the following code:

Example.example({ v: "foo" }, (value: ExampleCallbackValue) => console.log("callback", value))
          .then((value: ExampleReturnValue) => console.log("resolved", value));

Prints the expected behaviour into the console:

web console output

Android

The preferred solution currently passes the object in the last call.resolve() after setting keep alive to false to the callback.

android console output

matthiasschwarz avatar May 15 '22 12:05 matthiasschwarz