You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含极简逻辑及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无法显示的核心原因:

  1. 日期格式化后多余调用翻译方法:DateFormat('MMMM')在指定对应locale后已经会输出对应语言的月份名称,后续多余调用tr()会触发翻译查找逻辑,如果翻译文件中没有对应月份的小写key,会返回空值或原字符串,后续调用substring(0,3)时如果字符串长度不足会抛出范围异常,导致控件渲染失败。
  2. DateFormat未显式指定locale:未显式传入locale的情况下,DateFormat会使用系统默认locale,在iOS 14这类旧版本系统上容易出现兼容问题,返回不符合预期的结果。
  3. 强制解包无兜底逻辑:代码中大量使用!强制解包,若客户设备上的行程数据中startDate为空,会直接抛出空指针异常,导致逻辑中断。

修复步骤

  1. 修正月份处理逻辑,移除多余的翻译调用,显式指定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)
  1. 所有substring调用前添加长度校验,避免范围异常:
// 星期截取修正
controller.getDayOfWeek(...).tr().padRight(2).substring(0,2)
// 月份截取修正
DateFormat('MMMM', 'de_CH').format(tempDate).toLowerCase().padRight(3).substring(0,3)
  1. 替换所有强制解包逻辑,添加兜底判断:
// 先判断非空再执行弹窗逻辑
final tour = controller.tour;
if (tour.tourDays == null || tour.startDate == null) return;
final numberOfDays = tour.tourDays!.length;
final startDate = tour.startDate!;
  1. 若使用intl包做本地化,确认Info.plist中已添加德语作为支持的本地化语言,避免iOS系统拦截locale设置。
  2. 若上述修改后仍无法复现问题,可给客户推送带埋点日志的TestFlight版本,在弹窗逻辑的每一步添加日志输出,定位具体中断节点。

内容的提问来源于stack exchange,提问作者Abdelrahman Scherif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 02:27:03