• Flutter实战-自定义键盘(三)


    5e0577fa429ee51680be183ebe857c9c.jpeg用了两年的flutter,有了一些心得,从今天开始陆续更新一些案例,不虚头巴脑,只求实战有用,以供学习或使用flutter的小伙伴参考,学习尚浅,如有不正确的地方还望各路大神指正,以免误人子弟,在此拜谢~(原创不易,转发请标注来源和作者)

    注意:无特殊说明,flutter版本为3.0+


    当初写该组件的时候flutter的版本是2.1,直到有一天flutter 升级到2.5版本后,发现键盘突然不能用了,发现是官方废弃了TestDefaultBinaryMessenger,

    /// [WidgetTester], [TestWidgetsFlutterBinding], [TestDefaultBinaryMessenger],
    /// and [TestDefaultBinaryMessenger.handlePlatformMessage] respectively).
    ///
    /// To register a handler for a given message channel, see [setMessageHandler].
    ///
    /// To send a message _to_ a plugin on the platform thread, see [send].
    // TODO(ianh): deprecate this method once cocoon and other customer_tests are migrated:
    // @NotYetDeprecated(
    // 'Instead of calling this method, use ServicesBinding.instance.channelBuffers.push. '
    // 'In tests, consider using tester.binding.defaultBinaryMessenger.handlePlatformMessage '
    /
    / 'or TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.handlePlatformMessage. '
    // 'This feature was deprecated after v2.1.0-10.0.pre.'
    // )
    Future handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback);

    当时cool_ui的作者也没有发布新版本,那么如何解决这个问题呢,那就是重新写一个自己的BinaryMessenger。


    一.定义自己的WidgetsFlutterBinding

    不了解WidgetsFlutterBinding 的读者可以看我之前的文章,那首先我们要复写ServicesBingding,这个bingding是 用来处理flutter和原生交互用的

    class MyWidgetsFlutterBinding extends WidgetsFlutterBinding with MyServicesBinding {
    static WidgetsBinding? ensureInitialized() {
        MyWidgetsFlutterBinding();
    return WidgetsBinding.instance;
    }
    }

    mixin MyServicesBinding on BindingBase, ServicesBinding {
    @override
    BinaryMessenger createBinaryMessenger() {
        return TestDefaultBinaryMessenger(super.createBinaryMessenger());
    }
    }

    看源码中我们知道默认走的是系统的DefaultBinaryMessenger。

    我们先看源码

    class _DefaultBinaryMessenger extends BinaryMessenger {
    const _DefaultBinaryMessenger._();

    @override
    Future handlePlatformMessage(
    String channel,
    ByteData? message,
    ui.PlatformMessageResponseCallback? callback,
    ) async {
    ui.channelBuffers.push(channel, message, (ByteData? data) {
    if (callback != null)
    callback(data);
    });
    }

    @override
    Future send(String channel, ByteData? message) {
    final Completer completer = Completer();
    // ui.PlatformDispatcher.instance is accessed directly instead of using
    // ServicesBinding.instance.platformDispatcher because this method might be
    // invoked before any binding is initialized. This issue was reported in
    // #27541. It is not ideal to statically access
    // ui.PlatformDispatcher.instance because the PlatformDispatcher may be
    // dependency injected elsewhere with a different instance. However, static
    // access at this location seems to be the least bad option.
    // TODO(ianh): Use ServicesBinding.instance once we have better diagnostics
    // on that getter.
    ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
    try {
    completer.complete(reply);
    } catch (exception, stack) {
    FlutterError.reportError(FlutterErrorDetails(
    exception: exception,
    stack: stack,
    library: 'services library',
    context: ErrorDescription('during a platform message response callback'),
    ));
    }
    });
    return completer.future;
    }

    @override
    void setMessageHandler(String channel, MessageHandler? handler) {
    if (handler == null) {
    ui.channelBuffers.clearListener(channel);
    } else {
    ui.channelBuffers.setListener(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
    ByteData? response;
    try {
    response = await handler(data);
    } catch (exception, stack) {
    FlutterError.reportError(FlutterErrorDetails(
    exception: exception,
    stack: stack,
    library: 'services library',
    context: ErrorDescription('during a platform message callback'),
    ));
    } finally {
    callback(response);
    }
    });
    }
    }
    }

    这个也是实现了BinaryMessenger的方法,那我们的思路就是在默认方法中拦截并调用自己的方法

    final Map _outboundHandlers = {};


    @override
    void setMessageHandler(String channel, MessageHandler? handler) {
    if (handler != null && handler.toString().contains("_textInputHanlde")) {
    _outboundHandlers[channel] = handler;
    return;
    }

    ...

    当含有_textInputHanlde的时候,将处理方法改成自己的,然后再send的时候调用。

    @override
    Future send(String channel, ByteData? message) {
    final Completer completer = Completer();

    final Future? resultFuture;
    final MessageHandler? handler = _outboundHandlers[channel];
    if (handler != null) {
    resultFuture = handler(message);
    return resultFuture!;
    }

    ...

    这样就实现了拦截。

    二。使用

    在Main函数中,runApp()之前调用以下方法

    MyWidgetsFlutterBinding.ensureInitialized();


    附属源码:

    import 'dart:async';

    import 'package:flutter/foundation.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'dart:ui' as ui;

    class MyWidgetsFlutterBinding extends WidgetsFlutterBinding with MyServicesBinding {
    static WidgetsBinding? ensureInitialized() {
    MyWidgetsFlutterBinding();
    return WidgetsBinding.instance;
    }
    }

    mixin MyServicesBinding on BindingBase, ServicesBinding {
    @override
    BinaryMessenger createBinaryMessenger() {
    return TestDefaultBinaryMessenger(super.createBinaryMessenger());
    }
    }

    class TestDefaultBinaryMessenger extends BinaryMessenger {
    final BinaryMessenger origin;

    TestDefaultBinaryMessenger(this.origin);

    final Map _outboundHandlers = {};

    @override
    Future send(String channel, ByteData? message) {
    final Completer completer = Completer();

    final Future? resultFuture;
    final MessageHandler? handler = _outboundHandlers[channel];
    if (handler != null) {
    resultFuture = handler(message);
    return resultFuture!;
    }

    ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
    try {
    completer.complete(reply);
    } catch (exception, stack) {
    FlutterError.reportError(FlutterErrorDetails(
    exception: exception,
    stack: stack,
    library: 'services library',
    context: ErrorDescription('during a platform message response callback'),
    ));
    }
    });
    return completer.future;
    }

    @override
    void setMessageHandler(String channel, MessageHandler? handler) {
    if (handler != null && handler.toString().contains("_textInputHanlde")) {
    _outboundHandlers[channel] = handler;
    return;
    }
    if (handler == null) {
    ui.channelBuffers.clearListener(channel);
    } else {
    ui.channelBuffers.setListener(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
    ByteData? response;
    try {
    response = await handler(data);
    } catch (exception, stack) {
    FlutterError.reportError(FlutterErrorDetails(
    exception: exception,
    stack: stack,
    library: 'services library',
    context: ErrorDescription('during a platform message callback'),
    ));
    } finally {
    callback(response);
    }
    });
    }
    }

    @override
    Future handlePlatformMessage(
    String channel,
    ByteData? message,
    ui.PlatformMessageResponseCallback? callback,
    ) async {
    ui.channelBuffers.push(channel, message, (ByteData? data) {
    if (callback != null) callback(data);
    });
    }
    }

  • 相关阅读:
    北大肖臻老师《区块链技术与应用》系列课程学习笔记[20]以太坊-智能合约-1
    node写登录
    MySQL - 普通索引
    AUTOSAR规范与ECU软件开发(实践篇)10、AUTOSAR技术展望
    Fun和Do
    EV代码签名申请步骤
    jQuery_五角星评分/链式编程
    DDA数值微分法详解
    Python 处理 PDF —— PyMuPDF 的安装与使用
    愚人节礼物(C++)
  • 原文地址:https://blog.csdn.net/hantian616/article/details/125909473