Build your own Scalable Flutter plugin

Florian DUHEN
norsys-octogone
Published in
6 min readOct 20, 2021

If you have to develop a Flutter plugin, you may have to use some platform-specific APIs.
Flutter grows fast, and is now available on six different platforms.
How can a single team (person?) be able to handle properly six different platforms flawlessly ?

Almost impossible (Unless you’ve got plenty of free time!)

For this reason, your plugin should follow the Federated plugins implementation in order to ensure the scalability and availability of your plugin on the widest range of platforms possible.

In this story, I’ll take as an example the plugin url_launcher (A Flutter plugin for launching a URL which supports iOS, Android, web, Windows, macOS, and Linux)

Plugin architecture overview

The target architecture of your plugin should look like the following

| -- packages/
| | -- plugin_platform_interface/
| | -- app_facing_package/
| | -- plugin_specific_platform/ *Optional*
| | -- plugin_specific_platform2/ *Optional*
|
README.md
CONTRIBUTING.md
...

And the connection between each package can be represented with the following scheme

I strongly advise you to come back to this diagram at each step, it’ll help you understand how things are connected to each other.

I’ll explain more in depth what should be implemented in each package.

Plugin’s Platform interface package

The package that glues the app-facing packing to the platform package(s). This package declares an interface that any platform package must implement to support the app-facing package.
Having a single package that defines this interface ensures that all platform packages implement the same functionality in a uniform way.

The Platform Interface Package is the interface of your plugin, and it’ll ensure that all of its implementations will have the same signature.

In this package, you’ll write down the Platform Interface that should be extended in all the platform implementations.

Once this is done, you’ll create a class extending your Platform Interface, targeting your “main” platform target (in this example, the Mobile platform)

What would my platform interface package look like?

In this package, you should

1 Implement the plugin_platform_interface package under the dependencies of your pubspec.yaml

2Create your Platform interface and expose an instance of it so it can be called later

https://github.com/flutter/plugins/blob/master/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart

3Define all the methods that the facing package should (and will) implement

https://github.com/flutter/plugins/blob/master/packages/url_launcher/url_launcher_platform_interface/lib/url_launcher_platform_interface.dart

4Create a class extending the Platform Interface created at Step 2 and 3.
Since our main target in the Mobile, we’ll override the methods of the Platform Interface and invoke some MethodChannels that we’ll implement later.
These methods will be called by the facing package we’ll see next.

https://github.com/flutter/plugins/blob/master/packages/url_launcher/url_launcher_platform_interface/lib/method_channel_url_launcher.dart

So right now, your Plugin “ID Card” is written.
You now have to write the native code linked to the MethodChannels you declared for your main Platform Target (here Mobile)

Plugin’s App-Facing Package

The package that plugin users depend on to use the plugin. This package specifies the API used by the Flutter app.

Now that your Platform Interface is written and your MethodChannels are defined, it’s time to implement it.
That is the job of the App-Facing Package

This package should contain all the code relative to the main target of your plugin : in the case of the url_launcher plugin, this package will contain the Android and iOS implementations of the defined MethodChannels

This is the package which will be implemented by the end users in their app in order to use your plugin !

What should YOU do in your App-facing package ?

In this package, your should

1Add the platform_interface created right before to the dependencies of your pubspec.yaml (here url_launcher_platform_interface) and define the classes which will be holding the native implementations of your code

https://github.com/flutter/plugins/blob/master/packages/url_launcher/url_launcher/pubspec.yaml

2Define all the methods which will be called by your end user, and redirect their call toward the Instance of your Platform Package (See Step 2 of What should YOU do in your platform interface package ?)

Note that you can either directly call the Platform Instance (like in the method closeWebView()) or work on the datas first before calling the Platform Instance (like in the method launch()).
This is the point of this class.

3- Implement your Method Channels in the native parts of your code (here on Android and iOS)

👍👍👍 You now have a plugin which can be implemented on Android and iOS, congratulations ! 😄

“But now, I’d like to open my plugin to another platform, the Web for example, and I don’t know how to do it”

That’s the whole point of this article, and it leads us to the final part

Plugin’s Platform ‘specific’ packages

One or more packages that contain the platform-specific implementation code. The app-facing package calls into these packages — they aren’t included into an app, unless they contain platform-specific functionality accessible to the end user.

Since the Platform Interface is a separated package, anyone can implement it and write his implementation for a platform which isn’t supported yet.

It means that someone who knows a lot more in Web Development than you can implement your Platform Interface, write down the OS-specific code, and submit a pull-request to reference his implementation in your App-Facing Package

What should be found in a Platform Specific Package ??

In these packages, your should

1As presented in the App-facing package, you must add the platform_interface you want to implement to the dependencies of your pubspec.yaml (here url_launcher_platform_interface) and define the class which will be holding the implementation of the code

https://github.com/flutter/plugins/blob/master/packages/url_launcher/url_launcher_web/pubspec.yaml

2 Follow steps 2 and 3 of “What should YOU do in your app-facing package ?” : the goal here is the very same, and therefore the process to follow is also the same

3 Publish your package, and submit a pull-request in the app-facing package owner in order to reference your plugin

https://github.com/flutter/plugins/blob/master/packages/url_launcher/url_launcher/pubspec.yaml

Et voilà !
You or someone else added a Web-Support to your Mobile plugin without impacting any of your code.

What about the end user ?

Things are way easier for the end user since he doesn’t have anything specific to do !

Once a platform specific package is added to the app-facing package, the end-user will only have to upgrade it’s dependencies and won’t have anything else to do !

Conclusion

Following this implementation, you successfully developed a Plugin which can be extended on a new platform by anyone.

This structure should be used in any of your plugins projects, even if you don’t plan to open it to anybody else : it keeps things well organized and will help you a lot when you’ll add your unit tests !

If you want the whole backstory and reflexion behind this implementation, I strongly advise you to read this document which helped me fully understand the objective of the Federated Plugins.

Opening

There are a lot more things to say about this subject, but I tried my best to keep it short and easy to follow.
I strongly advise you to fully read the Federated Plugin Implementation article in the sources below, it’ll fully cover all of the points I’ve omitted in this document.

Sources

- The Federated Plugin Implementation which explains more in depth the pros and cons of this model
- The url_launcher source code (and many other projects from Google)
- The official flutter.dev doc

Thank you if you reached this far in this article ! 😍
I hope that it’ll help you fully understand how stuff works in the amazing Flutter’s world.

I’m Florian DUHEN, mobile developer and a Flutter enthusiast.
You can find me on Github and StackOverflow
I work in a French company, Norsys, which can be followed on LinkedIn and Twitter.

Feel free to ask any question or add any note in the comment section, I’ll do my best to answer it all.

--

--