Flutter is a portable UI kit from Google which lets developers build native applications for mobile and web from a single codebase. It’s used to build Android and iOS apps, as well as being the primary language for creating applications on Google Fuchsia.
When it comes to cross-platform development languages, such as Flutter and React-Native, accessing native features such as camera, Bluetooth or third-party functionality requires a bit of “hacking”. For native features, we can use the plugins, but for third-party systems we need to write our own package.
Selecting which method to go with depends entirely on the way the third party works.
Dart Packages: These use the Dart programming language and contain Flutter-specific functionality; meaning that the packages are completely reliant on the Flutter framework.
Plugin Packages: These packages contain an API written in Dart, combined with platform-specific implementation for Android and iOS, which use Java, Kotlin, Objective-C or Swift.
Plugin packages are not hard to write, Flutter provides a sample for getting a platform’s version as a guideline. Flutter is able to do almost anything that a native app can do through the use of Platform Channels and Message Passing.
The flow is Flutter instructing the native iOS/Android code to perform an action and then waiting to get the result back to Dart. In the directory structure of a Flutter app, you’d notice that along with the lib directory which contains Dart code, there is also an Android and iOS directory.
These contain the iOS and Android codebases, which are native projects that will run the compiled Dart code. By using the MethodChannel, we can establish communication between the Flutter (Dart) and the native Android/iOS code.
In this folder, we can also see the example Flutter code where we can test our Flutter plugin within an app.
Start a Flutter project->Flutter Plugin and set the name and package of the plugin you want to create. Android Studio will generate an example plugin for you. This plugin retrieves the platform’s version and displays it within the interface. Let’s go step-by-step and see what every file does. In the flutter_plugin.dart file of the lib folder:
We first need to create a MethodChannel variable, which will allow us to communicate with the native code. The initialisation of the MethodChannel requires a name, be careful and make sure that name is the same on the native Android/iOS code, which is located in representative folders (e.g., for Android will be android->src->main->your_package_name->flutter_plugin).
The get platformVersion is an async method that calls MethodChannel’s invokeMethod. This method call will trigger the onMethodCall on the native code. On the onMethodCall function we need to handle the “getPlatformVersion” method, by implementing its functionality and returning the result of it. Notice, the result variable should be the same type of the return value on the get platformVersion on flutter_plugin.dart.
We return only standard types of variables on the result.success, we could also return custom variables but we would have to implement the variable in native (Android or iOS) and Flutter (Dart) code in order to be able to parse the custom variable. After we have created the link between the Flutter and the native code, we can use this functionality on the example app. The main.dart file of the example folder:
import ‘package:flutter/services.dart’; //Import the plugin
In order for the app to know which page is being read or on what state (enabled/disabled) Alexa is, we need a way to send these signals/messages to the app. The best way, to our knowledge, was to use the PubNub API.
Despite the fact that they support so many languages, they do not, as of yet, support Flutter. So we have to implement that functionality, either by writing a Dart SDK or we could use the Android/iOS SDK as a Flutter plugin. Due to time constraints and because the SDKs are very robust and reliable, we choose to make a Flutter Plugin.
Initially, we need to create an example plugin that Android studio generates (we can then delete the unwanted functionality) with the name PubNubPlugin. Moreover, we will need to publish, subscribe and use a secret key in order to initialise the PubNub channel. We can do that through the PubNub website under a free account. In the PubNub dashboard we can then create an app.
The first step is to import the PubNub SDK for Android projects (at this point we need to say that during this week, we were focused mainly on the Android platform, but we will implement the iOS plugin, too). You can import the SDK in the same way as we would do that if the app was native, on the build.gradle of the Android folder.
implementation group: ‘com.pubnub’, name: ‘pubnub-gson’, version: ‘4.22.0-beta’ //We need Gson, to parse the json objects
// We used this joda, for the timestamps of the messages but that is optional
So far we have implemented the native Android functions, now we have to link them with Flutter code. In order to do that we will use the onMethodCall function on PubnubPlugin.java.
@Override public void onMethodCall(MethodCall call, Result result)
And because we will need to send messages and the status of PubNub on the Flutter app, we will need to create EventChannel objects that will carry those messages. Some of you may think, why are we not using the result.success to pass the result back to the Flutter app? The reason being that the result.success can be called only once, but we will retrieve many messages.
In the pubnub_plugin.dart we will need to call PubnubPlugin.java’s methods using the MethodChannel.
Implementing plugins is crucial for ensuring your app will be available on production, because otherwise mobile app developers will have to reinvent the wheel by implementing the same API in native Dart code, which is both time and money intensive.
Other frameworks such as React-Native and PhoneGap have a similar framework for writing plugins, so any developer that has cross-platform experience will find it simple and easy to develop a Flutter plugin.
Published on May 22, 2019, last updated on May 24, 2019