Invoking native iOS code from Flutter using MethodChannels

Akshat Sharma
Flutter Clan
Published in
3 min readJun 30, 2021

During your Flutter development, you might come across this situation when you’ll have to communicate with native platform APIs. If there is already a package on pub.dev, you just got lucky but if there is no package available you’ll have to get into this communication between Flutter and native code.

Flutter uses a very flexible system to call platform-specific APIs. In this article, we’ll be setting up a communication channel between Flutter and iOS code. We’ll be fetching the current badge count on the App Icon. On the native side, this can be done by the following one-liner.

UIApplication.shared.applicationIconBadgeNumber

Our native iOS app will keep listening to a message during the app’s lifecycle. From our futter app we will send a message on this channel. The native listener will now catch hold of this message and will return the response after verifying the message details.

Let’s begin! Make sure to check out the article for setting up push notifications in flutter and the article for simulating push notifications on iOS simulators for playing around with badge counts.

In your widget let’s first create a channel for communication.

static const platform = const MethodChannel('method_channel.flutter.dev/appIconBadge');

The native and flutter sides of the channel are connected through a channel name passed in the constructor. For our example, we have given channel name method_channel.flutter.dev/appIconBadge.

Now we’ll be sending a message to the native side of the channel.

final int result = await platform.invokeMethod('getBadgeCount');

Now the name of the message getBadgeCount plays a very important role. If the native side has not implemented support for this message, the Flutter host will receive a PlatformExeption. Therefore it is advisable to use try-catch block while invoking to avoid crashes.

String badgeCount;    
try {
final int result = await platform.invokeMethod('getBadgeCount');
badgeCount = 'Badge count: $result';
} on PlatformException catch (e) {
badgeCount = "Failed to get badge count: '${e.message}'."; }

Let’s get into the native side code. Open AppDelegate.swift file present inside ios/Runner path.

In didFinishLaunchingWithOptions method, we’ll be adding a listener for method_channel.flutter.dev/appIconBadge channel.

let controller : FlutterViewController = window?.rootViewController as! FlutterViewControllerlet badgeChannel = FlutterMethodChannel(name: "method_channel.flutter.dev/appIconBadge", binaryMessenger: controller.binaryMessenger)

Now we’ll be adding the callback handler which will get executed whenever we callinvokeMethod from the flutter host.

badgeChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
// Note: this method is invoked on the UI thread.
guard call.method == "getBadgeCount" else {
result(FlutterMethodNotImplemented)
return
}
self?.receiveBadgeCount(result: result)
})

Here we first check that the message if the name of the message isgetBageCount or not. If it is something else we will return FlutterMethodNotImplemented. Once we have guarded our check, we will execute the desired function.

func receiveBadgeCount(result: FlutterResult) -> Void {  
result(UIApplication.shared.applicationIconBadgeNumber)
}

Once you’ll run your application, your flutter app and the native app will be communicating successfully.

You can find the code on Github. To test out different badge counts change the badge count in SamplePush.apns file and drag-drop it on the simulator. To learn about its functioning check out this article.

Here is a sneak peek.

Having done this, check out the article to publish a package based on the above-implemented functionality so that others can also use it.

Happy Coding!!

--

--