Hi all,
I just wanted to announce that I've been experimenting with a different
way of authoring Cordova plugins.
I don't really have anything to show right now, but looking to get some
abstract high-level feedback based on the idea.
This is more or less a preliminary start of a discussion so that I can
get some early feedback. The plan is to come back some time later with
a more official specification document and usable PoCs for both Android
& iOS platforms.
Privately I've been experimenting with a more closer "native" method
which I feel like solves several issues
with the way that cordova plugins are traditionally authored.
First I'll explain briefly the pains of authoring cordova plugins, and
then I'll explain a high level idea that will likely solve the problems.
Currently the plugins are authored by having a set of arbitrary source
files as defined by the <source-file> / <header-file> directives,
which also declares where these files should be copied to into the
cordova native app project. Additionally, if the plugin requires
changing resource files or adding additional configurations, they must
make use of several directives which may include:
- config-file
- edit-config
- resource-file
- lib-file
- framework
- source-file / header-file
- asset
Most of these works well enough, but shouldn't be necessary to begin
with. Others, are very finicky or are barely usable due to bugs or other
caveats (e.g. config-file and edit-config)
The second issue with the way that Cordova plugins are traditionally
authored (based on the Official Apache plugins) is that they
aren't unit testable. They can only really be tested as part of a real
cordova project, which we currently do via cordova-paramedic.
This is because there is a disconnect between the plugin sources and an
actual native project.
So I've been experimenting with authoring cordova plugins using a native
project that gets imported a cordova project. Right now
my experimentation has been exclusively with the Android platform, so
I'll be using more Android-specific examples.
But my experimentation has me building a cordova plugin that instead of
containing loose java source files, they contain an actual
Gradle project that builds an Android Library. This means that the
Cordova Plugin has it's own:
- Source files
- AndroidManifest
- resources
- Gradle configs & dependency management
With these tools at the plugin's author disposal... it should eliminate,
or mostly eliminate the need of the aforementioned directives:
- edit-config
Is no longer required to edit AndroidManifest.xml, but may still be
required to edit config.xml (but is there really a need to?). Instead
native libraries have their own AndroidManifest.xml which will get
merged with the App's manifest.
- lib-file
A native library can bundle their own lib-files.
- resource-file
A native library can bundle their own resource files.
- framework
A native library has it's own gradle file to manage frameworks/dependencies
- source-file / header-file
A native library has it's own file structure for their source files,
whether java or native C++ modules.
- config-file*
While won't be needed to edit AndroidManifest.xml for the same reason as
edit-config, which was a common use case...
It will still be required for setting up cordova Feature
tags/declarations which gets placed into `config.xml`.
- asset*
Untested, I'm not sure if assets will get merged in a way that is usable
by the app. So this directive may still be relevant.
Additionally, the js-module directive will still be relevant as the
native project has no concept of setting up the webview JS modules.
*To be clear*, I'm not suggesting that the current plugin.xml directives
to be deprecated or removed. They are still going
to be required to support any cordova plugin authored in a traditional
method. However, with the module method, most of these directives won't
be necessary to use.
In fact, I think the module method could continue to use any one of the
existing directives if they choose to, but in all likeliness, there
won't be a need to. In
practice we may want to discourage people to use the "legacy" directives
so that support could be considered to be dropped in the future.
I foresee a new directive being created to declare the "module"
directory, which is the root folder of a native project, which would
simply be copied in full to a directory inside the app project.
For example, the module format really needs 4 main actions to be done in
a cordova android project. I'll pretend that cordova-plugin-file is
authored in a module format containing a gradle project.
Cordova will need to:
1. Copy the cordova-plugin-file gradle project into a subdirectory (e.g.
/platforms/android/cdvModules/cordova-plugin-file)
2. settings.gradle needs a line to include the gradle project into it's
build system (e.g. include ":cdvModules:cordova-plugin-file")
3. The "app" module needs to depend on cordova-plugin-file (e.g:
implementation project(":cdvModules:cordova-plugin-file"))
4. Configure the JS-modules / config.xml "Feature" tags just like it
always did before.
Apache Cordova will still not be distributing prebuilt libraries (e.g.
plugins are not AAR or xcframeworks) but rather the complete module that
can be copied into a project as a module.
The module itself will contain all the build scripts and source code. I
believe this still satisfies Apache's Release policy requiring source
packages with no compiled code[1]. Of course,
third-party plugin authors can still utilize this method of authoring
plugins and still include closed sources or libraries if they choose so.
Lastly, now that the plugin has a native project housed, it will also be
much easier to unit test the native side. However there is one caveat
where e2e tests cannot be done as that will still require a real cordova
project,
so cordova-paramedic will still have to be used for e2e testing.
I do have a working example of this system I described for Android but I
still have lots of testing to do myself. Still, I feel very confident
that this is major improvements to how plugins are authored, which
hopefully will encourage well written and well tested plugins, as well
as reducing
the need for plugin authors to manipulate the app's resource files,
which can often result in conflicts.
Moving forward I'd be continuing to experiment with both the Android &
iOS platforms, preparing proof of concept repositories as well as a
specification document for a lower level detailed
of what implementation may look like, which can then be further
reviewed/commented.
Looking forward for any comments, questions, or concerns.
Cheers,
Norman
References:
[1] https://www.apache.org/legal/release-policy.html#source-packages