Flutter to Native Code

How to call native code from Flutter

Yudi Setiawan
Nov 2 · 8 min read

Pengenalan

Flutter yang merupakan salah satu teknologi yang memiliki kecanggihan di lintas platform sepertinya agak sedikit aneh jika mereka sendiri tidak menyediakan jalan bagi developer untuk bisa melakukan pemanggilan kode native dari Flutter. Seandainya Flutter tidak bisa memberi jalan bagi para developer untuk melakukan pemanggilan kode native dari Flutter lalu hal ini akan memunculkan pertanyaan besar bagi kita semua yaitu,



Dari pertanyaan tersebut saya memiliki 2 jawaban yang bisa saya tuliskan yaitu sebagai berikut.

  1. Bahwa teknologi lintas platform sebenarnya tidak akan bisa menyediakan jalan bagi para developer untuk melakukan pemanggilan kode native dikarenakan produk tersebut tidak memiliki kemampuan untuk berkomunikasi langsung ke kode native.
  2. Teknologi lintas platform seharusnya bisa menyediakan jalan bagi developer untuk memanggil kode native langsung. Karena seperti yang kita ketahui bahwa setiap platform seperti Android dan iOS memiliki fitur-fitur native yang terkadang di produk lintas platform tidak memiliki kemampuan untuk membuatnya sehingga jalan satu-satunya adalah kita harus menggunakan kode native untuk membuat fitur tersebut.

Lalu, pertanyaannya adalah



Jawabannya adalah bisa. Teknologi besutan Google ini tidak mungkin mereka tidak memikirkan masalah hal seperti ini. Karena, Google sendiri pun memiliki Android jadi, sudah pasti mereka akan memikirkan bagaimana jikalau Flutter dimasa yang akan datang ternyata tidak bisa memiliki fitur native di platform tertentu. Sudah pasti jalan satu-satunya adalah harus memanggil kode native-nya dari Flutter. Dan percaya nggak percaya ternyata selama ini beberapa plugin yang kita pakai di website pub.dev merupakan hasil komunikasi langsung dengan kode native. Berikut saya tunjukkan salah satu contoh plugin-nya.

Dan berikut gambaran kode untuk komunikasi dari Flutter ke native-nya.

Kode Dart — Deklarasi Method Channel dan ada melakukan pemanggilan method check di kode native
Kode native Android — Deklarasi Method Channel
Kode native Android — List method yang diterima oleh kode native dari Flutter

Perhatikan baik-baik pada gambaran kode diatas bahwa di Flutter untuk bisa berkomunikasi dengan kode native-nya kita menggunakan Platform Channel. Info lengkap mengenai apa itu Platform Channel bisa dibaca di link berikut.

Contoh 1

Pada contoh pertama ini kita akan mencoba membuat sebuah aplikasi sederhana yang akan memanggil fungsi dari kode native-nya dan kemudian hasil dari fungsi native tersebut akan kita tampilkan ke Flutter. Untuk langkah pertamanya silakan buat projek baru dan beri nama projeknya flutter_to_native_code. Untuk contoh kali ini kita pakai Kotlin dan Swift untuk kode native-nya.

Proses pembuatan projek Flutter

Lalu, kita buka file main.dart dan isikan dengan kode berikut.

import 'package:flutter/material.dart';

void main() => runApp(App());

class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyApp(),
);
}
}

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
String _message;

@override
void initState() {
_message = 'Hello Yudi Setiawan, from Flutter code';
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter to Native Code'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Tap Me'),
onPressed: () {
// TODO: do something in here
},
),
Text(_message),
],
),
),
);
}
}

Output dari kode tersebut adalah seperti berikut.

Output statik dari Contoh 1

Sekarang kita perlu mendeklarasikan objek MethodChannel seperti berikut.

class _MyAppState extends State<MyApp> {
static const platform = const MethodChannel('flutter.native.code/example');

...

flutter.native.code/example merupakan nama channel yang akan kita buat dan pastikan juga bahwa nama channel tersebut haruslah unik. Selanjutnya, kita ubah kode komentar // TODO: do something in here menjadi seperti berikut.

try {
_message = await platform.invokeMethod('greetingFromNativeCode');
} on PlatformException catch (e) {
_message = 'Failed to invoke: ${e.message}';
}
setState(() {});

Kode diatas berfungsi untuk mengirimkan trigger ke kode native bahwa si Flutter perlu memanggil method dengan nama greetingFromNativeCode . Sekarang coba jalankan ulang app-nya. Dan test tap button Tap Me. Yang terjadi ialah kita akan mendapatkan pesan error seperti berikut.

Pesan error bahwa method di kode native tidak tersedia

Pesan error tersebut mengatakan bahwa method dengan nama greetingFromNativeCode tidak tersedia di kode native. Oleh karena itu, kita perlu membuatnya di file MainActivity.kt dan AppDelegate.swift. Untuk yang Android kita perlu buka file MainActivity.kt dan isi dengan kode berikut.

import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
val channel = "flutter.native.code/example"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)

MethodChannel(flutterView, channel).setMethodCallHandler { call, result ->
if (call.method == "greetingFromNativeCode") {
result.success("Hello Yudi Setiawan, from Android code")
}
}
}
}

Kode tersebut adalah kode di Kotlin bahwa kita ada mendeklarasikan objek MethodChannel dengan nama channel yang sama yang sudah kita deklarasikan tadi di kode Dart. Lalu, didalamnya ada callback dimana, kita ambil nilai nama method yang akan dipanggil oleh si kode Dart. Dan kita buat pengkondisiannya untuk setiap kemungkinan method yang akan dipanggil oleh kode Dart. Pada contoh diatas kita ada menambahkan kondisi untuk method dengan nama greetingFromNativeCode . Jika sesuai nama methodnya maka, kita kembalikan hasil success ke Dart dengan kode berikut.

result.success("...")

Pada contoh, diatas kita hanya kembalikan nilai String dengan pesan "Hello Yudi Setiawan, from Android code" Sekarang coba jalankan ulang lagi app-nya dari awal dan test tap button-nya lagi. Seharusnya berhasil dan akan menghasilkan output seperti berikut.

Output hasil pemanggilan kode dari Flutter ke Android

Selanjutnya, kita perlu buat untuk yang iOS. Silakan buka file AppDelegate.swift dan ubah kode didalamnya menjadi seperti berikut.

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "flutter.native.code/example", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if (call.method == "greetingFromNativeCode") {
result("Hello Yudi Setiawan, from iOS code")
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

Dan berikut output untuk yang iOS.

Output hasil pemanggilan kode dari Flutter ke iOS

Contoh 2

Pada contoh pertama kita telah berhasil membuat Flutter bisa memanggil kode native. Sekarang kita coba untuk contoh yang kedua dimana, kita ada kirim data ke kode native lalu native mengembalikan hasilnya ke Flutter. Sekarang, kita buka file main.dart dan tambahkan widget TextField dan letakkan tepat diatas dari widget RaisedButton . Berikut ialah kode lengkapnya.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(App());

class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyApp(),
);
}
}

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
static const platform = const MethodChannel('flutter.native.code/example');
String _message;
TextEditingController _controllerNama;

@override
void initState() {
_message = 'Hello Yudi Setiawan, from Flutter code';
_controllerNama = TextEditingController();
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter to Native Code'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
child: TextField(
controller: _controllerNama,
decoration: InputDecoration(hintText: "Input your name"),
),
),
RaisedButton(
child: Text('Tap Me'),
onPressed: () async {
try {
_message = await platform.invokeMethod(
'greetingFromNativeCode',
);
} on PlatformException catch (e) {
_message = 'Failed to invoke: ${e.message}';
}
setState(() {});
},
),
Text(_message),
],
),
),
);
}
}

Output dari kode tersebut adalah seperti berikut.

Output contoh kedua

Jadi, kita akan membuat si Flutter mengirimkan data yang dari widget TextField ke kode native. Silakan kita ubah fungsi didalam property onPressed menjadi seperti berikut.

try {
String name = _controllerNama.text;
_message = await platform.invokeMethod(
'greetingFromNativeCode',
{'name': name},
);
} on PlatformException catch (e) {
_message = 'Failed to invoke: ${e.message}';
}
setState(() {});

Selanjutnya, kita ubah juga kode di file MainActivity.kt menjadi seperti berikut.

package com.example.flutter_to_native_code

import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
val channel = "flutter.native.code/example"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)

MethodChannel(flutterView, channel).setMethodCallHandler { call, result ->
if (call.method == "greetingFromNativeCode") {
val name = call.argument<String>("name") ?: "unknown"
result.success("Hello $name, from Android code")
}
}
}
}

Dan yang terakhir kita perlu ubah juga kode yang didalam file AppDelegate.swift menjadi seperti berikut.

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "flutter.native.code/example", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if (call.method == "greetingFromNativeCode") {
let args = call.arguments as? [String: String]
let name = args!["name"]
result("Hello " + name! + ", from iOS code")

}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

Jadi, pada kode di file MainActivity.kt dan AppDelegate.swift kita ada menambahkan kode untuk menangani data yang dikirimkan dari si Flutter. Dan berikut ialah output terakhirnya.

Output contoh 2

Kesimpulan

Tanpa kita sadari ternyata beberapa plugin yang ada di website pub.dev ternyata merupakan hasil dari Platform Channel. Yaitu kode-kode Flutter yang sebenarnya melakukan proses pemanggilan kode-kode native. Sampai sekarang plugin-plugin di Flutter semakin hari semakin meningkat dan keterbatasan Flutter untuk menggunakan fitur-fitur native platform sepertinya sudah tidak bisa menjadi alasan lagi bagi kita yang mau mulai mempelajarinya tapi masih ragu dengan fitur-fitur native-nya. Untuk projek lengkapnya silakan lihat di Github ya.

Nusanet Developers

Stories and insights from the developers in Nusanet

Yudi Setiawan

Written by

I’m a software developer and specialize in android development

Nusanet Developers

Stories and insights from the developers in Nusanet

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade