Mobilutvikling med Flutter · leksjon

Plattformkanaler (MethodChannel)

Kommuniser med innebygd Android-kode (Kotlin/Java) og iOS-kode (Swift/Objective-C) ved hjelp av Platform Channels for plattformspesifikke funksjoner.

Leksjon 1 av 412 trinn

Plattformkanaler (MethodChannel) er en gratis leksjon i Mobilutvikling med Flutter på CoddyKit. Dette er leksjon 1 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Mobilutvikling med Flutter, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Platform Channels: Bro til innebygd kode

Velkommen til Platform Channels! Noen ganger trenger Flutter-appen din tilgang til funksjoner som er spesifikke for den underliggende mobilplattformen (Android eller iOS), og som ikke er direkte tilgjengelige i Flutter eller Dart.

Det er her Platform Channels kommer inn. De fungerer som en bro som lar Dart-koden kommunisere med innebygd kode skrevet i Kotlin/Java for Android eller Swift/Objective-C for iOS.

Slik fungerer MethodChannel

Platform Channels bruker et system kalt MethodChannel til å sende meldinger mellom Flutter og den innebygde plattformen. Tenk på det som en toveis forbindelse:

  • Flutter sender metodekall til den innebygde siden.
  • Den innebygde koden kjører metoden og sender et resultat tilbake til Flutter.

Meldinger sendes asynkront, slik at brukergrensesnittet forblir responsivt.

Flutter: Opprette MethodChannel

På Flutter (Dart)-siden oppretter du en MethodChannel-instans. Det viktigste er å bruke en unik strengidentifikator, ofte kalt «kanalnavnet», som må være den samme på både Flutter- og den native siden.

La oss sette opp en kanal for å hente enhetsinformasjon:

import 'package:flutter/services.dart';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Define the MethodChannel with a unique name
  static const platform = MethodChannel('com.example.app/device');
  String _deviceModel = 'Unknown';

  Future<void> _getDeviceModel() async {
    // Implementation to invoke native method will be added
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Platform Channel Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Device Model: $_deviceModel'),
            ElevatedButton(
              onPressed: _getDeviceModel,
              child: Text('Get Device Model'),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(home: HomePage()));
}

Flutter: Kalle native metoder

For å kalle en native metode bruker du platform.invokeMethod(). Dette kallet er asynkront og returnerer en Future. Du venter på resultatet for å hente dataene fra den native siden.

Vi oppdaterer metoden _getDeviceModel:

import 'package:flutter/services.dart';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  static const platform = MethodChannel('com.example.app/device');
  String _deviceModel = 'Unknown';

  Future<void> _getDeviceModel() async {
    String deviceModel;
    try {
      // Invoking the native method 'getDeviceModel'
      final String result = await platform.invokeMethod('getDeviceModel');
      deviceModel = result; // The result from native is a String
    } on PlatformException catch (e) {
      // Catch errors sent back from the native side
      deviceModel = "Failed to get model: '${e.message}'.";
    }
    setState(() {
      _deviceModel = deviceModel;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Platform Channel Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Device Model: $_deviceModel'),
            ElevatedButton(
              onPressed: _getDeviceModel,
              child: Text('Get Device Model'),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(home: HomePage()));
}

Flutter: Sende data til native kode

Du kan også sende argumenter til native metoder. Disse argumentene sendes som en Map, slik at du kan inkludere ulike datatyper.

La oss opprette en ny metode for å hente en «tilpasset» enhetsmodell med et prefiks og et suffiks:

import 'package:flutter/services.dart';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  static const platform = MethodChannel('com.example.app/device');
  String _customModel = 'Unknown';

  Future<void> _getCustomModel(String prefix) async {
    String customModel;
    try {
      // Invoking with arguments: a Map
      final String result = await platform.invokeMethod(
        'getCustomModel',
        {'prefix': prefix, 'suffix': 'v1'}
      );
      customModel = result;
    } on PlatformException catch (e) {
      customModel = "Failed to get custom model: '${e.message}'.";
    }
    setState(() {
      _customModel = customModel;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Platform Channel Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Custom Model: $_customModel'),
            ElevatedButton(
              onPressed: () => _getCustomModel('MyApp'),
              child: Text('Get Custom Model'),
            ),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(home: HomePage()));
}

Android (Kotlin): Sette opp kanalen

På Android-siden setter du opp MethodChannel i filen MainActivity.kt. Det er her du definerer hvordan innkommende metodekall fra Flutter skal håndteres.

Kontroller at kanalnavnet samsvarer med navnet i Flutter-koden.

package com.example.coddy_app

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

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.app/device"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
            // This block will execute when Flutter invokes a method
            call, result ->
            // Logic to handle 'call' and respond using 'result'
        }
    }
}

Android (Kotlin): Håndtere kall

Inne i setMethodCallHandler kontrollerer du strengen call.method for å finne ut hvilken metode Flutter prøver å kalle. Du kan også få tilgang til argumenter ved hjelp av call.argument().

Bruk result.success() til å sende data tilbake, eller result.notImplemented() hvis metoden ikke håndteres.

package com.example.coddy_app

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.os.Build // Import for device info

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.app/device"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
            call, result ->
            if (call.method == "getDeviceModel") {
                val model = Build.MODEL // Get device model
                result.success(model) // Return success to Flutter
            } else if (call.method == "getCustomModel") {
                val prefix = call.argument<String>("prefix") ?: ""
                val suffix = call.argument<String>("suffix") ?: ""
                val customModel = "$prefix-${Build.MODEL}-$suffix"
                result.success(customModel)
            }
            else {
                result.notImplemented() // Indicate method not found
            }
        }
    }
}

iOS (Swift): Sette opp kanalen

For iOS konfigurerer du vanligvis MethodChannel i filen AppDelegate.swift. I likhet med Android må kanalnavnet samsvare med navnet på Flutter-siden.

Oppsettet innebærer å hente FlutterViewController og opprette en FlutterMethodChannel.

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let deviceChannel = FlutterMethodChannel(name: "com.example.app/device",
                                                  binaryMessenger: controller.binaryMessenger)
    deviceChannel.setMethodCallHandler({ // Set up handler for incoming calls
      (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
      // Logic to handle 'call' and respond using 'result'
    })

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

iOS (Swift): Håndtere kall

I Swift bruker du en switch-setning eller if/else if for å kontrollere call.method. Du får tilgang til argumenter via call.arguments, som vanligvis er en [String: Any]-ordbok.

Bruk result() med verdien ved vellykket gjennomføring, eller FlutterMethodNotImplemented for metoder som ikke håndteres.

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let deviceChannel = FlutterMethodChannel(name: "com.example.app/device",
                                                  binaryMessenger: controller.binaryMessenger)
    deviceChannel.setMethodCallHandler({ 
      (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
      if call.method == "getDeviceModel" {
        let model = UIDevice.current.model // Get device model
        result(model) // Return success to Flutter
      } else if call.method == "getCustomModel" {
        if let args = call.arguments as? [String: Any],
           let prefix = args["prefix"] as? String,
           let suffix = args["suffix"] as? String {
           let customModel = "\(prefix)-\(UIDevice.current.model)-\(suffix)"
           result(customModel)
        } else {
           result(FlutterError(code: "INVALID_ARGUMENTS", message: "Arguments missing or invalid", details: nil))
        }
      }
      else {
        result(FlutterMethodNotImplemented)
      }
    })

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

Håndtere native feil

Det er viktig å håndtere feil fra den native siden på en god måte. Native kode kan sende tilbake en feil ved hjelp av result.error() (Android) eller FlutterError() (iOS).

Flutter fanger disse som en PlatformException, som du kan håndtere i en try-on-blokk, slik det vises i eksemplene våre på Flutter-kall.

package com.example.coddy_app

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

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.app/device"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
            call, result ->
            if (call.method == "getCustomModel") {
                val prefix = call.argument<String>("prefix")
                if (prefix == null || prefix.isEmpty()) {
                    // Sending an error back to Flutter
                    result.error("MISSING_PREFIX", "Prefix argument is required.", null)
                } else {
                    val suffix = call.argument<String>("suffix") ?: ""
                    val customModel = "$prefix-${Build.MODEL}-$suffix"
                    result.success(customModel)
                }
            }
            // ... other methods
            else { result.notImplemented() }
        }
    }
}

Kontroll av plattformkanaler

Test forståelsen din av Flutter-plattformkanaler.

Oppsummering: Bygge bro mellom plattformene

Godt jobbet! Du har lært hvordan du bruker Platform Channels til å utvide funksjonaliteten i Flutter-appen din ved å samhandle med plattformspesifikke native funksjoner.

  • Du oppretter en MethodChannel i Flutter og på hver native plattform (Android/iOS).
  • Flutter bruker invokeMethod() til å kalle native funksjoner.
  • Native kode håndterer disse kallene og returnerer resultater eller feil.

Denne kraftige teknikken sørger for at Flutter-appene dine aldri begrenses av det rammeverket tilbyr direkte!

Gratis å komme i gang

Lær deg Dart med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
22
Leksjoner
88

Ofte stilte spørsmål

Er leksjonen «Plattformkanaler (MethodChannel)» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Mobilutvikling med Flutter, inkludert «Plattformkanaler (MethodChannel)», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Mobilutvikling med Flutter inneholder totalt 4 leksjoner.

Hva lærer jeg i «Plattformkanaler (MethodChannel)»?

Kommuniser med innebygd Android-kode (Kotlin/Java) og iOS-kode (Swift/Objective-C) ved hjelp av Platform Channels for plattformspesifikke funksjoner. Du øver på Mobilutvikling med Flutter med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Mobilutvikling med Flutter?

Ingen tidligere erfaring er nødvendig. Mobilutvikling med Flutter på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «Plattformkanaler (MethodChannel)»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Mobilutvikling med Flutter-leksjonen?

Ja. Alle Mobilutvikling med Flutter-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Plattformkanaler (MethodChannel)
  2. Geolokasjons- og kameramoduler
  3. Integrering av innebygd brukergrensesnitt
  4. Tillatelser og sensorer
← Tilbake til Mobilutvikling med Flutter