Mastering Flutter: Create a plugin

This story starts when one of your clients or a designer asks you to implement a feature that can be done using native APIs but it has not included on Flutter yet.

The first thing that you try to do a little search on, someone has been in my situation and has developed a package to resolve this situation and has been kind enough to share it with the community. But unfortunately you don’t find anything that solves your problem, you have only one solution left: TO CREATE A PLUGIN.

But wait, first we should tell you what is a plugin. There are two types of packages in the Flutter ecosystem: 

  • Dart packages: general packages with only dart code (e.g. the path package)
  • Plugin packages: special packages that combine native code with a dart interface and allow you to use platform-specific code (e.g. the url_launcher package)

So…let’s do a plugin

If you’re using Android Studio you can go under File -> New -> New Flutter Project… and then select Flutter Plugin

You can also create a plugin using the command line:
flutter create --template=plugin

You can also specify the platform for which you want to develop the plugin and the language you will use 

flutter create --org com.example --template=plugin --platforms=android,ios -I swift -a kotlin flutter_is_awesome

This will create a plugin called flutter_is_awesome with the iOS part in Swift and the Android part in Kotlin.

We will create a plugin that will show the system contacts picker.

Plugin Anatomy

This is what will be created:

We have:

  • The android folder: we will put all the Android specific code here.
  • The iOS folder: the same as above, but for iOS.
  • The lib folder: this folder will contain all the Dart part of the plugin, that will be invoked by the application.
  • The test folder: Here you will develop the tests for your plugin.
  • The example folder: An application that imports our package as dependency, you can use this to try out the plugin without importing it in another app.

The plugin uses a a channel called MethodChannel to communicate between the Dart part and the native part, it’s like a tunnel where the dart part sends messages and the native part listen to those messages and react to them. It can be used also to send messages from the native part to the dart part, but this will not be covered in this article.

Our plugin will have just one function that will show the native contacts picker, let the user choose one contact, and return the name of the contact selected to the user. 

In this example we will return a simple string to the Dart part, but you can return more complex data structures using for example a map, or a list, you can find the list of the data type supported by the plugins here.

Now that we’ve created the plugin and defined what it will do we need to do those those things:

  • Write the Android part of the plugin
  • Write the iOS part of the plugin
  • Write the dart part of the plugin

Android Code

When the plugin has been created the default class has been generated, it contains two methods: onAttachedToEngine and onMethodCall. The first one is called when the plugin is initialized, it creates the channel of communication with the dart part and begins to listen to the channel for messages. The second is invoked whenever there’s a new message in the channel; it has 2 parameters: call which contains the details of the invocation (the method and eventual parameters) and result that will be used to send the result back to the dart part.

Let’s define some variable for our plugin that will be use later

Now we need to implement the ActivityAware and PluginRegistry.ActivityResultListener protocols, we need those to retrieve the activity that will be used to show our contact picker.

The only part that’s missing is the code to show the contacts picker and retrieve the result. In our onMethodCall start the activity to choose a contact and in onActivityResult retrieve the result and send it to the dart part using the result object that we’ve previously saved.

The Android part is done! ✅ 

iOS Code

The iOS part will be very similar to the Android one, here we have the register function, which is the equivalent of the onAttachedToEngine that we’ve seen for Android, and the handle function, that will be called when new messages will arrive.

Now we need to create a new class ContactPickerDelegate that will receive the callback of the contacts picker view controller (when a contact is selected or when the picker is dismissed) and will inform the plugin class. It has 2 blocks variable onSelectContact and onCancelthat will be invoked  when the picker will inform this class with the CNContactPickerDelegate protocol.

What we need to do now is to display the contacts picker when the getAContact message is received, so let’s add this to the plugin class:

The iOS part is done! ✅ 

Dart Code

The last piece of the puzzle 🧩 is to create the Dart part of the plugin that will glue all the other pieces toghether.

As you can see it’s very simple, it invokes the method getAContact on the channel and waits for the result and returns it. Note that all the functions that interact with the native part are asynchronous and will return a Future.

Now we only need to test out our plugin, we’ve done a simple app in the example folder, with just one button and a label to test out if everything is working fine.

And here’s the final result:


You can find the final code of the plugin at this GitHub link.

What we’ve developed here is a basic example that returns just a string to the dart part but, as said before you could return a more complex data structure and you can also pass parameters to the native part when calling the invokeMethod functions.
The things that you can do with the plugins are almost infinite, we’ve just scratched the surface, the limit is your imagination.