Kiedy pracujemy z cross-platformowym frameworkiem, nie można zagwarantować, że będziemy pracować tylko z tym frameworkiem bez żadnej pracy w natywnym kodzie. Deweloperzy najprawdopodobniej będą uciekać się do natywnego albo z powodu funkcji, których framework jeszcze nie dostarczył, albo z powodu problemów z wydajnością, które mogą być rozwiązane tylko w natywnym. Kanały platformy są metodą, w której można napisać specyficzny dla danej platformy natywny kod do wykorzystania w swoich aplikacjach Flutter.

Standardowe kanały platformy używają standardowego kodeka wiadomości, który obsługuje wydajną binarną serializację prostych wartości podobnych do JSON, takich jak booleans, liczby, Strings, bufory bajtowe, a także listy i mapy tych. Serializacja i deserializacja tych wartości do i z wiadomości dzieje się automatycznie podczas wysyłania i odbierania wartości.

Platform Channel składa się z trzech części: Klasa MethodChannel na Flutter, Klasa MethodChannel na Android i Klasa FlutterMethodChannel na iOS.

Zaletą Fluttera jest to, że wykorzystuje elastyczny system, który pozwala na wywołanie API specyficznych dla danej platformy, czy to dostępnych w kodzie Kotlin lub Java na Androidzie, czy w kodzie Swift lub Objective-C na iOS.

Ten tutorial pokazuje jak stworzyć funkcję Fluttera, która wywołuje natywny kod Androida i iOS.

 

Wywoływanie natywne z Flutter

Aplikacja będzie wywoływała funkcję zgodnie z jej nazwą, a program będzie szukał jej implementacji w kodzie Androida lub iOS.

Na początek utwórz MethodChannel.

 

Strony klienta i hosta kanału są połączone poprzez nazwę kanału przekazaną w konstruktorze kanału. Wszystkie nazwy kanałów używane w jednej aplikacji muszą być unikalne.

static final channelName = 'example.channel/native';
const methodChannel = MethodChannel(channelName);

Następnie należy utworzyć metodę, która będzie wywoływała określoną metodę na kanale platformy.

Future<void> _getBatteryLevel() async {
    String batteryLevel;
    try {
        batteryLevel = await platform.invokeMethod('getBatteryLevel');
    } on PlatformException catch (e) {
        batteryLevel = e.message;
    }
}

Android

Przejdź do katalogu z aplikacją Flutter i otwórz folder android w Android Studio.

Otwórz plik MainActivity.kt. Utwórz ten sam kanał, który zadeklarowałeś w swojej części Flutter.

 

private val channelName ='example.channel/native'

Następnie wewnątrz configureFlutterEngine() dodajemy handler wywołania metody.

MethodChannel(flutterEngine.dartExecutor.binaryMessage, channelName)
    .setMethodCallHandler { call, result ->
        if (call.method == "getBatteryLevel") {
            val batteryLevel = getBatteryLevel()
            result.success(batteryLevel)
        } else {
            result.notImplemented()
        }
    }

Następnie dodaj implementację metody, którą chcesz wywołać (w przykładzie funkcja getBatteryLevel() ).

iOS

Otwórz folder ios w XCode. Przejdź do pliku AppDelegate.swift i wewnątrz funkcji application:didFinishLaunchingWithOptions utwórz kanał.

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    let channelName = "example.channel/native"
    let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
    let methodChannel = FlutterMethodChannel(name: channelName, binaryMessage: rootViewController)

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

  }

Następnie dodajemy handler wywołania metody.

methodChannel.setMethodCallHandler( {(call: FlutterMethodCall, result: FlutterResult) -> Void in
    guard call.method == "getBatteryLevel" else {
        result(FlutterMethodNotImplemented)
        return
    }
    self?.getBatteryLevel(result: result)
})

Wytworzenie implementacji metody (na przykład getBatteryLevel).

Przykład odwrotny

Jeśli potrzebujesz wywołać metodę Flutter z natywnego kodu, wtedy wywołujesz te same metody z wcześniejszych, ale na odwrót.

Kod Flutter

static final channelName = 'example.channel/native'; 
const methodChannel = MethodChannel(channelName);
methodChannel.setMethodCallHandler(_nativeMethodCallHandler);

Future<dynamic> _nativeMethodCallHandler(MethodCall call) async {
    switch(call.method) {
        case "exampleMethod":
            //function call
    }
}

Kod Android

val channelName = 'example.channel/native'
val methodChannel = MethodChannel(flutterView, channelName)

methodChannel.invokeMethod("exampleMethod")

Kod iOS

let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
let channelName ="example.channel/native"
let methodChannel = FlutterEventChannel(name: channelName, binaryMessenger: rootViewController)

methodChannel.invokeMethod("exampleMethod")