在Flutter项目遇到Release模式Android会黑屏的

2023-05-10  本文已影响0人  Jagtu

在Flutter项目遇到Release模式Android会黑屏的问题,最大的概率可能是在Flutter项目中使用相关屏幕适配有关

在Flutter项目开发中,界面的适配是一个常见的问题。设计师通常会提供设计稿的尺寸,但是在不同的设备上展示可能会出现布局错乱或者显示不完整的情况。为了解决这个问题,我们可以使用第三方库screen_ratio_adapter,它可以帮助我们在界面开发中直接使用设计稿的尺寸,并自动适配不同的设备尺寸。

screen_ratio_adapter库的作用类似于Spring框架中的AOP(面向切面编程)方式。它允许我们在不修改原有代码的情况下实现屏幕适配,而且不会影响我们的代码逻辑。

你可以在以下地址找到该库的源代码和详细文档:https://github.com/D-meng/screen_ratio_adapter

我们的项目是一个旧项目的维护工作,其中使用了screen_ratio_adapter库来实现屏幕适配。由于项目规模较大,并且出于时间和资源的考虑,我们无法一次性替换掉整个库,因此需要继续使用它。

然而,在升级至Flutter 3.3.9版本时,我们遇到了一个奇怪的问题。在Android端,debug模式下运行正常,但是如果将应用打包成release包,并在Android设备上安装后打开应用,则只会显示黑屏。

问题分析

经过分析,我们发现这个问题是由于Flutter新版本为了加快启动速度,修改了渲染逻辑。在屏幕尺寸还为空时,即在应用程序启动的早期阶段,Flutter会尝试渲染页面。而我们使用的screen_ratio_adapter库需要获取屏幕尺寸以进行比例缩放,因此在应用程序启动时就会尝试获取window.physicalSize的值。然而,在Dart代码运行之前,视图的大小可能是未知的。如果在应用程序生命周期的早期阶段观察到该值,可能会返回[Size.zero],导致界面无法正常渲染,从而导致黑屏的问题。

解决方案

为了解决这个问题,我们可以利用Flutter提供的window.onMetricsChanged方法来监听physicalSize的变化,并在有值时进行启动界面的渲染。具体的解决方案如下:


///设计稿尺寸,单位应是pt或dp
final _uiSize = BlueprintsRectangle(375, 667);

Future<void> main() async {

  if(window.physicalSize.isEmpty){
    window.onMetricsChanged = () async {
      //在回调中,size仍然有可能是0
      if(!window.physicalSize.isEmpty){
        window.onMetricsChanged = null;
        await waitScreenSizeAvailable(); //引入上面那段代码
        runMyAPP();
      }
    };
  } else{
    //如果size非0,则直接runApp
    await waitScreenSizeAvailable(); //引入上面那段代码
    runMyAPP();
  }
}


Future<void> waitScreenSizeAvailable() async {

  FxWidgetsFlutterBinding.ensureInitialized(uiBlueprints: _uiSize);

  if (!_hasScreenSize) {
    // WidgetsFlutterBinding.ensureInitialized();
    var observer = _Observer();
    WidgetsBinding.instance.addObserver(observer);
    await observer.hasScreenSize;
    WidgetsBinding.instance.removeObserver(observer);
  }
}

bool get _hasScreenSize => !window.physicalSize.isEmpty;

class _Observer extends WidgetsBindingObserver {
  final _screenSizeCompleter = Completer<void>();

  Future<void> get hasScreenSize => _screenSizeCompleter.future;

  @override
  void didChangeMetrics() {
    if (!_screenSizeCompleter.isCompleted && _hasScreenSize) {
      _screenSizeCompleter.complete();
    }
  }
}

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

上一篇下一篇

猜你喜欢

热点阅读