flutter_boost icon indicating copy to clipboard operation
flutter_boost copied to clipboard

[Bug]: InAppWebView 加载异常(platformView集成显示异常)(必现)

Open marchlqq opened this issue 1 year ago • 25 comments

请描述遇到的问题,以及您所期望的正确的结果

flutter版本从3.16.9升级到3.24.5(升级到3.19.0,也是一样), 同样的代码,FlutterFragment 显示的 platformView 加载异常。 希望显示正常。

请说明如何操作会遇到上述问题

出现方式: 1、点击 open flutter fragment page 2、切换 tab 必现。

问题视频: https://github.com/user-attachments/assets/3db5bae0-58dd-420a-9328-1ebfafce9370

在下面填入关键复现代码

flutter版本从3.16.9升级到3.24.5(升级到3.19.0,也是一样),

InAppWebView 加载的view,50%会加载异常,白屏或者是加载完成以后动不了

代码: example.zip

复现的平台

Both

Flutter SDK版本

3.24.5

FlutterBoost版本

5.0.1,5.0.2

是否延迟初始化FlutterBoost

No

解决方案

marchlqq avatar Nov 29 '24 08:11 marchlqq

暂时没有思路,感觉跟生命周期也没关系,因为50%的概率显示,感觉那个地方有缓存,第一次加载失败,第二次就重新加载,反复如此。 我对比了加载成功和失败的日志,基本都是一模一样的。调试也没发现太大出入。 之前使用的flutter 3.16.9,显示没有问题。 @0xZOne

marchlqq avatar Nov 29 '24 08:11 marchlqq

我们项目中遇到了同样的问题 flutter 3.16.9版本没有问题 3.24.5版本 platformView @加载异常,从日志分析没有异常。希望可以提供解决思路 @0xZOne

JokerGHit avatar Nov 29 '24 09:11 JokerGHit

可以先设置InAppWebViewSettings里的useHybridComposition参数为false,来解决。 我发现目前FlutterBoost里有关PlatformView的一些异常问题,都是因为useHybridComposition这个玩意儿导致,更里面就是使用了PlatformViewsService.initExpensiveAndroidView导致的。直接使用AndroidView或者PlatformViewsService的其他init方法就没事。

joechan-cq avatar Dec 02 '24 09:12 joechan-cq

触发的原因大概查到了,和#1960 的问题一样,都是FlutterTextureViewisPaused变量的问题,这个变量会作为FlutterRender.startRenderingToSurface方法的第二个参数传入,然后这个startRenderingToSurface在3.16和3.19上的区别:

3.16: image

3.19: image

可以看到区别在于3.16中最后只会调用flutterJNI.onSurfaceCreated,而3.19会区分调用flutterJNI.onSurfaceCreatedflutterJNI.onSurfaceWindowChanged,然后就和#1960 里一个表现了。

那么再看isPaused为什么是true,是因为触发了FlutterView.convertToImageView方法,里面的renderSurface.pause()使其变成了trueimage

joechan-cq avatar Dec 03 '24 09:12 joechan-cq

根据Flutter 深入探索混合开发的技术演进这篇文章里面所写,另一种解法是在Flutter层调用

 PlatformViewsService.synchronizeToNativeViewHierarchy(false);

不过我看这个方法在高版本Flutter SDK里已经没了,不过Java层的方法定义还在,因此可以这么写:

SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false);

其实就是不让用FlutterImageView

joechan-cq avatar Dec 03 '24 09:12 joechan-cq

确实,设置了 SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 查看的话,少了 FlutterImageView。 对比3.16.9,和3.19.0,设置 Hybrid Composition,view集成方式也出现了变化。

但是,文档也说明了:那为什么会有把 FlutterSurfaceView 变成了 FlutterImageView 这样的操作?原因其实是为了更好的动画同步和渲染效果。

现在去掉了,demo目前看不出有什么问题,项目中还没验证。这里采用 synchronizeToNativeViewHierarchy,去掉,会有什么影响吗?暂时看不出来。

  1. synchronizeToNativeViewHierarchy 方法 作用: 这个方法用于确保 Flutter 的视图层次结构与原生视图层次结构同步。这在使用 Hybrid Composition 时尤其重要,因为你可能希望 Flutter 渲染的内容与原生 UI 组件无缝集成。 去掉的影响: 如果你去掉了 synchronizeToNativeViewHierarchy 的调用,可能会导致 Flutter 渲染的内容与原生视图的层次结构不同步。这可能会影响到视图的交互、动画效果和性能。 在某些情况下,可能不会立即发现显著问题,但在复杂的 UI 或动画场景中,潜在的问题可能会显现出来

marchlqq avatar Dec 04 '24 06:12 marchlqq

我的想法是如果PlatformView和Flutter上的UI没有复杂的交叉层级堆叠显示的问题,那么就没必要使用Hybrid模式。 如果想继续使用Hybrid,只要想办法让代码去触发onSurfaceCreated就行。

joechan-cq avatar Dec 04 '24 06:12 joechan-cq

嗯,暂时看是的。最好的办法,还是flutter,去修复这个问题,或者看看在什么合适的时机,改变 isPaused 状态。就跟之前手动处理的 platformview 的显示和隐藏一样。

marchlqq avatar Dec 04 '24 07:12 marchlqq

这个应该很难让Flutter去修改了,因为纯Flutter不存在跨Activity切换Surface的情况。真要FlutterBoost解决这个问题,之前为了修复 #1960 的PR里的动态代理的方案改改应该是能用的。

joechan-cq avatar Dec 04 '24 07:12 joechan-cq

这个应该很难让Flutter去修改了,因为纯Flutter不存在跨Activity切换Surface的情况。真要FlutterBoost解决这个问题,之前为了修复 #1960 的PR里的动态代理的方案改改应该是能用的。

最近苹果升级到 18.2 版本,必须得升级到 3.27.1,然后这个修改,又无效化了。

image

设置了 SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 反而显示白屏了。 不设置,又还是之前的问题。可能底层又改了 surface 的状态。

marchlqq avatar Dec 18 '24 02:12 marchlqq

查了一下,是 FlutterMutatorView 变成了 gone,不知道哪里出了问题,还得查查。 image

marchlqq avatar Dec 18 '24 02:12 marchlqq

这里增加了 initializePlatformViewIfNeeded(viewId),导致 return 了。 public void onDisplayPlatformView( int viewId, int x, int y, int width, int height, int viewWidth, int viewHeight, @NonNull FlutterMutatorsStack mutatorsStack) { initializeRootImageViewIfNeeded(); if (!initializePlatformViewIfNeeded(viewId)) { return; }

导致,后面的 contains 为false,然后platformView就没有显示。 if (currentFrameUsedPlatformViewIds.contains(viewId) && (isFrameRenderedUsingImageReaders || !synchronizeToNativeViewHierarchy)) { parentView.setVisibility(View.VISIBLE); } else { parentView.setVisibility(View.GONE); }

marchlqq avatar Dec 18 '24 08:12 marchlqq

我去flutter里面也增加了提问,看看那边有什么解释。 https://github.com/flutter/flutter/issues/160490

marchlqq avatar Dec 18 '24 09:12 marchlqq

我调试运行后,方法 onBeginFrame,在运行几次以后,后面不会运行 onDisplayOverlaySurface, 3.24.5: onBeginFrame -> onDisplayPlatformView -> onEndFrame

3.27.1: 开始运行: onBeginFrame -> onDisplayPlatformView -> onEndFrame

运行几次以后: onBeginFrame -> onEndFrame

暂时不清楚原因。

我看跟方法改动:

    initializeRootImageViewIfNeeded();
    if (!initializePlatformViewIfNeeded(viewId)) {
      return;
    }

关系不大。

marchlqq avatar Dec 19 '24 03:12 marchlqq

我这边在flutter boost的example中的webview_flutter_demo.dart里的weview的实现改成InAppWebView,并没有出现你说的问题。

joechan-cq avatar Dec 19 '24 08:12 joechan-cq

需要增加代码:

SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false);

最后我的回复,我下午尝试复现了:https://github.com/flutter/flutter/issues/160490

marchlqq avatar Dec 19 '24 08:12 marchlqq

@joechan-cq 有复现没?你改成 InAppWebView,需要运行一下 SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 是必现的,我继承 PlatformViewsController,在方法 onEndFrame,强制可见,也不行。

marchlqq avatar Dec 20 '24 07:12 marchlqq

@joechan-cq 还是使用 FlutterImageView 的话,可以处理吗? 就是这段代码不加, SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 我发现是flutter 那边的engine c++代码修改,造成的这个问题,暂时不清楚该如何解决。他们目前也没有回复。 https://github.com/flutter/flutter/issues/160490

marchlqq avatar Dec 24 '24 01:12 marchlqq

@joechan-cq 有复现没?你改成 InAppWebView,需要运行一下 SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 是必现的,我继承 PlatformViewsController,在方法 onEndFrame,强制可见,也不行。

我用inAppWebView的项目,加synchronizeToNativeViewHierarchy代码也没有复现。

joechan-cq avatar Dec 24 '24 02:12 joechan-cq

@joechan-cq 还是使用 FlutterImageView 的话,可以处理吗? 就是这段代码不加, SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 我发现是flutter 那边的engine c++代码修改,造成的这个问题,暂时不清楚该如何解决。他们目前也没有回复。 flutter/flutter#160490

如你之前所说,修改isPaused的值应该就行了

joechan-cq avatar Dec 24 '24 02:12 joechan-cq

@joechan-cq 有复现没?你改成 InAppWebView,需要运行一下 SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 是必现的,我继承 PlatformViewsController,在方法 onEndFrame,强制可见,也不行。

我用inAppWebView的项目,加synchronizeToNativeViewHierarchy代码也没有复现。

需要用3.27.1的flutter版本。

修改isPaused,我晚点试试。

marchlqq avatar Dec 24 '24 02:12 marchlqq

@joechan-cq 有复现没?你改成 InAppWebView,需要运行一下 SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 是必现的,我继承 PlatformViewsController,在方法 onEndFrame,强制可见,也不行。

我用inAppWebView的项目,加synchronizeToNativeViewHierarchy代码也没有复现。

需要用3.27.1的flutter版本。

修改isPaused,我晚点试试。

是的, 我用的就是3.27.1的Flutter。这么看,可能和设备也有关系

joechan-cq avatar Dec 24 '24 02:12 joechan-cq

看engine那边的提交记录,确实和设备GPU型号有关,另外不用Impeller估计也没这个问题。

joechan-cq avatar Dec 24 '24 02:12 joechan-cq

我这边验证了小米+oppo,一共4台设置,都是必白屏。也可能这几台设备都差不多吧。

marchlqq avatar Dec 24 '24 02:12 marchlqq

@joechan-cq 还是使用 FlutterImageView 的话,可以处理吗? 就是这段代码不加, SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 我发现是flutter 那边的engine c++代码修改,造成的这个问题,暂时不清楚该如何解决。他们目前也没有回复。 flutter/flutter#160490

如你之前所说,修改isPaused的值应该就行了

我验证了,单独反射调用,时机上不好弄,在 FlutterEngineAttachmentListener 里面调用,反射不行,找到 flutterView的方法,revertImageView 里面有调用 resume,使用以后,是可行的。

// 解决HybridComposition PlatformView中间页面问题
flutterView.addFlutterEngineAttachmentListener(new FlutterView.FlutterEngineAttachmentListener() {
    @Override
    public void onFlutterEngineAttachedToFlutterView(@NonNull FlutterEngine engine) {
        FlutterBoostFixUtil.log(FlutterBoostFixUtil.TAG, "onFlutterEngineAttachedToFlutterView: ");
        // 显示之前的记录的platform view
        showPlatformViews(true);
        if (flutterView != null) {
            flutterView.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onFlutterEngineDetachedFromFlutterView() {
        FlutterBoostFixUtil.log(FlutterBoostFixUtil.TAG, "onFlutterEngineDetachedFromFlutterView: ");
        // 解决platformView 切换的时候,显示异常的问题
        // 这里根据url 记录platform view,隐藏view
        FlutterBoostFixUtil.findFlutterPlatformViews(FlutterBoostActivity.this, platformViews,getFlutterEngine(), getUrl());
        if (flutterView != null) {
            // 解决flutter 从3.16.9,升级到3.24.x,flutter platformView 显示异常的问题
            // platformView 的状态存在问题,flutter 升级以后,renderSurface 调用了 pause 改变了状态,需要调用 resume 改变回去
            // 1、单独调用 resume 没有效果;2、使用 SystemChannels.platform_views.invokeMethod('synchronizeToNativeViewHierarchy', false); 存在 3.27.0,升级到3.27.1,flutter 白屏的问题
            // # https://github.com/alibaba/flutter_boost/issues/2161
            flutterView.revertImageView(new Runnable() {
                @Override
                public void run() {

                }
            });
            flutterView.setVisibility(View.INVISIBLE);
        }
        showPlatformViews(false);
    }
});

marchlqq avatar Dec 24 '24 06:12 marchlqq