See how Capacitor fits into the entire Ionic Ecosystem ->
Capacitor is part of the Ionic Ecosystem ->

Updating Capacitor to 3.0 in your plugin

There are several required and recommended changes for plugins that are being updated to Capacitor 3.

🚧 This guide is a work-in-progress. Thanks for your patience!

Planning for a Core API

It is currently difficult for the core team to make changes to the internals of Capacitor without potentially affecting plugins. Because most classes and methods in Capacitor 2 are public for both iOS and Android, we have observed undesired usage of Capacitor APIs that we considered internal.

During Capacitor 3 development, we will be evaluating this problem and creating an official public API for plugins, which will be documented here.


Use the new @CapacitorPlugin annotation

The @NativePlugin annotation is deprecated. We now recommend using the new @CapacitorPlugin annotation, which will allow for the new permissions API.

The name and requestCodes attributes are the same. The permissionRequestCode attribute is removed. The permissions attribute will need to be replaced with list of @Permission annotations, each containing a list of manifest strings and their corresponding alias, which you can omit for now until the new permissions API is implemented in your plugin.

     name = "FooBar",
     requestCodes = {
-    permissionRequestCode = FooBarPlugin.REQUEST_ALL_PERMISSIONS,
-    permissions = { Manifest.permission.FOO, Manifest.permission.BAR }
+    permissions = {
+        @Permission(strings = { Manifest.permission.FOO }, alias = "foo"),
+        @Permission(strings = { Manifest.permission.BAR }, alias = "bar")
+    })
 public class FooBarPlugin extends Plugin {
     static final int REQUEST_SOME_METHOD = 10051;
     static final int REQUEST_SOME_OTHER_METHOD = 10052;



Changes to PluginCall & CAPPluginCall

Use resolve() and reject()

We believe resolve() and reject() better reflect the Promise-like flow intended for plugin methods. They should be preferred over success() and error() (now deprecated), even in callback-style plugin methods.

resolve() without arguments now resolves with undefined

Previously, calling resolve() with no arguments resulted in an empty object being sent to the JavaScript layer. Because this is unlike the behavior of JavaScript’s Promise.resolve(), as of Capacitor 3, undefined is sent instead.



Evaluate error handling

We are now recommending that plugin authors make use of the new error codes in Capacitor 3:

  • Unavailable: indicates the functionality can’t be used right now
  • Unimplemented: indicates the functionality can’t or won’t be implemented, or may be implemented in the future

Read more about Error Handling for Web, iOS, and Android.

Adopting the new Permissions API

Prior to 3.0, it was expected that permissions were automatically requested by a plugin before feature use. For example, a Geolocation plugin would automatically request permission when the user location was requested for the first time and then continue appropriately if the permission was granted or denied.

One goal of Capacitor 3 is to give app developers the ability to request or check permissions at any time and control how and when the user prompts are presented. This provides more flexibility in the user experience by allowing the app to respond to the user’s choice in a variety of ways.

It is perfectly fine to continue automatically requesting permissions, but you are encouraged to adopt the new permissions pattern as well to give app developers control over permissions.

Learn how to implement the Permissions API in your plugin ›