繁体   English   中英

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

[英]How do I use a Flutter MethodChannel to invoke a method in dart code from the native swift code?

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

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

有谁知道我哪里出错了? 我知道我没有对methodChannel.invokeMethod()的“name”参数采取行动,但那是因为我只想调用调用方法......

这是我的 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."); } }

这是我的 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) } }

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

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

在此先感谢您的帮助!!

颤振侧代码:

 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), ], ), ), ); } }

Swift 代码在这里:

 @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) } }

或者参考这个链接:

平台渠道

问题

问题是您的平台端(在本例中为 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");
  }
}

你可以在reverse_platform_methods看到一个工作项目,尤其是AppDelegate.swift 我没有为 Android 实现它,但你可以在MainActivity.kt中以类似的方式实现它。

运行项目的 iOS 应用截图

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

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

嗯,问题全在于初始化过程。 在 dart/flutter 部分准备好处理它之前,您尝试从 swift 代码中调用您的方法。

您必须执行以下步骤才能获得结果:

  1. 重要的。 在你的AppDelegate for ios 中使用这个方法
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    
 var methodChannel: FlutterMethodChannel? = nil

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {

    print("Setup methodChannel from Swift")
    let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
    methodChannel = FlutterMethodChannel(name: "com.example.channeltest/changetext", binaryMessenger: rootViewController as! FlutterBinaryMessenger)

    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
    
    //THIS METHOD
    override func applicationDidBecomeActive(_ application: UIApplication) {
        methodChannel?.invokeMethod("some_method_name", arguments: "ios string")
    }
}

对于安卓:

class MainActivity : FlutterActivity() {
    var channel: MethodChannel? = null

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        channel = MethodChannel(
            flutterEngine.dartExecutor.binaryMessenger,
            "com.example.channeltest/changetext"
        )

    }

    override fun onStart() {
        super.onStart()
        channel?.invokeMethod("some_method_name", "android str")
    }
}
  1. 使用MethodChannel创建您自己的类( MethodChannel答案)
class TestChannel {
  static MethodChannel channel =
  const MethodChannel("com.example.channeltest/changetext");

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

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

  TestChannel() {
    channel.setMethodCallHandler((call) async {
      if (call.method == "some_method_name") {
        _controller.add(call.arguments as String);
      } else {
        print("Method not implemented: ${call.method}");
      }
    });
  }
}
  1. 重要的。 创建它的全局实例
final _changeTextChannel = TestChannel(); //<--- like this

void main() {
  runApp(MyApp());
}
  1. 在 UI 中处理它
class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: StreamBuilder<String>(
        stream: _changeTextChannel.stringStream,
        builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
          if (snapshot.hasError) {
            return Text("Error");
          }

          if (!snapshot.hasData) {
            return Text("Loading");
          }

          return Text(snapshot.data ?? "NO_DATA");
        },
      )),
    );
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM