Flutter platform-specific code

This section will introduce how to use platform channels to call native platform code in Flutter.


Platform Channel Overview

Platform channels allow Dart code to communicate with native platforms (iOS/Android).

TypeDescription
MethodChannelMethod channels, used for calling platform methods
EventChannelEvent channels, used for streaming data

Dart-side Call

Example: MethodChannel usage

import 'package:flutter/services.dart';

// Define channel
class PlatformChannel {
  static const MethodChannel _channel = MethodChannel('my_app/channel');

  // Call native method - get battery level
  static Future<int> getBatteryLevel() async {
    try {
      final int batteryLevel = await _channel.invokeMethod('getBatteryLevel');
      return batteryLevel;
    } on PlatformException catch (e) {
      print('Failed to get battery level: ${e.message}');
      return -1;
    }
  }

  // Call native method - show Toast
  static Future<void> showToast(String message) async {
    try {
      await _channel.invokeMethod('showToast', {'message': message});
    } on PlatformException catch (e) {
      print('Failed to show Toast: ${e.message}');
    }
  }

  // Call native method - get device information
  static Future<Map<String, dynamic>> getDeviceInfo() async {
    try {
      final result = await _channel.invokeMapMethod('getDeviceInfo');
      return result ?? {};
    } on PlatformException catch (e) {
      print(Failed to get device information: ${e.message});
      return {};
    }
  }
}

// Usage example
class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () async {
        final battery = await PlatformChannel.getBatteryLevel();
        print(Battery level: $battery%);
      },
      child: const Text(Get battery level),
    );
  }
}

Android Implementation (Kotlin)

Example: Android-side Code

// MainActivity.kt
package com.example.my_app

import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "my_app/channel"

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

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "getBatteryLevel" -> {
                        val batteryLevel = getBatteryLevel()
                        if (batteryLevel != -1) {
                            result.success(batteryLevel)
                        } else {
result.error("UNAVAILABLE", "Unable to get battery level", null)
                        }
                    }
                    "showToast" -> {
                        val message = call.argument<String>("message")
                        showToast(message!!)
                        result.success(null)
                    }
                    else -> {
                        result.notImplemented()
                    }
                }
            }
    }

    private fun getBatteryLevel(): Int {
        return try {
            val batteryManager = getSystemService(BATTERY_SERVICE) as BatteryManager
            batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        } catch (e: Exception) {
            -1
        }
    }

    private fun showToast(message: String) {
        android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show()
    }
}

iOS Implementation (Swift)

Example: iOS-side Code

// AppDelegate.swift
import Flutter
import UIKit

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    private let CHANNEL = "my_app/channel"

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller = window?.rootViewController as! FlutterViewController

        let channel = FlutterMethodChannel(
            name: CHANNEL,
            binaryMessenger: controller.binaryMessenger
        )

        channel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in
            switch call.method {
            case "getBatteryLevel":
                self.getBatteryLevel(result: result)
            case "showToast":
                if let args = call.arguments as? [String: Any],
                   let message = args["message"] as? String {
                    self.showToast(message: message)
                    result(nil)
                }
            default:
                result(FlutterMethodNotImplemented)
            }
        }

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

    private func getBatteryLevel(result: @escaping FlutterResult) {
        UIDevice.current.isBatteryMonitoringEnabled = true
        let batteryLevel = UIDevice.current.batteryLevel

        if batteryLevel < 0 {
result(FlutterError(code: "UNAVAILABLE", message: "Unable to get battery level", details: nil))
        } else {
            result(Int(batteryLevel * 100))
        }
    }

    private func showToast(message: String) {
        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        present(alert, animated: true)
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
            alert.dismiss(animated: true)
        }
    }
}

Platform channels are the primary way for Flutter to communicate with native code, commonly used to call system APIs, hardware features, or use third-party native SDKs.

other extensions