Migrating Cordova Plugins to Capacitor (Android)
Cordova has a huge ecosystem of existing plugins that have been created over the past decade. Capacitor has its own method for allowing developers to create plugins, for themselves or for the community in general, but this ecosystem is still in its infancy as Capacitor is a relatively new project. It will take some time before Capacitor plugins are as prolific as their Cordova counterparts, which is why it is fortunate that we can still use Cordova plugins in Capacitor.
This means that, in general, you won't need to give up access to the plugins you want to use if you move to Capacitor. Most of the time, installing a Cordova plugin in Capacitor is as simple as running:
npm install name-of-plugin
and then running:
npx cap sync
To pull that plugin into your native Capacitor projects. However, that is not always the case. There are some Cordova plugins that just won't work in Capacitor, and some that will require additional manual configuration before they work. This tutorial will explore how Capacitor utilises Cordova plugins, and how we can attempt to migrate Cordova plugins that don't just work out of the box.
WARNING: The purpose of this tutorial is to serve as a deep dive into how a Cordova plugin is utilised by Capacitor and, through understanding this process, how we can attempt to configure plugins correctly for Capacitor. It goes into a lot of technical detail, and if you're only interested in getting the cordova-plugin-facebook4
plugin up and running you might find it frustrating. I have a much more brief tutorial that covers setting up cordova-plugin-facebook4
in Capacitor here: Using Cordova Plugins that Require Install Variables with Capacitor.
Outline
1. Cordova Plugins that are Incompatible with Capacitor
Before we get into the main portion of this tutorial, it is important to note that there is a list of known plugins that do not work with Capacitor. In some cases Capacitor provides its own way to achieve the functionality already, and sometimes there are other reasons the plugin doesn't work. You can find a list of these incompatible plugins here: known incompatible Cordova plugins. Keep in mind that this is not necessarily an exhaustive list of all incompatible plugins.
2. Cordova Plugins that Require Additional Configuration
This will be the main focus of this tutorial: Cordova plugins that don't work out of the box, but can be made to work with some additional configuration. The trick is to figure out what needs to be done to configure the plugin correctly, which can be difficult to do if you don't really know how it works behind the scenes.
The basic principles behind how Cordova plugins and Capacitor plugins work are the same. They both have code that runs in the native iOS or Android projects, and allow communication between your application running in the web view and the rest of the native code, such that your application can send requests for native functionality and receive results.
This is why Capacitor is able to utilise Cordova plugins, because the idea is fundamentally the same. Capacitor can just take the same native files that the Cordova plugin is using and add them to the Capacitor project.
One of the key differences between Cordova and Capacitor is that Cordova takes more of an abstracted approach, where things are configured through Cordova. Capacitor takes a more simplistic approach where things are generally configured directly in the native projects. This means that there are a lot of things happening in "Cordova-land" for a plugin to work outside of the native files for the plugin, and that is going to need to be translated to work in the native projects that Capacitor creates for us (either by us, or by Capacitor itself).
The plugin.xml File
The plugin.xml
file that Cordova plugins use is the key to getting everything correctly configured for Capacitor. The plugin.xml
file serves as a sort of road map as to how the plugin should be installed and configured in a Cordova project. Capacitor will look at this file and interpret it the best it can in order to set up the plugin in Capacitor as well. Most of the time this works just fine.
Sometimes, however, it might not work. This is especially the case when you want to use a Cordova plugin that makes use of install variables that look like this:
cordova plugin add cordova-plugin-facebook4 --variable APP_ID="123456789" --variable APP_NAME="myApplication"
Capacitor doesn't have a mechanism to supply variables like this when installing a plugin. By understanding how the plugin.xml
file works, we can see what sort of configurations need to be added to our native projects, and if there is anything that Capacitor hasn't been able to add automatically we can attempt to do it ourselves.
We will use the cordova-plugin-facebook4
plugin as an example to see how Capacitor treats the plugin.xml
file. This tutorial will focus specifically on Android.
NOTE: To really solidify these concepts, you might find it useful to set up your own Capacitor project and follow along in Android Studio. It is also helpful to have the source code for the cordova-plugin-facebook4
plugin to reference on GitHub, and even the source code for Capacitor as well.
Example Cordova/Capacitor Plugin Migration: Facebook (cordova-plugin-facebook4)
Let's try to get a complete picture of what is happening when we install a Cordova plugin in a Capacitor project, and we will talk about how to tackle the manual configuration we need to do along the way.
Consider the cordova-plugin-facebook4 plugin that is used to access the Facebook SDK in Cordova projects (and with the techniques we will cover in this tutorial... Capacitor projects too). Most of the functionality for this plugin is contained within the src/ios and src/android folders. It is in these folders that the native code to make the Facebook SDK work for both iOS and Android is contained, therefore you will find a bunch of Objective-C and Java code.
For the sake of this tutorial, it is not important to understand what is going on in these files (nor is it ever, generally, if you are just using the plugin). The purpose of the code in these files is to call various methods of the Facebook SDK and expose them to the application through Cordova (or in our case, Capacitor).
So, these files are probably important for Capacitor to pull into the project if we want to make use of the plugin. What happens to them?
We could go ahead and install the plugin in a Capacitor project to find out by running the following commands:
npm install cordova-plugin-facebook4
npx cap sync
NOTE: Keep an eye out for warnings when you run the npx cap sync
command, as it may give hints as to additional configurations you will need to add to the native projects.
If we inspect the native Android project inside of our Capacitor project we would find that the ConnectPlugin.java
file that was inside of the src/android folder of the plugin is now located at:
capacitor-cordova-android-plugins/src/main/java/org.apachce.cordova.facebook/ConnectPlugin.java
Great! The native file to make this functionality work has been set up by Capacitor automatically. But we're not quite done. This Cordova plugin does more than just what is contained in that file, there is still additional configurations that Cordova performs by following instructions in the plugin.xml
file that we talked about. Therefore, there is more Capacitor is going to have to do as well.
Let's take a look at that now, and how the plugin.xml
file plays into getting the plugin set up for usage in Capacitor. As I mentioned before, understanding the plugin.xml
file is the key to understanding how a plugin needs to be set up in Capacitor.
Although there is a bit more to the plugin.xml
, we will just be focusing on the Android portion of the plugin.xml
file, which is contained within the <platform name="android">
tag:
plugin.xml
<platform name="android">
<js-module src="www/facebook-native.js" name="FacebookConnectPlugin">
<clobbers target="facebookConnectPlugin" />
</js-module>
<config-file target="res/xml/config.xml" parent="/*">
<feature name="FacebookConnectPlugin">
<param name="android-package" value="org.apache.cordova.facebook.ConnectPlugin" />
<param name="onload" value="true" />
</feature>
<access origin="https://m.facebook.com" />
<access origin="https://graph.facebook.com" />
<access origin="https://api.facebook.com" />
<access origin="https://*.fbcdn.net" />
<access origin="https://*.akamaihd.net" />
<preference name="android-minSdkVersion" value="15" />
</config-file>
<source-file src="src/android/facebookconnect.xml" target-dir="res/values" />
<!-- Used for cordova-android 6 -->
<config-file target="res/values/facebookconnect.xml" parent="/*">
<string name="fb_app_id">$APP_ID</string>
<string name="fb_app_name">$APP_NAME</string>
<bool name="fb_hybrid_app_events">$FACEBOOK_HYBRID_APP_EVENTS</bool>
</config-file>
<!-- Used for cordova-android 7 -->
<config-file target="app/src/main/res/values/facebookconnect.xml" parent="/*">
<string name="fb_app_id">$APP_ID</string>
<string name="fb_app_name">$APP_NAME</string>
<bool name="fb_hybrid_app_events">$FACEBOOK_HYBRID_APP_EVENTS</bool>
</config-file>
<config-file target="AndroidManifest.xml" parent="application">
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/fb_app_id"/>
<meta-data android:name="com.facebook.sdk.ApplicationName" android:value="@string/fb_app_name" />
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/fb_app_name" />
</config-file>
<framework src="com.facebook.android:facebook-android-sdk:$FACEBOOK_ANDROID_SDK_VERSION"/>
<!-- cordova plugin src files -->
<source-file src="src/android/ConnectPlugin.java" target-dir="src/org/apache/cordova/facebook" />
</platform>
There are a few different types of tags present here:
<js-module>
<config-file>
<source-file>
<framework>
Each of these contain instructions on how the native platforms should be configured. A lot of this will be performed by Capacitor for us automatically, but not everything can be handled for us. Let's see how Capacitor treats this file.
First, we have the <js-module>
section:
<js-module src="www/facebook-native.js" name="FacebookConnectPlugin">
<clobbers target="facebookConnectPlugin" />
</js-module>
The src
indicates the JavaScript file in the cordova-plugin-facebook4
plugin that we are working in, in this case the one located at www/facebook-native.js
, that will be loaded by the browser to export the methods that the plugin makes available to the application. This file exports a bunch of methods like: getLoginStatus
, showDialog
, login
, logout
, and so on. These are the methods that we would call from within our application to access the native functionality. A clobbers
target of facebookConnectPlugin
here means that these methods would be made available under the window.facebookConnectPlugin
namespace. This means that within our application we would be able to make a call to window.facebookConnectPlugin.getLoginStatus()
to access the functionality.
This is how <js-module>
is used by Cordova, but how does Capacitor handle this instruction?
There are a few things that go on behind the scenes, but in short, Capacitor will:
- Create its own
cordova_plugins.js
file that defines a list of all of the Cordova plugins being used, and each plugin entry will contain a reference to the JavaScript file that needs to be loaded (e.g.facebook-native.js
) - This list is then loaded in the
cordova.js
file, and prepared for export by theJSExport.java
file - Capacitor's
Bridge.java
file (which is the "main engine" of Capacitor) will then use itsJSInjector
to inject the necessary JavaScript files for the plugin directly into the web view for use by the app.
In the end, we have more or less the same result without having to perform any configuration ourselves. Capacitor will take that facebook-native.js
file that exports all of the methods we can use to integrate with the Facebook SDK, and inject it into the web view which will make it available to our application.
Let's move on to the next section:
<config-file target="res/xml/config.xml" parent="/*">
<feature name="FacebookConnectPlugin">
<param name="android-package" value="org.apache.cordova.facebook.ConnectPlugin" />
<param name="onload" value="true" />
</feature>
<access origin="https://m.facebook.com" />
<access origin="https://graph.facebook.com" />
<access origin="https://api.facebook.com" />
<access origin="https://*.fbcdn.net" />
<access origin="https://*.akamaihd.net" />
<preference name="android-minSdkVersion" value="15" />
</config-file>
This section wants to add some configurations to the res/xml/config.xml
file. The way in which Capacitor will handle this is to look for any config-file
that has a target that includes config.xml
in its name and it will add the configurations to it's own config.xml
file located at app/src/main/res/xml/config.xml
in the native Android project. The result will look like this:
<?xml version='1.0' encoding='utf-8'?>
<widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<access origin="*" />
<feature name="FacebookConnectPlugin">
<param name="android-package" value="org.apache.cordova.facebook.ConnectPlugin"/>
<param name="onload" value="true"/>
</feature>
</widget>
Notice that only the <feature>
entries get copied over. This is where it is useful to understand this process in detail. Now we can clearly see something that is being left out when Capacitor tries to use this plugin. If this is something required to make the plugin work, we could now investigate configuring our native project to also include these additional configurations. In this case, I don't think it will make a difference as the default Capacitor config.xml
file already sets a wildcard access origin: <access origin="*">
and the minSdkVersion
is already higher than 15
.
If there were a <preference>
there that we did need to set, we could set that manually in the capacitor.config.json
file by adding a preferences
object to capacitor.config.json
. For example, if we did need to set android-minSdkVersion
to 15
we could do it like this:
{
"appId": "com.joshmorony.myapp",
"appName": "myapp",
"bundledWebRuntime": false,
"npmClient": "npm",
"webDir": "www",
"plugins": {
"SplashScreen": {
"launchShowDuration": 0
}
},
"cordova": {
"preferences": {
"android-minSdkVersion": "15"
}
}
}
The config.xml
file would then end up looking like this:
<?xml version='1.0' encoding='utf-8'?>
<widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<access origin="*" />
<feature name="FacebookConnectPlugin">
<param name="android-package" value="org.apache.cordova.facebook.ConnectPlugin"/>
<param name="onload" value="true"/>
</feature>
<preference name="android-minSdkVersion" value="15" />
</widget>
The end result is again similar here, but it's important to keep in mind that the Cordova plugin's plugin.xml
file can't control what happens in Capacitor directly. In this sense, even though this particular result ends up at res/xml/config.xml
, if the target
specified a different file path it wouldn't make a difference to Capacitor (any that have config.xml
in the target
will get added to this same file, any that don't will be ignored).
NOTE: Capacitor will also look for <config-file>
entries with a target of AndroidManifest.xml
and add any configurations supplied there to the AndroidManifest.xml
file that is automatically created at capacitor-cordova-android-plugins/src/main/AndroidManifest.xml
. This file will automatically be merged with any other AndroidManifest.xml
files from other modules in the project (including the main manifest file at app/src/main/AndroidManifest.xml
).
Still with me? Let's keep diving.
The next few sections looks like this:
<source-file src="src/android/facebookconnect.xml" target-dir="res/values" />
<!-- Used for cordova-android 6 -->
<config-file target="res/values/facebookconnect.xml" parent="/*">
<string name="fb_app_id">$APP_ID</string>
<string name="fb_app_name">$APP_NAME</string>
<bool name="fb_hybrid_app_events">$FACEBOOK_HYBRID_APP_EVENTS</bool>
</config-file>
<!-- Used for cordova-android 7 -->
<config-file target="app/src/main/res/values/facebookconnect.xml" parent="/*">
<string name="fb_app_id">$APP_ID</string>
<string name="fb_app_name">$APP_NAME</string>
<bool name="fb_hybrid_app_events">$FACEBOOK_HYBRID_APP_EVENTS</bool>
</config-file>
This should be interesting because now we are encountering those Cordova install variables, in this case:
$APP_ID
$APP_NAME
$FACEBOOK_HYBRID_APP_EVENTS
This doesn't mean much to Capacitor, in fact, you will soon see that all of the above achieves absolutely nothing for us.
The source-file
entry in Cordova-land points to a file in the plugin that should be executed. In this case, it wants to copy the facebookconnect.xml
file to the res/values
directory. It then uses the config-file
entries to target the file that was just created and set up some strings/variables inside of it for the application to use. Again, that is what is happening with Cordova, but how does Capacitor handle this?
Capacitor will actually copy this file into our native Android project at capacitor-cordova-android-plugins/src/main/res/values/facebookconnect.xml
but the result will look like this:
<?xml version='1.0' encoding='utf-8'?>
<resources>
</resources>
When what the plugin.xml
file wanted to do was this:
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="fb_app_id">$APP_ID</string>
<string name="fb_app_name">$APP_NAME</string>
<bool name="fb_hybrid_app_events">$FACEBOOK_HYBRID_APP_EVENTS</bool>
</resources>
NOTE: Cordova would also replace $APP_ID
, $APP_NAME
, and $FACEBOOK_HYBRID_APP_EVENTS
with the install variables supplied when running the install command.
Remember that the following two <config-file>
entries don't contain config.xml
in the target
so they will be ignored by Capacitor. The end result is that we have a file with no resource definitions, which is absolutely useless to us.
This is fine, though, because it doesn't do any harm either. However, we do need those <string>
and <bool>
entries defined for this plugin. It would be wise at this point to take a peek at the native code for the plugin (i.e. ConnectPlugin.java
) and see if and where it is making use of these variables. If the native code is making use of these variables then you definitely want to make sure that they are defined.
It is common to see native Android code making use of these strings and booleans by referencing getResources()
. It is also common for Android native code to make use of the <preference>
values supplied by referencing getSharedPreferences()
. It can be a good idea to search through the native .java
files the plugin uses to see if they are expecting these values to be defined anywhere.
In this case, ConnectPlugin.java
isn't making use of the variables, but rather it is some additional configuration that we will be adding to AndroidManifest.xml
in the next step that makes use of the variables. This means that we don't need to define these variables, as we could just supply the values manually instead of using @string/fb_app_id
in the AndroidManifest.xml
. However, I think it is nicer to define the variables, and it is safer to just do this in general since sometimes the native code will be making use of these values (or if not now, maybe an update of the plugin will - best to interfere with things as little as possible).
Defining these variables manually in the native Android project is simple enough, if you open app/src/main/res/values/strings.xml
you will find a file like the following:
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="app_name">myapp</string>
<string name="title_activity_main">myapp</string>
<string name="package_name">com.joshmorony.myapp</string>
<string name="custom_url_scheme">com.joshmorony.myapp</string>
</resources>
These values can be referenced throughout the native Android project. We can just add the values required for the Facebook plugin to this file. I don't think the $FACEBOOK_HYBRID_APP_EVENTS
variable is actually used anywhere by the plugin, but we will add it anyway:
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="app_name">facebooktest</string>
<string name="title_activity_main">facebooktest</string>
<string name="package_name">com.joshmorony.facebooktest</string>
<string name="custom_url_scheme">com.joshmorony.facebooktest</string>
<string name="fb_app_id">123</string>
<string name="fb_app_name">myapp</string>
<bool name="fb_hybrid_app_events">true</bool>
</resources>
Let's move on to the next section:
<config-file target="AndroidManifest.xml" parent="application">
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/fb_app_id"/>
<meta-data android:name="com.facebook.sdk.ApplicationName" android:value="@string/fb_app_name" />
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/fb_app_name" />
</config-file>
We have another <config-file>
and, again, this one does not include config.xml
in its target
. However, since it has a target
of AndroidManifest.xml
it will merge all of these values:
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/fb_app_id"/>
<meta-data android:name="com.facebook.sdk.ApplicationName" android:value="@string/fb_app_name" />
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/fb_app_name" />
Into the AndroidManifest.xml
within the capacitor-cordova-android-plugins
module (along with the configurations for any other plugins that target AndroidManifest.xml
) and then those values will be merged with the Android projects main AndroidManifest.xml
file. Notice that the <meta-data>
and <activity>
tags that will be added to the manifest reference those <string>
variables that we just added to strings.xml
.
If you didn't set up those variables, you would need to manually add these <meta-data>
and <activity>
tags to the AndroidManifest.xml
file and supply the fb_app_id
and fb_app_name
strings manually rather than referencing @string/fb_app_id
and @string/fb_app_name
. This is why it is often beneficial to set up those variables in strings.xml
rather than replacing values manually.
Just a couple more lines left to take a look at now:
<framework src="com.facebook.android:facebook-android-sdk:$FACEBOOK_ANDROID_SDK_VERSION"/>
This is a tag that we haven't dealt with yet, and it is also trying to make use of a $FACEBOOK_ANDROID_SDK_VERSION
Cordova install variable. As a result of this line, Capacitor will add the following inside of the capacitor.build.gradle
file under dependencies:
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation "com.facebook.android:facebook-android-sdk:5.13.0"
}
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}
You can see above that implementation "com.facebook.android:facebook-android-sdk:5.13.0"
has been added automatically after installing this plugin. But, wait a minute... how did it know to replace $FACEBOOK_ANDROID_SDK_VERSION
with 5.13.0
?
If we look a little further up the plugin.xml
file (outside of the <platform name="android">
section) we would find some additional preferences being defined:
<preference name="APP_ID" />
<preference name="APP_NAME" />
<preference name="FACEBOOK_HYBRID_APP_EVENTS" default="false" />
<preference name="FACEBOOK_ANDROID_SDK_VERSION" default="5.13.0"/>
Notice that a preference for FACEBOOK_ANDROID_SDK_VERSION
is supplied, with a default value of 5.13.0
. Capacitor will create a preferences array from all of the preference
tags listed in plugin.xml
. It will then loop through all of those preferences, and when creating the framework string that is added to capacitor.build.gradle
:
implementation "com.facebook.android:facebook-android-sdk:$FACEBOOK_ANDROID_SDK_VERSION
Capacitor will use a regular expression to find the $
variable syntax being used here, and replace it with the default value of the preference for FACEBOOK_ANDROID_SDK_VERSION
that was found in the plugin.xml
file (if that preference exists). Since there is a preference defined for FACEBOOK_ANDROID_SDK_VERSION
in the plugins plugin.xml
file, the string will be modified to be:
implementation "com.facebook.android:facebook-android-sdk:5.13.0
Before replacing $FACEBOOK_ANDROID_SDK_VERSION
with the default value listed in the preference, it will first check to see if there is an entry in the native Android variables.gradle
file for FACEBOOK_ANDROID_SDK_VERSION
. If there is, e.g:
ext {
minSdkVersion = 21
compileSdkVersion = 29
targetSdkVersion = 29
androidxAppCompatVersion = '1.1.0'
androidxCoreVersion = '1.2.0'
androidxMaterialVersion = '1.1.0-rc02'
androidxBrowserVersion = '1.2.0'
androidxLocalbroadcastmanagerVersion = '1.0.0'
androidxExifInterfaceVersion = '1.2.0'
firebaseMessagingVersion = '20.1.2'
playServicesLocationVersion = '17.0.0'
junitVersion = '4.12'
androidxJunitVersion = '1.1.1'
androidxEspressoCoreVersion = '3.2.0'
cordovaAndroidVersion = '7.0.0'
FACEBOOK_ANDROID_SDK_VERSION = '5.10.0'
}
Capacitor will instead leave $FACEBOOK_ANDROID_SDK_VERSION
as it is in capacitor.build.gradle
and whatever value is listed in variables.gradle
will be used when the application is built.
There are situations where this happens (a $VARIABLE
gets copied literally over into the native project) and Capacitor doesn't have special logic to substitute a value where the $
syntax exists. Again, this is where it is important to understand how this whole process works because you will be able to see where this is happening, and hopefully, find a way to override that value manually in the native project. For example, in another plugin I migrated to Capacitor, it tried to use some Cordova install variables to set some <preference>
tags:
<preference name="keyHash" value="$KEY_HASH" />
However, this was just copied literally into the config.xml
file as $KEY_HASH
. This meant when the native plugin tried to make use of the key hash value, it literally used the string value "$KEY_HASH"
. In order to overwrite this dodgy preference, I was able to just supply the actual value using the capacitor.config.json
file:
{
"appId": "com.joshmorony.myapp",
"appName": "myapp",
"bundledWebRuntime": false,
"npmClient": "npm",
"webDir": "www",
"plugins": {
"SplashScreen": {
"launchShowDuration": 0
}
},
"cordova": {
"preferences": {
"keyHash": "aabbccdd"
}
}
}
This resulted in both being defined in config.xml
, but the Capacitor one took precedence:
<preference name="keyHash" value="$KEY_HASH" />
<preference name="keyHash" value="aabbccdd" />
This brings us to the final line of the plugin.xml
file for cordova-plugin-facebook4
which is:
<source-file src="src/android/ConnectPlugin.java" target-dir="src/org/apache/cordova/facebook" />
We have already had a peek of the result of this at the beginning when we searched our native Android project for where those native files were added.
Capacitor will use these source-file
entries to determine what native files for the plugin need to be pulled over to the Capacitor project. In this case, it will place the ConnectPlugin.java
file inside of the src/main/java
folder, e.g:
capacitor-cordova-android-plugins/src/main/java/org.apachce.cordova.facebook/ConnectPlugin.java
If the native file has an extension of .aidl
instead of .java
it will be placed inside of a aidl
folder instead of java
.
Summary
The techniques I have covered in this tutorial will likely make it possible to migrate most Cordova plugins that require install variables to Capacitor. I haven't met one that I haven't been able to port over yet, but I also haven't tried all that many. Likely, there will be some gotchas in some plugins depending on the way that they are designed.
If all else fails, you could create a fork of the Cordova plugin, and there is also the option to build your own Capacitor plugin. I know it is appealing to be able to just install whatever functionality you need with a single command, but that comes with risk. There are lots of well maintained plugins to use, but there are many more abandoned plugins. This was a big problem with Cordova and it will be with Capacitor as well: relying on community created plugins without the ability to fix/maintain them yourself. The more niche the functionality you are implementing, the more likely you are to find a plugin that hasn't been updated in 3 years but it's your only option... unless you learn to build plugins yourself.
The difference with Capacitor, I think, is that the plugin creation process is more friendly. A lot of the time, you don't really even need to know much about the native code. You can generally find examples for iOS or Android of whatever functionality you want, copy those into your native projects, and set up a Capacitor plugin to make a call to it. You now have full control over the native code in your project. If the plugin breaks in the future, you don't need to open issues on an abandoned GitHub repository, you can Google X not working in iOS 18.1
and update the native code directly yourself with the fix. Of course, the more you do this the more you will start to feel comfortable with the native side of things as well.