BY JOSH MORONY | LAST UPDATED: SEPTEMBER 02, 2020
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.
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=