Étiquette : swift

  • Canaux de plateforme Flutter: appeler du code natif Android et iOS

    Canaux de plateforme Flutter: appeler du code natif Android et iOS

    Flutter couvre un terrain enorme, mais on finit par toucher quelque chose qu il n expose pas. Un capteur precis, un SDK fournisseur, un comportement de plateforme sans plugin. Quand cela arrive, on se tourne vers les canaux de plateforme, qui permettent a votre code Dart d appeler du Kotlin natif sur Android et du Swift sur iOS. Je les ai utilises pour tout, du materiel Bluetooth a un SDK de paiement, et ils sont moins effrayants qu ils n en ont l air.

    Comment fonctionne un canal

    Un canal de plateforme est un tuyau nomme entre Dart et le cote natif. Vous lui donnez un nom de chaine, vous envoyez un appel de methode avec des arguments optionnels, et le cote natif repond avec un resultat ou une erreur. Les messages sont serialises avec un codec standard qui gere les types courants comme les chaines, nombres, listes et maps. Vous ne pouvez pas passer d objets directement, alors vous concevez un petit contrat plat et vous vous y tenez.

    import 'package:flutter/services.dart';
    
    class Battery {
      static const _channel = MethodChannel('app/battery');
    
      Future<int> level() async {
        final result = await _channel.invokeMethod('getLevel');
        return result as int;
      }
    }

    Le nom du canal doit correspondre exactement des deux cotes. Une faute de frappe vous donne une erreur d implementation manquante a l execution et aucun compilateur ne vous avertira, alors je garde le nom du canal dans une seule constante et je le reference partout.

    Le cote Android en Kotlin

    Sur Android vous enregistrez un gestionnaire dans votre activite principale. Il recoit le nom de methode comme chaine, choisit selon ce nom, et repond via le callback de resultat. Tout ce que vous faites ici tourne sur le thread de plateforme, donc le travail lourd doit en sortir ou vous saccaderez l interface, un sujet que je couvre dans l optimisation des performances Flutter.

    class MainActivity : FlutterActivity() {
      override fun configureFlutterEngine(engine: FlutterEngine) {
        super.configureFlutterEngine(engine)
        MethodChannel(engine.dartExecutor.binaryMessenger, "app/battery")
          .setMethodCallHandler { call, result ->
            if (call.method == "getLevel") {
              result.success(readBatteryLevel())
            } else {
              result.notImplemented()
            }
          }
      }
    }

    Le cote iOS en Swift

    La configuration iOS reflete celle d Android. Vous enregistrez le meme nom de canal dans le delegate de l application et vous gerez l appel. La forme est identique meme si le langage differe, ce qui est une des choses que j apprecie dans la conception. Une fois le motif appris sur une plateforme, l autre parait familiere.

    let channel = FlutterMethodChannel(
      name: "app/battery",
      binaryMessenger: controller.binaryMessenger)
    
    channel.setMethodCallHandler { call, result in
      if call.method == "getLevel" {
        result(self.readBatteryLevel())
      } else {
        result(FlutterMethodNotImplemented)
      }
    }

    Gerer les erreurs et les threads

    Les appels natifs echouent. Le materiel est absent, une permission est refusee, le SDK leve une exception. Renvoyez ces echecs comme erreurs plutot que de les avaler, et attrapez les cote Dart pour que l interface reagisse. J enveloppe chaque appel de canal dans un bloc try et je presente un message clair a l utilisateur au lieu d une exception de plateforme brute.

    • Gardez le nom du canal dans une seule constante partagee
    • Renvoyez les erreurs explicitement pour que Dart les gere proprement
    • Sortez le travail natif lourd du thread de plateforme
    • Faites correspondre les types d arguments a ce que le codec standard supporte

    Quand ecrire un plugin a la place

    Si le code natif est quelque chose que d autres applications pourraient utiliser, empaquetez le comme plugin plutot que de l enterrer dans une seule application. Un plugin enveloppe les memes mecaniques de canal mais vous donne une API Dart propre et une structure reutilisable. Avant d ecrire l un ou l autre, cherchez dans le registre de packages, car la chose dont vous avez besoin existe souvent deja et est mieux testee qu une tentative fraiche. Les canaux de plateforme sont puissants, mais le meilleur code natif est celui que vous n avez pas eu a ecrire. Pour les bases de mise en place avant d arriver ici, voir debuter avec Flutter.