Nusanet Developers
Published in

Nusanet Developers

Flutter: Event Channel

How to stream data from native side

Pengenalan

Salah satu tantangan terbesar untuk framework cross platform seperti Flutter ini ialah bagaimana cara mereka agar si Flutter ini tetap bisa menggunakan fungsi-fungsi native dari sebuah platform. Baik itu di sisi mobile ada Android dan iOS maupun nanti kedepannya untuk platform Web dan Desktop (Mac, Linux, dan Windows). Beruntungnya di Flutter sudah mereka sediakan yang namanya itu platform channel. Jadi, platform channel ini ialah cara bagaimana si Flutter atau bahasa Dart bisa berkomunikasi dengan kode-kode native-nya si platform. Misal, kalau di Android kita bisa berkomunikasi dengan kode Java atau Kotlin. Dan di iOS bisa berkomunikasi dengan Obj-C atau Swift. Jadi, di platform channel ini ada 3 metode yang bisa kita gunakan untuk melakukan komunikasi dengan kode native-nya. Berikut adalah beberapa metodenya.

Untuk yang pertama, method channel ini ialah sebuah metode dimana, kita membuat kode Dart yang memanggil fungsi yang ada di native-nya. Jadi, secara sederhana saya katakan saja bahwa method channel ini cara kerjanya hampir mirip seperti kita memanggil sebuah method. Kita panggil method yang ada di native dari bahasa Dart lalu, kita tunggu respon yang diberikan oleh si native.

Cara kerja method channel di Flutter

Untuk pembahasan detail-nya bisa kamu baca pada link berikut ini ya.

Untuk metode kedua, ini cara kerjanya berbeda dengan metode pertama. Jadi, jika di method channel kita panggil method yang ada di native dan menunggu kembalian datanya. Maka, di event channel kita cukup meng-listen data yang diberikan oleh si native. Cara kerjanya ini hampir mirip kayak stream. Jadi, di sisi Dart kita cukup listen aja. Dan di sisi native-nya nanti yang akan mengirimkan datanya.

Cara kerja event channel

Untuk metode yang ketiga ini jujur saja saya kurang begitu paham gimana cara kerjanya. Tapi, nanti kalau saya sudah paham akan saya buat tulisan terpisah mengenai detail penggunaannya.

Dari ketiga metode tersebut yang pernah saya pakai di lapangan itu hanya yang method channel saja. Untuk event channel saya belum pakai karena belum ada kebutuhan untuk menggunakannya. Jadi, untuk method channel saya pernah pakai untuk menggunakan plugin camera native-nya si Android ketimbang menggunakan plugin camera-nya si Flutter. Alasannya cukup sederhana yaitu, karena pas dipakai oleh user ternyata ada beberapa sebagian device Android yang error ketika coba pakai plugin camera-nya si Flutter. Alhasil saya kepikiran untuk memisahkan kode untuk fitur camera-nya. Untuk Android-nya saya pakai method channel agar menggunakan plugin camera-nya si Android sementara, untuk iOS saya tetap pakai plugin camera-nya si Flutter. So far sih untuk plugin camera di iOS belum ada kendala ya.

Contoh Kasus

Jadi, di tulisan ini saya akan bahas detail mengenai penggunaan event channel. Untuk projeknya silakan kita buat projek baru dengan nama belajar_flutter_event_channel.

Buat projek baru

Untuk platform-nya nanti kita coba buat untuk Android dan iOS saja ya.

Jadi, di contoh kasus kali ini kita akan coba buat aplikasi timer. Cuma timer-nya itu dibuat dari kode native-nya bukan dari Dart. Untuk memulai membuatnya kita perlu buat UI-nya terlebih dahulu. Silakan kita buka file main.dart dan ubah kode didalamnya menjadi seperti berikut.

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

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Belajar Event Channel',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Belajar Event Channel'),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);

final String title;

@override
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
final eventChannel = const EventChannel('belajar_flutter_event_channel');
final valueNotifier = ValueNotifier<String>('value');

@override
void initState() {
eventChannel.receiveBroadcastStream().listen((event) {
if (event is String) {
valueNotifier.value = event;
}
});
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ValueListenableBuilder<String>(
valueListenable: valueNotifier,
builder: (BuildContext context, String value, Widget? child) {
return Text(
value,
style: Theme.of(context).textTheme.headline6,
);
},
),
),
);
}
}

Bisa kita lihat pada kode diatas bahwa kita ada menggunakan widget ValueListenableBuilder untuk meng-listen perubahan dari variable valueNotifier . Kemudian, didalam method initState kita ada menggunakan event channel untuk meng-listen data yang diberikan dari si native dan data yang dari native akan kita masukkan kedalam variable valueNotifier . Dan berikut ini adalah tampilan dari programnya.

Tampilan utama dari program

Untuk membuat event channel di Android silakan kita buka file MainActivity.kt (sesuaikan dengan bahasa native-nya masing-masing ya) dan ubah kode didalamnya menjadi seperti berikut.

package com.example.belajar_flutter_event_channel

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
import java.util.*

class MainActivity: FlutterActivity() {
private val channel = "belajar_flutter_event_channel"
private lateinit var timer: Timer
private var eventSink: EventChannel.EventSink? = null
private var counter = 0

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
val eventChannel = EventChannel(flutterEngine.dartExecutor.binaryMessenger, channel)
eventChannel.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
}

override fun onCancel(arguments: Any?) {
stopTimer()
}
})
startTimer()
}

private fun startTimer() {
timer = Timer()
timer.scheduleAtFixedRate(object : TimerTask() {
override fun run() {
this@MainActivity.runOnUiThread {
counter += 1
eventSink?.success("Counter from Android: $counter")
}
}
}, 0, 1000)
}

private fun stopTimer() {
timer.cancel()
}
}

Jadi, didalam file tersebut kita ada menggunakan timer miliknya si Android lalu, data counter-nya kita kirim kedalam variable eventSink . Nah, data yang kita kirim ini nantinya akan diterima oleh si Flutter karena si Flutter kan tadinya sudah meng-listen ya. Sehingga jika kita jalankan programnya maka, output untuk di Android akan menjadi seperti berikut.

Output event channel di Android

Untuk yang iOS kita bisa buka file AppDelegate.swift dan ubah kode didalamnya menjadi seperti berikut.

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, FlutterStreamHandler {
private var eventSink: FlutterEventSink?
private var timer: Timer?
private var counter = 0

override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)

let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let eventChannel = FlutterEventChannel(name: "belajar_flutter_event_channel", binaryMessenger: controller.binaryMessenger)
eventChannel.setStreamHandler(self)

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: "increaseCounter", userInfo: nil, repeats: true)

return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

@objc func increaseCounter() {
counter += 1
eventSink?("Counter from iOS: \(counter)")
}

public func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = eventSink
return nil
}

public func onCancel(withArguments arguments: Any?) -> FlutterError? {
timer?.invalidate()
eventSink = nil
return nil
}
}

Cara kerjanya sama seperti di Android. Kita ada menggunakan timer-nya si iOS lalu data dari variable counter kita masukkan kedalam variable eventSink.

Output event channel di iOS

Kesimpulan

Jadi, kesimpulannya adalah Flutter memiliki 3 metode untuk bisa melakukan komunikasi dari Dart ke platform-nya masing-masing yaitu, method channel, event channel, dan basic message channel. Event channel memiliki cara kerja mirip seperti stream. Dari Dart cukup meng-listen datanya dan native-nya akan mengirimkan datanya. Untuk source code lengkapnya bisa di Github ya.

--

--

Stories and insights from the developers in Nusanet

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store