登录文本字段在iPad Air M3(iPadOS 26)上似乎会清空——在iPhone或模拟器上无法重现
Our Flutter应用已被应用审核拒绝四次。审核人员报告,在运行iPadOS 26.4.2的 iPad Air 11英寸(M3)上,在邮箱/密码字段中输入文字会导致字段清空,无法登录。
我们无法在真实的iPhone(iOS 18.x)或iPad模拟器(iPadOS 26.3.1)上复现。
Flutter:3.41.4 | 状态管理:GetX
登录界面(简化版):
class LoginScreen extends StatelessWidget {
LoginScreen({super.key});
final AuthenticationController authenticationController =
Get.find<AuthenticationController>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: SizedBox(
height: height,
child: Obx( // <-- wraps the entire column
() => Column(
children: [
CommonTitleTextField(
textEditingController:
authenticationController.emailTextEditingController,
autofillHints: const [AutofillHints.email],
onChanged: (_) => authenticationController.checkCanLogin(),
),
CommonTitleTextField(
textEditingController:
authenticationController.passwordTextEditingController,
obscureText: authenticationController
.isLoginPasswordVisible.value, // observable read
suffixIcon: ...,
onSuffixPress: () {
authenticationController.isLoginPasswordVisible.value =
!authenticationController.isLoginPasswordVisible.value;
},
autofillHints: const [AutofillHints.password],
onChanged: (_) => authenticationController.checkCanLogin(),
),
// ...
],
),
),
),
),
);
}
}
控制器(相关部分):
class AuthenticationController extends GetxController {
// TextEditingControllers declared as fields — NOT inside build()
final TextEditingController emailTextEditingController =
TextEditingController();
final TextEditingController passwordTextEditingController =
TextEditingController();
final RxBool isLoginPasswordVisible = RxBool(true);
final RxBool canLogin = RxBool(false);
final RxBool isLoginLoading = RxBool(false);
void checkCanLogin() {
canLogin.value =
emailTextEditingController.text.trim().isNotEmpty &&
passwordTextEditingController.text.trim().isNotEmpty &&
passwordTextEditingController.text.length >= 6;
}
}
该控制器在main() 中通过Get.put(AuthenticationController()) 注册一次。
怀疑的问题:
外层Obx监听isLoginPasswordVisible(以及isLoginLoading、canLogin、isStayLoggedInChecked)。当任意一个变化时——包括用户点击密码可见性切换时——整列都会重新构建,连同两个CommonTitleTextField小部件一起重新构建。
我们的推测:在iPadOS 26上,键盘/自动填充会话或焦点处理中的某些因素导致文本字段在其小部件重新构建时丢失或重置内容,尽管TextEditingController实例本身是稳定的。这在iPhone上不会发生。
问题:
- 由Obx触发的整棵小部件子树重新构建,在TextEditingController是同一个实例的情况下,是否会导致TextField在 iPadOS 26上被清空?
- AutofillGroup、iPad的自动填充UI与 Obx重新构建之间是否存在已知的交互,可能导致这种情况?
- 将Obx拆分为更小的作用域观察者(使仅在isLoginPasswordVisible改变时重新构建密码字段)是否可以解决这个问题——这是正确的做法吗?
解决方案
我会首先怀疑是在重新构建过程中发生的控制器或状态重置,而不是实际存在的iPad专有Flutter问题。iPad在处理键盘焦点和自动填充方面与iPhone略有不同,应用评审设备有时会暴露在模拟器看不到的问题。
我个人还没有看到有确凿证据的Flutter问题报告,指出iPadOS 26会随机清空字段。大多数情况最终是导航、认证状态变化、校验流程,或控制器被意外重新创建。
如果我要调试这件事,我会在完全相同iPadOS版本的真实iPad上进行测试,并临时添加日志,看看在登录过程中哪些代码在触碰文本字段。此外,为了通过应用评审,我可能直接预填演示凭据,或添加一个快速的“使用演示账户”按钮,避免审核人员再次被阻塞。