作为系列文章的第二十篇,本篇将结合官方的技术文档科普 Android 上 PlatformView 的实现逻辑,并且解释为什么在 Android 上 PlatformView 的键盘总是有问题。

为什么 iOS 上相对稳定,文中也做了对应介绍。

文章汇总地址:

Flutter 完整实战实战系列文章专栏

Flutter 番外的世界系列文章专栏

1、为什么有 PlatformView

因为 Flutter 的实现在概念上类似于 Android 上的 WebView,Flutter 是通过将 Widget Tree 转化为纹理后通过 Skia 实现控件绘制,这造就了优秀的跨平台效果的同时,也带来了不可逆的兼容问题。

1.1、无法集成原生平台控件

这就像 WebView 一样,Flutter UI 不会转换为 Android 控件,而是由 Flutter Engine 使用 Skia 直接在 SurfaceView 上渲染出来

这意味着默认情况下 Flutter UI 永远不会包含 Android Native 的控件,也就是说无法在 Flutter 中集成如 WebView 或 MapView 这些常用的控件。

所以为解决这个问题,Flutter 创建了一个叫 AndroidView 的控件逻辑, 开发者使用该 Widget 可以将 Android Native 组件嵌入到 Flutter UI 中

1.2、AndroidView 的实现

AndroidView 这个 Widget 需要和 Flutter 相结合才能完整显示:在 Flutter 中通过将 AndroidView 需要渲染的内容绘制到 VirtualDisplays 中 ,然后在 VirtualDisplay 对应的内存中,绘制的画面就可以通过其 Surface 获取得到

VirtualDisplay 类似于一个虚拟显示区域,需要结合 DisplayManager 一起调用,一般在副屏显示或者录屏场景下会用到。VirtualDisplay 会将虚拟显示区域的内容渲染在一个 Surface 上。


如上图所示,简单来说就是原生控件的内容被绘制到内存里,然后 Flutter Engine 通过相对应的 textureId 就可以获取到控件的渲染数据并显示出来

通过从 VirtualDisplay 输出中获取纹理,并将其和 Flutter 原有的 UI 渲染树混合,使得 Flutter 可以在自己的 Flutter Widget tree 中以图形方式插入 Android 原生控件。

1.3、 有其他可以实现的方式吗?

在 iOS 平台上就不使用类似 VirtualDisplay 的方法,而是通过将 Flutter UI 分为两个透明纹理来完成组合:一个在 iOS 平台视图之下,一个在其上面

所以这样的好处就是:需要在“iOS平台”视图下方呈现的Flutter UI,最终会被绘制到其下方的纹理上;而需要在“平台”上方呈现的Flutter UI,最终会被绘制在其上方的纹理。它们只需要在最后组合起来就可以了

通常这种方法更好,因为这意味着 Android Native View 可以直接添加到 Flutter 的 UI 层次结构中。

但是,Android 平台并不支持这种模式,因为在 iOS 上框架渲染后系统会有回调通知,例如:当 iOS 视图向下移动 2px 时,我们也可以将其列表中的所有其他 Flutter 控件也向下渲染 2px

但是在 Android 上就没有任何有关的系统 API,因此无法实现同步输出的渲染。如果强行以这种方式在 Android 上使用,最终将产生很多如  AndroidView 与 Flutter UI 不同步的问题

有关此替代方法的详细讨论,详见 https://flutter.dev/go/nshc

2、相关问题和解决方法

尽管前面可以使用 VirtualDisplay 将 Android 控件嵌入到 Flutter UI 中 ,但这种 VirtualDisplay 的介入还有其他麻烦的问题需要处理。

2.1、触摸事件

默认情况下, PlatformViews 是没办法接收触摸事件

因为 AndroidView 其实是被渲染在 VirtualDisplay 中 ,而每当用户点击看到的 "AndroidView" 时,其实他们就真正”点击的是正在渲染的 Flutter 纹理 。用户产生的触摸事件是直接发送到 Flutter View 中,而不是他们实际点击的 AndroidView

2.1.1、解决方法

  • AndroidView 使用 Flutter Framework 中的点击测试逻辑来检测用户的触摸是否在需要特殊处理的区域内。

类似可见:《Flutter完整开发实战详解(十三、全面深入触摸和滑动原理)》

  • 当触摸成功时会向 Android embedding 发送一条消息,其中包含 touch 事件的详细信息。

  • 在 Android embedding 中,该事件的坐标最后会匹配到 AndroidView 在 VirtualDisplay 中的坐标,然后会创建一个 MotionEvent 用于 描述触摸的新控件,并将其转发到内部 VirtualDisplay 中真实的 AndroidView 中进行响应。

2.1.2、局限性

  • 该实现逻辑会将新的 MotionEvent 直接分发给 AndroidView ,如果这个 View 又派生了其他视图,那么就可能会出现触摸信息被发送到错误的位置。

  • MotionEvent 的转化过程中可能会因为机制的不同,存在某些信息没办法完整转化的丢失。

2.2、文字输入

通常,AndroidView 是无法获取到文本输入,因为 VirtualDisplay 所在的位置会始终被认为是 unfocused 的状态

Android 目前不提供任何 API 来动态设置或更改的焦点 WindowFlutter 中focused 的 Window 通常是实际持有“真实的” Flutter 纹理和 UI ,并且对于用户直接可见。

而 InputConnections(如何在 Android 中 输入文本)在 unfocused 的 View 中通常是会被丢弃

2.2.1、解决方法

  • Flutter 重写了 checkInputConnectionProxy 方法,这样 Android 会认为 Flutter View 是作为 AndroidView 和输入法编辑器(IME)的代理,这样 Android 就可以从 Flutter View 中获取到 InputConnections 然后作用于 AndroidView 上面。

  • 在 Android Q 开始 InputMethodManager(IMM)改为每个 Window 自己实例化而不是全局单例。因此之前幼稚的“设置代理”的模式在 Q 开始不起作用。为了进一步解决这个问题,Flutter 创建了一个 Context 的子类, 该子类返回的内容与 Flutter View 中的 IMM 相同,这样就不会需要在查询 IMM 时需要返回的真实的  Window。这意味着当 Android 需要 IMM 时,VirtualDisplay 仍然会使用 Flutter View 的 IMM 作为代理。

  • 当要求 AndroidView 提供 InputConnection 时,它会检查 AndroidView 是否确实是输入的目标。如果是,那 AndroidView 中的 InputConnection 将被获取并返回给 Android  。

  • Android 认为 Flutter View 是 focused 且可用的,因此 AndroidView 的  InputConnection 可以成功被获取并使用。

2.2.2、 Platforview 中的 WebView 键盘输入

在 Android N 之前的版本上 WebView 输入比较复杂,因为它们具有自己内部的逻辑来创建和设置输入连接,而这些输入连接并没有完全遵循 Android 的协议。在 flutter_webview 插件中,还需要添加其他解决方法以便在可以在  WebView 启用文本输入。

  • 设置一个代理 View ,该 View 与 WebView 在相同的线程上侦听输入连接。如果没有此功能,WebView 将在内部消耗所有 InputConnection 的呼叫,而不会通知 Flutter View 代理。
  • 在代理线程中,返回 Flutter View 以创建输入。。
  • WebView 失去焦点时,将输入连接重置回 Flutter 线程。这样可以防止文本输入“卡”在 WebView 内。

2.2.3、局限性

  • 通常这个逻辑取决于 Android 的内部行为,并且可能会十分脆弱,比如: 1.12 版本下针对华为等设备出现的键盘输入异常等问题。

  • 某些文本功能仍然不可用,例如:“复制”和“共享”对话框当前不可用。

3、总结

PlatformView 的实现模式增加了 Flutter 的生命力和活力,但是相对的也引出了很多问题,比如 #webview-keyboard、#webview、#platform-views 相关的 issue 专题高居不下,并且如 webview_flutter 插件的文档所述:

该插件依赖 Flutter 的新机制来嵌入 Android 和 iOS 视图。由于该机制当前处于开发人员预览中,因此该插件也应被视为开发人员预览。

webview_flutter 的键盘支持也尚未准备好用于生产,因为 Webview 中的键盘支持目前还处于实验性的阶段。

所以到这里相信你应该知道,为什么 Flutter 中的 PlatforView 在 Android 上如此之难兼容,并且键盘输入问题会那么多坑了

自此,第二十篇终于结束了!(///▽///)

 创作不易,点个“在看

flutter 获取android 还是ios_Flutter完整开发实战详解(二十、 Android PlatformView 和键盘问题)...相关推荐

  1. Flutter完整开发实战详解(二、 快速开发实战篇) | 掘金技术征文

     作为系列文章的第二篇,继<Flutter完整开发实战详解(一.Dart语言和Flutter基础)>之后,本篇将为你着重展示:如何搭建一个通用的Flutter App 常用功能脚手架,快速 ...

  2. Flutter完整开发实战详解(十七、 实用技巧与填坑二)

    作为系列文章的第十七篇,本篇再一次带来 Flutter 开发过程中的实用技巧,让你继续弯道超车,全篇均为个人的日常干货总结,以实用填坑为主,让你少走弯路狂飙车. Flutter 完整实战实战系列文章专 ...

  3. element布局容器大小_Flutter完整开发实战详解(十六、详解自定义布局实战)

    本篇将解析 Flutter 中自定义布局的原理,并带你深入实战自定义布局的流程,利用两种自定义布局的实现方式,完成如下图所示的界面效果,看完这一篇你将可以更轻松的对 Flutter 为所欲为. 文章汇 ...

  4. 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...

  5. 《Android Studio应用开发实战详解》——第1章,第1.4节Android和Linux的关系

    本节书摘来自异步社区<Android Studio应用开发实战详解>一书中的第1章,第1.4节Android和Linux的关系,作者 王翠萍,更多章节内容可以访问云栖社区"异步社 ...

  6. 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——2.1节简析Android安装文件...

    本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第2章,第2.1节简析Android安装文件,作者 王石磊 , 吴峥,更多章节内容可以访问 ...

  7. 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——1.2节Android的巨大优势...

    本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第1章,第1.2节Android的巨大优势,作者 王石磊 , 吴峥,更多章节内容可以访问云 ...

  8. 《Android 平板电脑开发实战详解和典型案例》——1.1节平板电脑基础知识概览...

    本节书摘来自异步社区<Android 平板电脑开发实战详解和典型案例>一书中的第1章,第1.1节平板电脑基础知识概览,作者 吴亚峰 , 杜化美 , 索依娜,更多章节内容可以访问云栖社区&q ...

  9. Android NFC开发实战详解

    Android NFC开发实战详解 Android开发实战详解NFC国内第一本AndroidNFC开发书籍带你开启AndroidNFC开发的神秘之旅大综合案例帮助读者快速进入实战角色:WiFi快速连接 ...

最新文章

  1. 最佳页面置换算法代码_(存储管理)页面置换算法
  2. 分布式配置中心disconf第三部(基于xml配置的实现原理)
  3. 5 年开发搞不定 MySQL !
  4. 【Karma】多环境自动测试框架 -- 基础教程
  5. 【NLP】NER数据标注中的标签一致性验证
  6. eclipse官网下载详细指南
  7. 被问到了!为什么一定要使用分布式,内行啊
  8. Linux Shell编程之脚本执行方式
  9. 去除报错_转录组分析 | 使用trimgalore去除低质量的reads和adaptor
  10. mysql4ge表联表查询_【MySQL】MariaDB10.2新特性--Flashback
  11. 3D世界相机防抖杆的机制探究
  12. 关于C++编写com和调用com组件的小例子以及个人所犯错误见解
  13. 【数据库】E-R图相关知识、绘制方法及工具推荐
  14. 贝壳DMP平台建设实践
  15. HP580G7服务器电流
  16. html的绝对定位脱离文档流吗,子元素position:absolute定位之后脱离文档流,怎么使子元素撑开父元素...
  17. 为什么应该为“数据时代原住民”打造智能产品?
  18. DSGN: Deep Stereo Geometry Network for 3D Object Detection---基于双目视觉的3D目标检测(1)
  19. You Aren’t Special
  20. C++ 手把手教你实现可变长的数组

热门文章

  1. Fluent Ribbon项目出现“命名空间“clr-namespace:Fluent;assembly=Fluent”中不存在“RibbonWindow”名称”的解决方法...
  2. Discuz!NT实际安装流程
  3. 举例说明操作系统在计算机系统中的重要地位,第一二三章作业参考答案
  4. 写python代码的心得体会_写python代码的一点感想
  5. 数据库单表数据过亿_我也能写数据库 —— 单表查询
  6. 如何提高服务器响应的数据速度_如何提高服务器并发处理能力
  7. 创新元旦新年PSD分层海报,新气象开启!
  8. 手绘水彩卡通插画 | 艺术品因有灵魂而珍藏
  9. 高质量的设计灵感社区网站
  10. UI搜索栏设计素材模板|设计原则