import 'package:flutter/foundation.dart'; import 'package:sentry_flutter/sentry_flutter.dart' show SentryFlutter; /// 全局编译期环境配置。所有值通过 --dart-define 注入,避免明文 secrets。 /// /// **环境名与 iOS NetworkConfig.swift 对齐**:dev / test / release /// /// 用法: /// ```bash /// # 开发环境 + mock(默认) /// flutter run --dart-define=ENV=dev --dart-define=USE_MOCK=true /// /// # 测试环境(连真服 dev.yixiong-tech.com:8081) /// flutter run --dart-define=ENV=test /// /// # 正式环境(连 bac.new.hamkke.top) /// flutter build apk --release --dart-define=ENV=release \ /// --dart-define=SENTRY_DSN=https://...@sentry/1 /// /// # CI/CD 临时覆盖 API URL(不修改源码) /// flutter run --dart-define=API_BASE_URL=https://my-private.example.com /// ``` /// /// 详见: /// - `docs/flutter-architecture-design.md` §九.1 / §十一.5 /// - `docs/real-environment-verification.md`(环境就绪后填值) /// - `lib/core/config/api_config.dart`(baseUrl 决策权威) abstract class Env { /// 当前环境名:**dev / test / release**(与 iOS NetworkConfig 三态对齐)。默认 dev。 /// /// - dev:开发环境(局域网 192.168.1.201:24801 / mock 模式可用) /// - test:测试环境(dev.yixiong-tech.com:8081 — 与 iOS test 同源) /// - release:正式环境(bac.new.hamkke.top — Release 包应锁定此值) static const String name = String.fromEnvironment('ENV', defaultValue: 'dev'); /// API baseUrl 临时覆盖(CI/CD / 私有环境调试用)。 /// /// **正常情况下不应使用此变量** — 让 [ApiConfig.baseUrl] 按 [name] 自动选择 /// iOS 同源 URL。仅当需要连私有/临时环境时通过 dart-define 注入。 /// /// ```bash /// flutter run --dart-define=API_BASE_URL=https://my-private.example.com /// ``` static const String apiBaseUrlOverride = String.fromEnvironment( 'API_BASE_URL', ); /// Sentry DSN。**Q9 待答前**为空,[SentryFlutter.init] 自动跳过实际上报。 static const String sentryDsn = String.fromEnvironment( 'SENTRY_DSN', ); /// 是否为内部测试包(决定 TalkerScreen 调试面板是否挂载)。 /// 详见 docs/real-environment-verification.md §M4 / §Talker 准入。 static const bool isInternalBuild = bool.fromEnvironment( 'INTERNAL_BUILD', ); /// 是否启用 mock fixtures 路径(绕过真实网络请求)。 /// 详见 plan §Mock 与真实环境验证分层策略。 static const bool useMock = bool.fromEnvironment( 'USE_MOCK', ); /// 腾讯云 IM SDKAppID(数字 ID)。 /// **Q3 待答前**为 0(无效值,init 会返回失败但不崩溃)。 /// 沙箱测试用控制台测试 SDKAppID;生产用真实业务 SDKAppID。 /// 注入:--dart-define=IM_SDK_APP_ID=1400xxxxxx static const int imSdkAppId = int.fromEnvironment( 'IM_SDK_APP_ID', ); /// RSA 公钥(DER-SPKI Base64)— 用于登录密码加密。 /// 默认值 = iOS dev 公钥(对应 platform-ios/.../RSAEncryption.swift 中的 publicKeyString)。 /// 生产 / Q6 答复后通过 --dart-define=RSA_PUBLIC_KEY=... 注入真实公钥。 static const String rsaPublicKey = String.fromEnvironment( 'RSA_PUBLIC_KEY', defaultValue: 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmZfR/bA9X3vp86y1aEpvwzXJYKRRF1fLau2+05/ZtaITLpV8bhkmSf3neSy/Q9gAdvG75Fr73E+GWE+K5b0BpvIS1jDGo319+PpZR39SaZTKZ27XFXrosmJTZutN79t819HS1VseleunHAFgMVufE9U5jP6LGzl/wbkSy01GhzwIDAQAB', ); /// TLS 证书绑定指纹列表(SHA-256,多指纹支持轮换)。 /// **Q2 待答前**为空,CertificatePinningInterceptor 在空列表时跳过校验。 /// 真实指纹通过 --dart-define=PINNED_FINGERPRINTS=AA:BB,CC:DD 注入。 static List get pinnedFingerprints { const raw = String.fromEnvironment( 'PINNED_FINGERPRINTS', ); if (raw.isEmpty) return const []; return raw .split(',') .map((s) => s.trim()) .where((s) => s.isNotEmpty) .toList(); } // ---- 便捷判断(对齐 iOS NetworkConfig.Environment 三态)---- static bool get isDev => name == 'dev'; static bool get isTest => name == 'test'; static bool get isRelease => name == 'release'; /// 兼容旧调用 — 历史代码可能用 isProd 判断 /// @Deprecated 新代码请用 [isRelease] static bool get isProd => isRelease; /// Release 包除非 INTERNAL_BUILD=true,否则视为生产模式。 /// 用于 TalkerScreen / Riverpod observer 等开发面板的门控。 static bool get enableDevPanel => kDebugMode || isInternalBuild; }