含极简逻辑及DateFormat调用的对话框未在客户端iPhone上正常显示
问题描述
开发的应用内有一个点击后弹出对话框的按钮,该对话框逻辑非常简单,却无法在客户设备上正常显示。已在多台安卓模拟器和所有iOS模拟器上完成测试,功能完全正常,同时Crashlytics平台未收到任何来自客户设备的报错信息。
相关说明
- tourDays永远不为空
- 应用内其他多个animatedDialogs均可正常运行
- 客户居住在瑞士,使用设备为德语系统的iPhone 12 mini,系统版本为iOS 14.4.2
- 客户点击按钮后无任何响应
- 翻译文件运行状态正常
- 已将个人iPhone的地区和语言调整为和客户设备一致,但仍无法复现问题,怀疑是DateFormat类的使用存在问题
相关代码
按钮onPressed对应代码
final int numberOfDays = controller.tour.tourDays!.length; showAnimatedDialog( context: context, child: Dialog( backgroundColor: Colors.black, insetPadding: EdgeInsets.symmetric(horizontal: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8)), child: SizedBox( width: double.infinity, child: Padding( padding: const EdgeInsets.all(16.0), child: Wrap( crossAxisAlignment: WrapCrossAlignment.center, runSpacing: 30, children: List.generate(numberOfDays, (calendarIndex) { final tempDate = controller .tour.startDate! .add(Duration(days: calendarIndex)); return InkWell( onTap: () { Navigator.of(context).pop(); pageController .jumpToPage(calendarIndex); }, child: Container( decoration: index == calendarIndex ? BoxDecoration( border: Border.all( color: Constants.lightPink, width: 2, ), borderRadius: BorderRadius.circular(8)) : BoxDecoration(), width: (MediaQuery.of(context) .size .width - MediaQuery.of(context) .viewInsets .left - MediaQuery.of(context) .viewInsets .right - 64) / 3, child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( controller .getDayOfWeek(controller .tour .startDate! .weekday + calendarIndex) .tr() .substring(0, 2), style: Constants.boldMediumStyle .apply( color: Constants .lightPink), ), Text( tempDate.day.toString() + '. ' + DateFormat('MMMM') .format(DateTime .fromMillisecondsSinceEpoch( tempDate .millisecondsSinceEpoch)) .toLowerCase() .tr() .substring(0, 3) + ' ' + tempDate.year .toString() .substring(2, 4), style: Constants .regularSmallStyle .apply( color: Constants.lightPink, fontSizeDelta: -3, )), ], ), ), );
getDayOfWeek方法代码
String getDayOfWeek(int weekDay) { weekDay = weekDay % 7; String nameOfDay; switch (weekDay) { case 0: nameOfDay = 'sunday'; break; case 1: nameOfDay = 'monday'; break; case 2: nameOfDay = 'tuesday'; break; case 3: nameOfDay = 'wednesday'; break; case 4: nameOfDay = 'thursday'; break; case 5: nameOfDay = 'friday'; break; case 6: nameOfDay = 'saturday'; break; default: nameOfDay = 'NA'; break; } return nameOfDay; }
预期效果

问题排查与解决方案
核心问题定位
代码中存在三处极易在多语言旧版本iOS环境下触发渲染异常的逻辑,是导致dialog无法显示的核心原因:
- 日期格式化后多余调用翻译方法:
DateFormat('MMMM')在指定对应locale后已经会输出对应语言的月份名称,后续多余调用tr()会触发翻译查找逻辑,如果翻译文件中没有对应月份的小写key,会返回空值或原字符串,后续调用substring(0,3)时如果字符串长度不足会抛出范围异常,导致控件渲染失败。 - DateFormat未显式指定locale:未显式传入locale的情况下,
DateFormat会使用系统默认locale,在iOS 14这类旧版本系统上容易出现兼容问题,返回不符合预期的结果。 - 强制解包无兜底逻辑:代码中大量使用
!强制解包,若客户设备上的行程数据中startDate为空,会直接抛出空指针异常,导致逻辑中断。
修复步骤
- 修正月份处理逻辑,移除多余的翻译调用,显式指定DateFormat的locale,同时删除多余的DateTime转换逻辑:
// 修正前 DateFormat('MMMM') .format(DateTime.fromMillisecondsSinceEpoch(tempDate.millisecondsSinceEpoch)) .toLowerCase() .tr() .substring(0, 3) // 修正后(若使用多语言框架,locale参数可替换为框架提供的当前系统locale,瑞士德语对应值为de_CH) DateFormat('MMMM', 'de_CH') .format(tempDate) .toLowerCase() .substring(0, 3)
- 所有substring调用前添加长度校验,避免范围异常:
// 星期截取修正 controller.getDayOfWeek(...).tr().padRight(2).substring(0,2) // 月份截取修正 DateFormat('MMMM', 'de_CH').format(tempDate).toLowerCase().padRight(3).substring(0,3)
- 替换所有强制解包逻辑,添加兜底判断:
// 先判断非空再执行弹窗逻辑 final tour = controller.tour; if (tour.tourDays == null || tour.startDate == null) return; final numberOfDays = tour.tourDays!.length; final startDate = tour.startDate!;
- 若使用intl包做本地化,确认Info.plist中已添加德语作为支持的本地化语言,避免iOS系统拦截locale设置。
- 若上述修改后仍无法复现问题,可给客户推送带埋点日志的TestFlight版本,在弹窗逻辑的每一步添加日志输出,定位具体中断节点。
内容的提问来源于stack exchange,提问作者Abdelrahman Scherif
相关产品推荐
相关产品推荐

