Creating a Flutter Plugin | Dialog Box

What is the Flutter plugin?

Flutter plugin is the wrapper of the native code like android( Kotlin or java) and iOS(swift or objective c).

For the plugin we need to write android and ios specific code, We can either user Kotlin or Java for Android and swift or objective-c for iOS.

Flutter can do anything that a native application can through the use of Platform Channels and Message Passing.

Flutter instructs the native iOS/Android code to perform an action and returns the result to Dart.

Flutter Directory Structure

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 an ios directory. These contain the iOS and the Android hosts, these native projects that will run the compiled Dart.

To introduce communication, all we need is to create a Platform Channel, such as MethodChannel, in both the Dart and the host(Android and iOS).

MethodChannel is used to communicate the native code of android and iOS to flutter (dart code).

This is the basic understanding of the flutter plugin now let’s see why plugins are required.

Why Plugin Required?

Flutter does not support many of thing like geolocation, payment SDK, video calling SDK etc and if we want to use these kinds of thing in the flutter project, so we have to write our own plugin in the native code Android and iOS.

Creating your own plugin:

Before creating your own plugin you should check whether there is already any plugin exist or not.

These are the following steps to create a plugin:

Open the android studio got to File>> New >> New flutter project.

Click on the New flutter project >>Select the Flutter plugin option.

Set name of the plugin :

In this, I have created a Dialog Box plugin because flutter does not support Dialog box.

Flutter Directory Structure

By default, this looks like a flutter project we have one Android folder one example folder and one iOS folder and one lib folder

We also have one ore folder that is an example.

In this example folder, we also have another flutter code where we can test our flutter plugin within an app.

Now if you see the file under project_name -> lib, you will find the default code as

import 'dart:async';
import 'package:flutter/services.dart';
class FlutterAlertDemo {
static const MethodChannel _channel =
const MethodChannel('flutter_alert_demo');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
}

So we have a property that platformVersion which is asking _channel to invoke one method which is getting platform version which is defined in Android as well as in iOS and from (‘getPlatformVersion) we are getting the version and we are returning this version to our flutter project.

This version will get from the static get method initPlatformState() in the main.dart file inside the example directory

Above code will be communicated with the native code that you will write in Android and iOS files.

Android Native code(java code):

You will find this code in the Android section (project_name -> android)

package adhoc.successive.com.flutteralertdemo;
import android.app.Activity;
import android.app.Dialog;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/** FlutterAlertDemoPlugin */
public class FlutterAlertDemoPlugin implements MethodCallHandler {
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_alert_demo");
channel.setMethodCallHandler(new FlutterAlertDemoPlugin());
}
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else {
result.notImplemented();
}
}
}

FlutterAlertDemoPlugin class implements the MethodCallHandler so we have to @override onMethodCall method.

( project_name -> ios)

iOS Native code(swift code):

import Flutter
import UIKit
public class SwiftFlutterAlertDemoPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "flutter_alert_demo", binaryMessenger: registrar.messenger())
let instance = SwiftFlutterAlertDemoPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
result("iOS " + UIDevice.current.systemVersion)
}
}

Now we will write platform specific code

Android Native code(project_name -> android -> src):

iOS Native code(project_name -> iOS -> Classes):

The above two code files of android and ios are ready now we need to implement our invoke method in the file under (project_name -> lib).

As we want to invoke the method that will return the output( in our case we will receive all the images).

Now we will make a static method to show dialog box

In the lib folder, we have dialog_box_plugin dart file we will make a static method to show dialog box.

static get showAlertDialog async {
await _channel.invokeMethod('showAlertDialog');
}

Dart file (project_name -> lib):

import 'dart:async';
import 'package:flutter/services.dart';
class FlutterAlertDemo {
static const MethodChannel _channel =
const MethodChannel('flutter_alert_demo');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
static get showAleartDialog async {
await _channel.invokeMethod('showAlertDialog');
}
}

Now, your first plugin is ready to use.

So how we will test whether our app plugin is working or not?

Go to the folder example/lib, you will find a main.dart file with the default code as follows:

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_gallery_plugin/flutter_gallery_plugin.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
@override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await FlutterGalleryPlugin.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
),
);
}
}

Now you can change this file according to your need

In my case I need to show the dialog box so

FlutterAlertDemo.showAleartDialog();

Example code(project_name -> example -> lib):

Here are some Screenshots of output:

Android:

iOS:

How to publish plugin:

These are the following command to publish plugin into https://pub.dartlang.org/

flutter packages pub publish--dry-run
flutter packages pub publish

Thanks for reading this article ❤

If I got something wrong? Let me in the comments. I would love to improve.

Clap 👏 If this article helps you.

Connect with me on LinkedIn.

Check my GitHub repositories.

Follow me on Twitter.