Platform Embedder #

Platform Embedder adalah lapisan paling bawah dalam arsitektur Flutter yang langsung bersentuhan dengan sistem operasi. Tanpa Embedder, Flutter Engine tidak tahu bagaimana cara menampilkan piksel ke layar, menerima input dari pengguna, atau berinteraksi dengan layanan OS. Embedder adalah “jembatan” yang membuat Flutter bisa berjalan di platform manapun — bahkan platform yang belum pernah ada sebelumnya.

Peran Utama Embedder #

Secara sederhana, Embedder bertanggung jawab atas empat hal utama:

Flutter Engine (platform-agnostic)
         |
         | Embedder API (ABI stabil)
         v
+------------------------------------------+
|           Platform Embedder              |
|                                          |
|  1. Rendering Surface  --> layar/canvas  |
|  2. Input Handling     --> sentuhan/kb   |
|  3. Lifecycle Mgmt     --> pause/resume  |
|  4. Platform Services  --> kamera/GPS    |
+------------------------------------------+
         |
         v
    Sistem Operasi & Hardware

Yang paling penting dipahami: Engine tidak peduli sedang berjalan di platform apa. Engine hanya tahu bahwa ada Embedder yang menyediakan rendering surface dan meneruskan event kepadanya. Embedder yang mengurus semua detail spesifik platform.


Bahasa Embedder per Platform #

Setiap platform memiliki Embedder yang ditulis dalam bahasa native platform tersebut:

PlatformBahasa EmbedderRendering Surface
AndroidJava / Kotlin + C++SurfaceView / TextureView
iOSSwift / Obj-C / Obj-C++CAMetalLayer (Metal)
macOSSwift / Obj-C / Obj-C++NSView + CAMetalLayer
WindowsC++HWND (Win32 window)
LinuxC++GTK window / Wayland
WebJavaScript / WasmHTML Canvas / WebGL

Android Embedder #

Android Embedder adalah implementasi yang paling matang karena Android adalah platform target pertama Flutter. Embedder Android menyediakan dua cara untuk menampilkan Flutter:

FlutterActivity dan FlutterFragment #

// Cara paling sederhana: gunakan FlutterActivity langsung
class MainActivity : FlutterActivity() {
    // Tidak perlu kode tambahan untuk Flutter dasar
    // FlutterActivity mengurus segalanya
}

// Atau gunakan FlutterFragment untuk integrasi ke Activity yang sudah ada
class NativeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_native)

        // Embed Flutter sebagai Fragment
        val flutterFragment = FlutterFragment
            .withNewEngine()
            .initialRoute("/flutter-screen")
            .build<FlutterFragment>()

        supportFragmentManager
            .beginTransaction()
            .add(R.id.flutter_container, flutterFragment, "flutter_fragment")
            .commit()
    }
}

Rendering di Android #

Android Embedder mendukung dua mode rendering surface:

SurfaceView (default):
  + Performa lebih baik (dedicated surface)
  + Tidak ada overdraw dengan UI native
  - Tidak bisa di-overlap dengan view native biasa

TextureView (fallback):
  + Bisa di-overlay dengan view native
  + Mendukung transformasi (rotate, scale)
  - Sedikit lebih lambat (copy texture per frame)

Lifecycle Android → Flutter #

Android Activity Lifecycle    Flutter App Lifecycle
         |                           |
  onCreate()              -->  AppLifecycleState.resumed
  onStart()               -->  (tidak ada mapping langsung)
  onResume()              -->  AppLifecycleState.resumed
  onPause()               -->  AppLifecycleState.inactive
  onStop()                -->  AppLifecycleState.paused
  onDestroy()             -->  AppLifecycleState.detached

Di sisi Dart, kamu bisa mendengarkan perubahan lifecycle ini:

class _MyWidgetState extends State<MyWidget>
    with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    switch (state) {
      case AppLifecycleState.resumed:
        print('App aktif kembali');
        // resume video, koneksi, dll.
      case AppLifecycleState.paused:
        print('App di background');
        // pause video, simpan state, dll.
      case AppLifecycleState.detached:
        print('App akan ditutup');
      default:
        break;
    }
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

iOS Embedder #

iOS Embedder menggunakan UIKit sebagai fondasi dan Metal sebagai rendering backend melalui Impeller.

FlutterViewController #

// Cara menggunakan Flutter di iOS Native App
import Flutter
import UIKit

class NativeViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // Buat FlutterEngine (sebaiknya dibuat sekali dan di-cache)
        let flutterEngine = FlutterEngine(name: "my_flutter_engine")
        flutterEngine.run(withEntrypoint: nil)

        // Buat FlutterViewController
        let flutterVC = FlutterViewController(
            engine: flutterEngine,
            nibName: nil,
            bundle: nil
        )

        // Tampilkan sebagai modal atau push ke navigation stack
        present(flutterVC, animated: true)
    }
}

Engine Caching di iOS #

Membuat FlutterEngine baru setiap kali Flutter ditampilkan itu mahal — ada overhead cold start sekitar 100–200ms. Solusinya adalah pre-warm engine:

// AppDelegate.swift — inisialisasi engine saat app pertama kali dibuka
@main
class AppDelegate: FlutterAppDelegate {
    lazy var flutterEngine = FlutterEngine(name: "shared_engine")

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Pre-warm Flutter engine di background
        flutterEngine.run()
        GeneratedPluginRegistrant.register(with: flutterEngine)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

// Di ViewController, gunakan engine yang sudah di-warm-up
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let flutterVC = FlutterViewController(
    engine: appDelegate.flutterEngine,
    nibName: nil,
    bundle: nil
)

Desktop Embedder #

Flutter mendukung tiga platform desktop secara official: Windows, macOS, dan Linux. Masing-masing memiliki Embedder yang ditulis dalam C++ (Windows dan Linux) atau Objective-C++ (macOS).

Windows Embedder #

Windows App Structure:
  main() -- entry point C++
    |
    v
  FlutterDesktopInit()         --> inisialisasi Flutter
    |
    v
  FlutterDesktopViewControllerCreate() --> buat window Flutter
    |
    v
  Win32 message loop           --> event loop platform
    |
    v
  FlutterDesktopDestroyViewController() --> cleanup

Perbedaan Desktop vs Mobile #

AspekMobileDesktop
InputTouch, gesturesMouse, keyboard, trackpad
WindowFullscreen, fixed sizeResizable, multiple windows
MenuBottom nav, drawerMenu bar, context menu
CursorTidak adaPointer, hover states
ScrollTouch scrollMouse wheel, trackpad

Flutter menyediakan abstraksi untuk semua perbedaan ini:

// Deteksi platform untuk penyesuaian UI
import 'package:flutter/foundation.dart';

Widget buildButton() {
  if (defaultTargetPlatform == TargetPlatform.macOS ||
      defaultTargetPlatform == TargetPlatform.windows ||
      defaultTargetPlatform == TargetPlatform.linux) {
    // UI untuk desktop
    return TextButton(onPressed: () {}, child: const Text('Desktop Button'));
  }
  // UI untuk mobile
  return ElevatedButton(onPressed: () {}, child: const Text('Mobile Button'));
}

Web Embedder #

Web Embedder sedikit berbeda dari platform lainnya karena tidak ada “sistem operasi” dalam artian tradisional — yang ada adalah browser.

Flutter Web (dua mode rendering):

  CanvasKit Mode (default):
    Dart --> JavaScript + CanvasKit (Skia compiled to Wasm)
    Kelebihan: rendering identik dengan mobile/desktop
    Kekurangan: download size lebih besar (~1.5MB)

  HTML Mode (legacy, dihapus di Flutter 3.x):
    Dart --> JavaScript --> HTML/CSS/DOM
    Kelebihan: lebih ringan, SEO-friendly
    Kekurangan: rendering tidak selalu identik

  Wasm Mode (masa depan):
    Dart --> WebAssembly + Impeller (dalam pengembangan)
    Kelebihan: performa jauh lebih baik dari JavaScript
    Kekurangan: masih eksperimental

Custom Embedder — Flutter di Mana Saja #

Salah satu keunggulan arsitektur Embedder adalah siapapun bisa membuat Embedder baru untuk platform yang belum didukung secara official. Engine Flutter menyediakan Embedder API yang stabil berbasis C:

// Contoh inisialisasi Flutter Engine dari custom embedder (C API)
FlutterEngineResult result = FlutterEngineInitialize(
    FLUTTER_ENGINE_VERSION,
    &renderer_config,    // konfigurasi rendering (OpenGL/Vulkan/Metal/Software)
    &project_args,       // path ke assets, flags, dll
    user_data,           // pointer ke data embedder kamu
    &engine              // output: handle ke engine
);

FlutterEngineRunInitialized(engine);

Beberapa implementasi custom embedder yang sudah ada di komunitas:

  • Toyota — sistem infotainment in-dash untuk kendaraan menggunakan Flutter
  • Raspberry Pi — beberapa project community untuk embedded Linux
  • Flutter-elinux — Embedder untuk embedded Linux (Wayland/DRM)
  • Samsung Tizen — Embedder untuk smart TV Samsung
  • Meta Quest — eksperimen Flutter di VR headset
Implikasi arsitektur yang luar biasa: karena Engine bersifat platform-agnostic dan Embedder API-nya stabil, jika ada sistem operasi baru yang muncul di masa depan, Flutter hanya perlu satu Embedder baru untuk bisa menjalankan semua aplikasi Flutter yang sudah ada tanpa perubahan apapun di sisi developer.

Platform Channel — Jembatan Dart ke Native #

Embedder juga berperan sebagai router untuk Platform Channel — mekanisme komunikasi antara kode Dart dan kode native platform.

Kode Dart (UI Thread)
      |
      | MethodChannel / EventChannel / BasicMessageChannel
      v
Flutter Engine (serialisasi pesan)
      |
      v
Platform Embedder (routing)
      |
      v
Native Code (Android: Kotlin/Java, iOS: Swift/ObjC)
      |
      v (hasil dikembalikan asinkron)
Kode Dart (callback/Future)
// Sisi Dart: memanggil fungsi native
const platform = MethodChannel('com.example.app/battery');

Future<int> getBatteryLevel() async {
  try {
    final int level = await platform.invokeMethod('getBatteryLevel');
    return level;
  } on PlatformException catch (e) {
    throw Exception('Gagal mendapat info baterai: ${e.message}');
  }
}
// Sisi Android (Kotlin): mengimplementasikan fungsi native
class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.app/battery"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call, result ->
                if (call.method == "getBatteryLevel") {
                    val batteryLevel = getBatteryLevel()
                    if (batteryLevel != -1) {
                        result.success(batteryLevel)
                    } else {
                        result.error("UNAVAILABLE", "Battery level unavailable", null)
                    }
                } else {
                    result.notImplemented()
                }
            }
    }

    private fun getBatteryLevel(): Int {
        val batteryManager = getSystemService(BATTERY_SERVICE) as BatteryManager
        return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
    }
}

Ringkasan #

  • Platform Embedder adalah lapisan native yang menghubungkan Flutter Engine dengan sistem operasi — ditulis dalam bahasa native masing-masing platform.
  • Engine bersifat platform-agnostic dan tidak peduli sedang berjalan di platform apa — Embedder yang mengurus semua detail spesifik platform.
  • Android Embedder menggunakan FlutterActivity / FlutterFragment dengan SurfaceView atau TextureView sebagai rendering surface.
  • iOS Embedder menggunakan FlutterViewController di atas UIKit dengan Metal/Impeller sebagai backend rendering.
  • Desktop Embedder (Windows, macOS, Linux) menangani perbedaan input model (mouse/keyboard) dan window management yang tidak ada di mobile.
  • Web Embedder menggunakan CanvasKit (Skia compiled to Wasm) untuk rendering yang identik dengan platform lain.
  • Embedder API Flutter bersifat stabil — siapapun bisa membuat Embedder baru untuk platform baru tanpa harus mengubah Engine atau aplikasi Flutter yang sudah ada.
  • Platform Channel dikerjakan oleh Embedder sebagai router pesan antara kode Dart dan kode native platform.

← Sebelumnya: Engine Layer   Berikutnya: Rendering Pipeline →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact