前期开发调试时一直都是在真机上运行的debug包,没有发现随机黑屏的问题,准备上架打release包后发现部分Android的机型会出现随机黑屏的问题,查了资料后说有以下原因:
1.混淆(未解决):
在android/app/build.gradle文件中添加以下配置
buildTypes {
release {
minifyEnabled false //关闭混淆
shrinkResources false //删除无用资源
signingConfig signingConfigs.release
...
}
}
2.关闭R8压缩,使用D8压缩(未解决):
在android/gradle.properties文件中增加
# 开启D8压缩
android.enableD8=true
# 关闭R8压缩
#android.enableR8=true
以上尝试后都没有解决问题,又考虑是否是Android和flutter生命周期不一致?项目使用了fishredux框架?
在android/app/src/main/kotlin/.../MainActivity.kt文件中写入Android原生的生命周期,重新编译后发现没执行这个文件,因为没有接触过Android原生,因此造成未执行的具体原因不清楚,但想来和生命周期不一致没关系。
将页面替换为flutter原生的写法不使用fishredux,重新编译后也没有解决问题。
到这里这个问题已经卡了我一周多了,没有报错无法定位问题,release也无法打断点,有点绝望,最后想实在不行就重构?那会不会是依赖或者环境的配置有问题?这样的话只能一个依赖一个依赖排查,重新搭环境看是哪里的问题,但着急上线哪有那么多时间真的想哭...。
我先排查了是否是依赖的问题,flutter create了一个新的项目,依次把原项目的依赖引入,发现依赖没问题,但这个新项目打release是没有黑屏问题的!那和原项目的区别就只在于入口的main文件不一样,把新建项目的main文件替换到原项目,打release后没有出现黑屏,OK!就是main文件里的问题!!!
以下为问题原因!解决!!!
main文件中有这样一段代码:
window.physicalSize监听屏幕尺寸大小,当不为空时执行window.onMetricsChanged回调
if(window.physicalSize.isEmpty){
window.onMetricsChanged = (){
//在回调中,size仍然有可能是0
if(!window.physicalSize.isEmpty){
window.onMetricsChanged = null;
runMyAPP();
}
};
} else{
//如果size非0,则直接runApp
runMyAPP();
}
怀疑是这段代码的问题,于是把这段中的逻辑判断都注掉,只留了runApp,重新编译后发现没有黑屏了但随机出现页面错乱的现象。
出现黑屏和页面错乱的原因是flutter为了加快启动速度,屏幕尺寸还为空时就渲染页面。查了一下runApp前必须先WidgetsFlutterBinding.ensureInitialized(),确保有WidgetsFlutterBinding实例,修改上述代码为:
if(window.physicalSize.isEmpty){
window.onMetricsChanged = (){
//在回调中,size仍然有可能是0
if(!window.physicalSize.isEmpty){
window.onMetricsChanged = null;
runMyAPP();
}
};
} else{
//如果size非0,则直接runApp
runMyAPP();
}
void runMyApp() async{
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
编译后依旧没有解决问题,在Stack Overflow上有人遇到了同样的问题,提供了一段代码:
import 'dart:async';
import 'dart:ui';
import 'package:flutter/widgets.dart';
Future<void> waitScreenSizeAvailable() async {
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();
}
}
}
修改main文件中的代码为:
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();
}
编译后问题解决!!!!!
这个问题前后卡了快两周,全程没有任何报错信息导致无法定位问题,再加上release没法打断点,只能盲猜问题可能在哪再一步步排查。不过总算是解决了,泪目...