如何使用 Flutter MethodChannel 从本机 swift 代码调用 dart 代码中的方法?

Sco*_*nts 6 ios dart swift flutter

我看过很多关于这个主题的类似问题,但没有一个解决方案对我有用。我正在 Flutter 中开发一个应用程序,但想从本机 iOS 项目中调用我的main.dart文件中的特定方法。AppDelegate.swift

为了删除所有其他变量,我已将问题提取到一个新的 dart 项目中。我试图setChannelText()AppDelegate.swiftusing 中调用methodChannel.invokeMethod(),但没有成功。

有人知道我哪里出错了吗?我知道我没有对 中的“名称”参数进行操作methodChannel.invokeMethod(),但那是因为我只想调用该方法......

这是我的 main.dart 文件:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  MethodChannel channel =
      new MethodChannel("com.example.channeltest/changetext");
  String centerText;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.purple,
        body: Center(
          child: Text(
            centerText,
            style: TextStyle(
              color: Colors.white,
              fontWeight: FontWeight.bold,
              fontSize: 30.0,
            ),
          ),
        ),
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    this.channel.setMethodCallHandler((call) async => await setChannelText());
    this.centerText = "Hello World!";
  }

  Future setChannelText() async {
    Future.delayed(Duration(milliseconds: 200));
    setState(() => this.centerText = "Another Text.");
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 AppDelegate.swift 文件:

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    var methodChannel: FlutterMethodChannel!
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions:                 

[UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    
    let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
    methodChannel = FlutterMethodChannel(name: "com.example.channeltest/changetext", binaryMessenger: rootViewController as! FlutterBinaryMessenger)
    
    //This call would obviously be somewhere else in a real world example, but I'm just
    //testing if I can invoke the method in my dart code at all..
    methodChannel.invokeMethod("some_method_name", arguments: nil)
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
Run Code Online (Sandbox Code Playgroud)

最后,我试图让文本在启动后立即更改,但事实并非如此。

应用程序在 iOS 模拟器上运行的屏幕截图

预先感谢您的任何帮助!

Ben*_*rth 5

问题

问题是您的平台端(在本例中为 iOS)在Flutter 准备好之前调用 Flutter 端的方法。没有办法从平台端检查,所以你的Flutter 应用程序必须告诉你的平台端。在 Android 上你也会遇到同样的问题。

解决方案

为了克服这个问题,您必须告诉平台端应用程序已准备就绪(通过发送平台方法)并将其保存在布尔值中,或者实例化一个类并调用一个方法。然后平台方就可以开始发送消息了。

您应该真正阅读日志,它应该警告您以下内容:“没有任何内容在监听此内容,或者未连接 Flutter 引擎”。

import 'dart:async';

import 'package:flutter/src/services/platform_channel.dart';

class StringService {
  final methodChannel =
      const MethodChannel("com.example.app_name.method_channel.strings");

  final StreamController<String> _stringStreamController =
      StreamController<String>();

  Stream<String> get stringStream => _stringStreamController.stream;

  StringService() {
    // Set method call handler before telling platform side we are ready to receive.
    methodChannel.setMethodCallHandler((call) async {
      print('Just received ${call.method} from platform');
      if (call.method == "new_string") {
        _stringStreamController.add(call.arguments as String);
      } else {
        print("Method not implemented: ${call.method}");
      }
    });
    // Tell platform side we are ready!
    methodChannel.invokeMethod("isReady");
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以在reverse_platform_methods看到一个工作项目,特别是AppDelegate.swift. 我没有在 Android 上实现它,但你可以在MainActivity.kt.

iOS 应用程序运行项目的屏幕截图

问题

大多数应用程序不希望代码首先从平台端调用。您的用例是什么?根据您的回答,我可能会提供更好的建议。我实现这个是为了处理发送到设备的推送通知,因此“事件”肯定是从平台端触发的。

另外,如果遇到错误和警告,您应该显示它们,例如No implementation found for method $method on channel $name'


Roh*_*Das -3

颤振端代码:

import 'dart:async';

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

class _MyHomePageState extends State<MyHomePage> {
  static const platform = MethodChannel('samples.flutter.dev/battery');

  // Get battery level.
  String _batteryLevel = 'Unknown battery level.';

  Future<void> _getBatteryLevel() async {
    String batteryLevel;
    try {
      final int result = await platform.invokeMethod('getBatteryLevel');
      batteryLevel = 'Battery level at $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to get battery level: '${e.message}'.";
    }

    setState(() {
      _batteryLevel = batteryLevel;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            ElevatedButton(
              child: Text('Get Battery Level'),
              onPressed: _getBatteryLevel,
            ),
            Text(_batteryLevel),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

快速代码在这里:

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
                                              binaryMessenger: controller.binaryMessenger)
    batteryChannel.setMethodCallHandler({
      [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
      // Note: this method is invoked on the UI thread.
      guard call.method == "getBatteryLevel" else {
        result(FlutterMethodNotImplemented)
        return
      }
      self?.receiveBatteryLevel(result: result)
    })

    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
Run Code Online (Sandbox Code Playgroud)

或者参考这个链接:

平台渠道

  • 这只是从 Flutter 文档中复制粘贴代码,而不理解问题或文档,甚至不解释它。 (3认同)