Flutter: Writing platform specific code on macOS
Implementing method channels on macOS
Since its first stable version in 2018, Flutter has evolved so much, including support of multiple platforms such as Web, Windows, Linux, and macOS (there's even support for Risk V Architectures!)
When using Flutter, you'll write mostly code in the Dart language. This means you cannot access native platform functionalities (except if you are using ffigen or jnigen). Despite the fact you have a lot of libraries on pub.dev covering most of your needs in terms of accessing native platform functionalities (Android storage, connectivity status, etc...) you'll probably need some time to write your platform-specific code to handle some tasks. Fortunately, Flutter provides an API to do that. These are called platform channels.
I recently needed to write platform code for a pet project and realized there was no resource in the documentation about how to do this on macOS. So in this article, we are going to learn how to write platform-specific code for a macOS Application.
For this tutorial, we will write a simple macOS app. The app will show information about the device battery such as the time left, the current capacity, and whether it is charging or not.
So first, we will create a new Flutter application. Since we are targeting macOS only, we will uncheck the other platforms
Our project is now created. Next, we will write the Dart part of your code. We will create a DeviceBatteryChannel that will handle our calls to the native APIs:
Full file: device_battery_channel.dart
What's happening here
We created a class to handle our calls to native APIs. In this class we defined a Method Channel named
com.stevenosse.battery/device_battery. This class defines three methods that will effectively handle our calls. Let's dive into our first method,
In this method, we are invoking the
getBatteryLevel method from our Method Channel without any parameter.
Our native code will be written in Swift.
The code we need to accomplish our task was copied and pasted from this answer on StackOverflow.
See mom, I'm a real programmer 🥰
We will now set up our method call handler. To do this, we will override the
applicationDidFinishLaunching method from our
So here we implemented our method and initiated our method channel. We will need to implement a method call handler (that will handle invocation from our Dart code). Here is what it looks like for our
What's happening here ?
When a call on
getBatteryLevel is received, we use our
InternalFinder class. We will first check whether the device has an internal battery or not, and then get the current charge of the battery and return the result.
The full source code of this app is available here: https://github.com/stevenosse/battery
I wanted to make things the simplest in this article to make it easy to understand. However, we could go further by using Pigeon. Pigeon is a generator tool to make communication between Flutter and the host platform type-safe, easier and faster, it's developed by the Flutter team.
Thank you for reading.
Did you find this article valuable?
Support Steve Nosse by becoming a sponsor. Any amount is appreciated!