/// 登录页上可能出现的入口。 enum LoginMethod { /// 页面上方那组「手机号/邮箱 + 验证码 + 继续」。 contact, wechat, apple, guest, } /// 这个**包**提供哪些登录方式(2026-09-18 产品口径)。 /// /// | 包 | 留下的入口 | /// |---|---| /// | 苹果包(iOS) | 苹果登录 + 游客 | /// | 安卓国内包 | 微信登录 + 游客 | /// | 谷歌包 | 邮箱登录 + 游客 | /// /// ⚠️ **判据是 `.env` 的 `Channel`,不是 `VersionUpdateService.cachedChannel`**。 /// 后者在安卓上由设备品牌**异步**推导,推导完成之前 `_channel` 还是 null, /// 而它的兜底恰好是 `GLOBAL_GOOGLE` —— 拿它做判据的话,国内包在进入登录页的 /// 头几百毫秒会显示成谷歌包(露出邮箱登录、藏掉微信),品牌识别完再跳回来。 /// `.env` 的 Channel 是打包时由 `build_channels.sh` 写死的(google → `GLOBAL_GOOGLE`), /// 同步可读、不会变,正是「这是哪个包」本身。 /// /// ⚠️ iOS 必须**先判平台**:iOS 不走 `build_channels.sh`,`.env` 里留的还是 /// 国内渠道值(`CHINA_XIAOMI`),只看 Channel 会把苹果包判成国内包。 /// /// [guestVisible] 由服务端下发(「游客显隐控制」按应用+版本配),与包无关, /// 所以单独传进来而不是在这里推。 Set resolveLoginMethods({ required bool isIOS, required String envChannel, required bool guestVisible, }) { final methods = {}; if (isIOS) { methods.add(LoginMethod.apple); } else if (envChannel.trim().toUpperCase() == 'GLOBAL_GOOGLE') { // 谷歌包:邮箱登录(contact 这一档在非 iOS 只可能是谷歌包,故恒为邮箱, // 见 LoginController.isEmailOnlyLogin) methods.add(LoginMethod.contact); } else { // 其余安卓包(国内五家共用一个 APK,Channel 为 CHINA_*;认不出也按国内算) methods.add(LoginMethod.wechat); } if (guestVisible) methods.add(LoginMethod.guest); return methods; }