How to create a Flutter Plugin from scratch
May 15, 2023 by Marvin

How to Create a Flutter Plugin from Scratch and integrate it into your App

What is a Flutter Plugin anyway?

Flutter Plugins provide the ability to use native device capabilities that are not available in standard Flutter apps. Common examples are camera access, payment SDK, location APIs and many more. There are already a lot of ready to use plugins available for developers: Flutter Plugins.

If there is no plugin available which helps you acquire the native functionality you need for your app or if you need to develop a Flutter Plugin as part of your product like we do, we have a solution. This article will serve you as a Flutter Plugin development tutorial on how to create a plugin by developing a plugin that will show an alert dialog.

Check out our Docutain SDK
Integrate high quality document scanning, text recognition and data extraction into your apps. It is also available as Flutter Plugin. To learn more about the Docutain SDK and its packages contact us at SDK@Docutain.com.

Prerequesites

Create a Flutter Plugin Project

Open Android Studio and go to File > New > New Flutter Project... to create a new Flutter project.

Ensure the Flutter SDK path leads to the installation location of the Flutter SDK, then click Next.

Android Flutter Plugin New Project

In the next screen you have several options to configure your Flutterplugin Project. Most importantly you have to select Plugin as the Project type.

Chose the Platforms and Android/iOS languages as you like. In this sample we checked Android and iOS as platforms and Kotlin and Swift as languages. Once you have selected the options you like, click Finish.

Android Flutter Plugin New Project

Once configuration is complete, the project tree should look similar to this flutter project structure:

Android Flutter Plugin project tree

The structure contains four important parts:

  • A folder lib that contains the interface of your plugin.
  • A folder for each platform (Android and iOS) that will contain the native implementation of your interface.
  • An example project that will show a sample integration of your plugin.

Implement the interface

We want to have a method showAlert which will show our alert dialog. In order to do this, go to lib > flutter_plugin_alert_platform_interface.dart and add the following code right after getPlatformVersion:

1
2
3
Future showAlert() {
    throw UnimplementedError('showAlert() has not been implemented.');
}

Now go to lib > flutter_plugin_alert_method_channel.dart and override this method with the following code:

1
2
3
4
@override
Future showAlert() async {
    return await methodChannel.invokeMethod('showAlert');
}

Now go to lib > flutter_plugin_alert.dart and add the following code:

1
2
3
Future showAlert() {
    return FlutterPluginAlertPlatform.instance.showAlert();
}

Implement the native code

Now that we have defined the interface of our showAlert method, it is time to implement the native Android and iOS code that will actually show the alert.

Assuming you know Android and iOS, and how programming works for them.

Android native code (Kotlin)

Go to android > src.main > kotlin > FlutterPluginAlertPlugin.

When you have opened the native Android class you will notice a lot of unresolved references (red lines). The project loads as a Flutter plugin, which causes this to happen.

If you like to write native Android code, select Open for Editing in Android Studio in the top right corner. The class will be updated and the Android classes will be fixed. This will allow you to start writing your own Android code.

Android Studio Flutter Open for editing

In order to show a native alert dialog, we make use of the class android.app.AlertDialog. To construct an AlertDialog we need to pass the current activity.

To find the current activity in a Flutter App, we can use the Flutter ActivityAware plugin. It overrides some methods to track the current activity. Inside the onMethodCall we need to check for our showAlert method call that we have defined in our interface.

Replace the whole content of FlutterPluginAlertPlugin with the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.example.flutter_plugin_alert

import android.app.AlertDialog
import android.content.DialogInterface
import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
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

/* FlutterPluginAlertPlugin */
class FlutterPluginAlertPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
    /// The MethodChannel that will the communication between Flutter and native Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private lateinit var channel : MethodChannel
    private var currentActivity: android.app.Activity? = null
    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_plugin_alert")
        channel.setMethodCallHandler(this)
    }

    override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
        when (call.method) {
            "getPlatformVersion" -> {
            result.success("Android ${ android.os.Build.VERSION.RELEASE}
)
    }
    "showAlert" -> {
        return currentActivity?.let {
            val builder = AlertDialog.Builder(it)
            builder.setTitle("Hello")
            builder.setMessage("I am a native alert dialog.")
                <.setPositiveButton(android.R.string.ok,
                DialogInterface.OnClickListener { dialog, id ->
            })
                builder.create().show()
                result.success(true)
            } ?: result.error("0", "Current activity null", "Can not show dialog because current activity is null.")
            }
            else -> {
                result.notImplemented()
            }
        }
    }
    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {

    channel.setMethodCallHandler(null)
    }
    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        currentActivity = binding.activity
    }
    override fun onDetachedFromActivityForConfigChanges() {
        currentActivity = null
    }
    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        currentActivity = binding.activity
    }
    override fun onDetachedFromActivity() {
        currentActivity = null
    }
}

iOS native code (Swift)

In iOS we use the class UIAlertController to show the alert dialog.

Go to iOS > Classes > SwiftFlutterPluginAlertPlugin.swift and replace the handle method with the following:

1
2
3
4
5
6
7
8
9
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    if(call.method == "getPlatformVersion"){
        result("iOS" + UIDevice.current.systemVersion)
    } else if(call.method == "showAlert"){
        let alert = UIAlertController(title: "Hello", message: "I am a native alert dialog.", preferredStyle: .alert);
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
        UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil);
    }
}

The plugin code is now ready to use. Let's see how to use it in our example project.

Test the Flutter plugin

Go to example > lib > main.dart. This is the code of the Flutter example app where we will show our alert dialog.

We keep it simple by adding a button to the screen that will show the alert dialog when clicked.

To do this, replace the content of the build Widget at the end of the class with the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@override
    Widget build(BuildContext context) {
        return MaterialApp(
            home: Scaffold(
                appBar: AppBar(
                    title: const Text('Plugin example app'),
                ),
                    body: Center(
                        child:  MaterialButton(onPressed: (){
                            FlutterPluginAlert().showAlert();
                    },color: Colors.green, child: const Text("Show Alert")
                ),
            ),
        ),
    );
}

You can now run the app. Once you click the button, the output should be the following:

Flutter Plugin iOS alert dialog
Flutter Plugin Android alert dialog

Check out our Docutain Flutter SDK
Integrate a high quality document scanner, text recognition and data extraction into your apps. It is also available as Flutter Plugin. To learn more about the Flutter Document Scanner SDK, check out our Developer Documentation for Flutter or contact us at SDK@Docutain.com.

Congratulations! You now know the basics of how to create Flutter plugin. If you enjoyed this Flutter tutorial we would appreciate you sharing it among your colleagues, partners and friends.


💡 Github Sample

Learn how to use a plugin in our Github sample Docutain SDK for Flutter.

Your contact to Docutain

Please tell our colleague Harry Beck how the Docutain SDK can help you with your project. We are looking forward to receiving your inquiry, either by telephone or contact form.