Flutter plattformspezifischer Code
Dieser Abschnitt erläutert, wie man Plattformkanäle verwendet, um nativen Plattformcode in Flutter aufzurufen.
Übersicht über Plattformkanäle
Plattformkanäle ermöglichen es Dart-Code, mit nativen Plattformen (iOS/Android) zu kommunizieren.
| Type | Beschreibung |
|---|---|
| MethodChannel | Methodenkanäle, die zum Aufrufen von Plattformmethoden verwendet werden |
| EventChannel | Ereigniskanäle, die zum Streamen von Daten verwendet werden |
Dart-seitiger Aufruf
Beispiel: Verwendung von MethodChannel
import 'package:flutter/services.dart';
// Kanal definieren
class PlatformChannel {
static const MethodChannel _channel = MethodChannel('my_app/channel');
// Native Methode aufrufen – Batteriestand abrufen
static Future<int> getBatteryLevel() async {
try {
final int batteryLevel = await _channel.invokeMethod('getBatteryLevel');
return batteryLevel;
} on PlatformException catch (e) {
print('Batteriestand konnte nicht abgerufen werden: ${e.message}');
return -1;
}
}
// Native Methode aufrufen – Toast anzeigen
static Future<void> showToast(String message) async {
try {
await _channel.invokeMethod('showToast', {'message': message});
} on PlatformException catch (e) {
print('Toast konnte nicht angezeigt werden: ${e.message}');
}
}
// Native Methode aufrufen - Geräteinformationen abrufen
static Future<Map<String, dynamic>> getDeviceInfo() async {
try {
final result = await _channel.invokeMapMethod('getDeviceInfo');
return result ?? {};
} on PlatformException catch (e) {
print(Geräteinformationen konnten nicht abgerufen werden: ${e.message});
return {};
}
}
}
// Anwendungsbeispiel
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
final battery = await PlatformChannel.getBatteryLevel();
print(Batteriestand: $battery%);
},
child: const Text(Batteriestand abrufen),
);
}
}
// Kanal definieren
class PlatformChannel {
static const MethodChannel _channel = MethodChannel('my_app/channel');
// Native Methode aufrufen – Batteriestand abrufen
static Future<int> getBatteryLevel() async {
try {
final int batteryLevel = await _channel.invokeMethod('getBatteryLevel');
return batteryLevel;
} on PlatformException catch (e) {
print('Batteriestand konnte nicht abgerufen werden: ${e.message}');
return -1;
}
}
// Native Methode aufrufen – Toast anzeigen
static Future<void> showToast(String message) async {
try {
await _channel.invokeMethod('showToast', {'message': message});
} on PlatformException catch (e) {
print('Toast konnte nicht angezeigt werden: ${e.message}');
}
}
// Native Methode aufrufen - Geräteinformationen abrufen
static Future<Map<String, dynamic>> getDeviceInfo() async {
try {
final result = await _channel.invokeMapMethod('getDeviceInfo');
return result ?? {};
} on PlatformException catch (e) {
print(Geräteinformationen konnten nicht abgerufen werden: ${e.message});
return {};
}
}
}
// Anwendungsbeispiel
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
final battery = await PlatformChannel.getBatteryLevel();
print(Batteriestand: $battery%);
},
child: const Text(Batteriestand abrufen),
);
}
}
Android-Implementierung (Kotlin)
Beispiel: Android-seitiger 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", "Batteriestand konnte nicht abgerufen werden", 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()
}
}
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", "Batteriestand konnte nicht abgerufen werden", 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-Implementierung (Swift)
Beispiel: iOS-seitiger 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: "Batteriestand konnte nicht abgerufen werden", 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)
}
}
}
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: "Batteriestand konnte nicht abgerufen werden", 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)
}
}
}
Weitere ErweiterungenPlattformkanäle sind der primäre Weg für Flutter, mit nativem Code zu kommunizieren; sie werden häufig verwendet, um System-APIs, Hardwarefunktionen aufzurufen oder native SDKs von Drittanbietern zu nutzen.