应用架构设计实战(新应用从 0 到 1 + 通用模块封装)
资深架构师视角的应用工程笔记。覆盖:新应用架构决策路径、分层/组件化/路由、跨端架构、网络/登录/图片/存储/日志/路由/埋点/推送/崩溃/UI/权限/性能/配置/安全 等模块的封装范式。面向工程落地,不做概念科普。
目录
一、架构决策方法论
1.1 三层目标
| 层次 | 目标 | 衡量 |
|---|---|---|
| 业务架构 | 业务域划分、流程编排 | 用例覆盖度、领域边界 |
| 应用架构 | 分层、模块化、依赖规则 | 编译依赖图、模块耦合度 |
| 技术架构 | 框架选型、基建 | 性能、稳定性、可维护性指标 |
1.2 决策原则
- YAGNI:不提前设计未发生的需求。
- KISS:能用一层不要两层;能用结构体不要类。
- 依赖倒置:业务定义协议,基建实现协议;业务永远不直接依赖底层 SDK。
- 单向依赖:上层 → 下层;禁止反向。
- 稳定依赖:稳定点(协议、领域模型)依赖不稳定点(实现)。
- 隔离变化:把会变的(业务策略、UI、网络栈)和不变的(领域模型、协议)分离。
1.3 常见反模式
| 反模式 | 表现 | 纠正 |
|---|---|---|
| Fat Controller/Activity/VC | 一个类 3000 行 | 拆 Service + ViewModel |
| 上帝对象 | 全局 Manager 什么都能做 | 拆领域 Service |
| 滥用单例 | 状态隐式耦合 | DI 注入 |
| 基建反向依赖业务 | 网络库引用业务 Model | 反转,用泛型 + 协议 |
| 过早抽象 | 一个调用点就抽 4 层 | 三次重复再抽象 |
| 链式回调地狱 | Promise 嵌套 5 层 | async/await / Flow / Combine |
| 配置即代码 | 硬编码 everywhere | 抽 ConfigCenter |
二、新应用从 0 到 1 架构路径
2.1 阶段决策树
需求 → 团队规模 →
单团队小项目 → 单 Module 分包
多团队/多业务线 → 组件化(多 Pod/Module/Package)
→ 端选择 →
单端 → 原生(iOS Swift / Android Kotlin)
双端 → Flutter(首选)/ RN(互动少)/ KMP(重逻辑)
三端(含 Web) → Flutter Web(短页面)/ React(重交互)
→ 复杂度评估 →
简单 CRUD → MVVM + Repository
状态机复杂(IM、播放器、订单)→ MVI / Redux / Bloc
富领域(电商、金融)→ Clean Architecture + DDD 简化版2.2 技术选型矩阵
| 维度 | iOS | Android | Flutter |
|---|---|---|---|
| 语言 | Swift 5.9+ | Kotlin 1.9+ | Dart 3+ |
| UI | SwiftUI + UIKit 混编 | Jetpack Compose + View | Material 3 + cupertino_icons |
| DI | Resolver / Factory / 手动 | Hilt (Dagger) | get_it / riverpod Provider |
| 网络 | URLSession / Alamofire / Moya | OkHttp / Retrofit / Ktor | dio + retrofit (retrofit/dart) |
| 存储 | GRDB / Realm / SwiftData | Room / Realm / DataStore | drift / sqflite / realm / isar |
| 图片 | Kingfisher | Coil | extended_image / cached_network_image |
| 响应式 | Combine / Async-Algorithms | Flow / Coroutines | Stream / RxDart |
| 路由 | swift-navigation / Coodinator | Navigation Compose / ARouter | go_router / auto_route |
| 埋点 | 自研 + Firebase | 自研 + Firebase | 自研 + firebase_analytics |
| 崩溃 | Crashlytics / Sentry / Bugly | Crashlytics / Sentry / Bugly | Crashlytics / Sentry |
| CI | Xcode Cloud / fastlane + GitHub Actions | GitHub Actions + gradle | Codemagic / GitHub Actions |
2.3 工程分层
┌─────────────────────────────────────────┐
│ App Shell (启动、路由、DI 容器) │
├─────────────────────────────────────────┤
│ Features (按业务域拆分,互不依赖) │
│ - Home / Profile / Order / IM ... │
├─────────────────────────────────────────┤
│ Core / Domain (协议、模型、用例) │
├─────────────────────────────────────────┤
│ Data (Repository、网络、缓存、本地数据) │
├─────────────────────────────────────────┤
│ Infrastructure (网络/存储/日志/埋点/安全)│
├─────────────────────────────────────────┤
│ Platform SDK (Foundation/AndroidX/Dart) │
└─────────────────────────────────────────┘依赖规则(严格单向):
- App → Features → Core → Infrastructure → Platform
- Features 之间禁止横向依赖;跨 Feature 走 Core 协议 + 路由。
2.4 包/目录命名(约定式)
features/
home/
presentation/ (View + ViewModel)
domain/ (UseCase + Entity)
data/ (Repository 实现 + DTO)
di/ (依赖注入配置)
core/
common/ (扩展、工具)
designsystem/ (UI Kit)
model/ (全局共享模型)
network/ (网络基建)
storage/ (存储基建)
infra/
tracking/ push/ crash/ logger/ config/2.5 多环境配置
| 项 | iOS | Android | Flutter |
|---|---|---|---|
| 配置文件 | .xcconfig | gradle + buildConfigField | --dart-define / flutter_dotenv |
| 多 Target / Flavor | 多 Target + Scheme | productFlavors | --flavor |
| Bundle/Application ID | 后缀 .dev / .staging | 后缀 .dev / .staging | 共用 + 切 Bundle |
| 图标 | Asset Catalog 多套 | res/src/main/dev/res | --flavor 切图标 |
| 域名切换 | xcconfig 注入 Info.plist | BuildConfig | 启动读 env 文件 |
iOS xcconfig 示例:
// Dev.xcconfig
API_BASE_URL = https:\/\/api.dev.example.com
APP_DISPLAY_NAME = AppName-dev
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUGAndroid flavor 示例:
kotlin
flavorDimensions += "env"
productFlavors {
create("dev") { dimension = "env"; applicationIdSuffix = ".dev" }
create("staging") { dimension = "env"; applicationIdSuffix = ".staging" }
create("prod") { dimension = "env" }
}Flutter --dart-define:
bash
flutter run \
--dart-define=API_BASE_URL=https://api.dev.example.com \
--dart-define=ENV=dev \
--flavor dev2.6 CI/CD 流水线
PR 阶段:
- Lint (SwiftLint / Detekt / dart format + analyze)
- Unit Test
- Build (Debug)
Merge 阶段:
- Build (Release)
- 上传符号 (dSYM / mapping.txt / .symbols)
- 内测包 (TestFlight / Play Internal)
Release 阶段:
- 灰度 (Phased Release / Staged Rollout)
- 监控告警阈值
- 一键回滚开关 (Feature Flag)三、iOS 工程架构
3.1 模块化方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| CocoaPods | 生态成熟、二进制化容易 | 安装慢、Pods.xcodeproj 易冲突 |
| Swift Package Manager | 苹果原生、Xcode 集成、自动管理依赖 | 不支持资源脚本、二进制 framework 集成弱 |
| BBBundle / 自研二进制 | 编译速度快 | 维护成本高 |
| Tuist / Bazel | 大型项目编译加速 | 学习曲线陡 |
经验:中小型项目用 SPM 优先;二进制化需求强 → SPM + XCFramework;超大型 → Tuist。
3.2 路由方案
| 方案 | 实现 | 适用 |
|---|---|---|
| URL Router(MGJRouter / CTMediator) | 字符串注册 + 解析 | 解耦彻底、动态化、不利于编译检查 |
| Target-Action(CTMediator) | runtime 调用 target-action | 中间件轻;OC 友好、Swift 弱 |
| Protocol-Router(BeeHive) | 协议 + 实现 bind | 强类型;模块加载复杂 |
| 类型安全 + Coordinator(swift-navigation / Combine) | 强类型、可测试 | 纯 Swift 项目首选 |
| DeepLink 桥接 | URL Router + 统一入口 | 处理 Push / Universal Link / Scheme |
混合方案:对外(推送、DeepLink、Web Bridge)用 URL Router;App 内跳转用强类型 Coordinator。
3.3 资源管理
- 资源命名:
<module>_<feature>_<role>_<state>.png(例:home_avatar_default)。 - Bundle 隔离:每个 Feature Module 自带
.bundle。 - Asset Catalog:On-demand resources + App Thinning。
- 颜色用 Color Set(暗黑模式自动适配)。
3.4 启动优化分层
Pre-main:
+load → initialize → 静态初始化器
▼ 优化:合并动态库、移除无用 +load、二进制重排 (Order File)
Main 后:
willFinishLaunching → didFinishLaunching → 首帧
▼ 优化:
- 启动任务分级(必须/可延迟/可后台)
- 启动器(Task Scheduler)并行
- Flutter Engine 预热(混合栈)
- 首页用快照占位四、Android 工程架构
4.1 模块化
- Multiple Module Gradle:
app / feature-xxx / core-xxx / library-xxx。 - buildSrc / Version Catalog (
libs.versions.toml):依赖统一管理。 - 构建加速:并行构建、配置缓存 (
org.gradle.unsafe.configuration-cache=true)、模块二进制化 (AAR)。
4.2 路由
| 方案 | 备注 |
|---|---|
| ARouter | 阿里出品,业界主流 |
| TheRouter | 字节出品,支持 KSP |
| Navigation Compose | 官方,类型安全(@Serializable route) |
| DeepLink Dispatch | 处理 App Link / Scheme |
4.3 资源
- 模块资源前缀:
resourcePrefix "home_"。 - VectorDrawable 优先;位图 WebP。
- 多 Language:
values-zh / values-ja / values-ar。
五、Flutter 工程架构
5.1 分层
lib/
main.dart
app/ (App 入口、主题、路由)
core/ (网络、存储、错误、日志)
data/ (Repository、DTO、Mapper)
domain/ (Entity、UseCase、Repository 接口)
presentation/ (Page、Widget、Controller)
shared/ (DesignSystem、Utils、Extensions)
gen/ (l10n、json_serializable 生成)5.2 状态管理选型
| 方案 | 适用 | 心智 |
|---|---|---|
| Riverpod 2.x | 中大型项目首选 | 编译期安全、可测试 |
| Bloc / Cubit | 复杂状态机(IM、订单) | 事件驱动、模板代码多 |
| GetX | 快速原型 / 小项目 | 灵活但易滥用全局状态 |
| Provider | 简单场景 | Riverpod 前身,新项目不推 |
| Signal / Flutter Hooks | 局部状态 | 轻量 |
5.3 路由
- go_router:官方推荐,声明式 + DeepLink 友好。
- auto_route:类型安全 + 代码生成,中大型项目首选。
- 统一
RouteGuard:登录拦截、权限校验、埋点。
5.4 依赖注入
- get_it:Service Locator 模式,简洁。
- riverpod Provider:纯声明式 DI。
- injectable:编译期生成 get_it 注册代码。
六、通用模块封装
6.1 网络模块
6.1.1 分层
API DSL(业务调用)
│
RequestBuilder(路径/方法/参数/头)
│
Client(执行器)
│
Interceptor Chain(鉴权/签名/加密/日志/重试/缓存)
│
Transport(URLSession / OkHttp / HttpClient)
│
Decoder(JSON → DTO → Domain Model)
│
ErrorMapper(HTTP/IO → App Error)6.1.2 接口设计(伪代码)
swift
// 业务侧
let resp: UserDTO = try await API.request(.user(id: "123"))kotlin
suspend fun getUser(id: String): UserDTO =
api.get("users/$id")dart
final user = await api.get<UserDTO>('users/123', parse: UserDTO.fromJson);6.1.3 关键能力清单
| 能力 | 实现 |
|---|---|
| BaseURL 多环境 | xcconfig / BuildConfig / --dart-define |
| HTTPDNS | HappyDNS / OkHttp Dns SPI / cronet_http |
| TLS Pinning | URLSessionDelegate / CertificatePinner / SecurityContext |
| HTTP/2 / HTTP/3 | URLSession 默认 / OkHttp 默认 / cronet_http |
| 拦截器链 | Adapter/Interceptor 模式,按序注册 |
| 鉴权拦截 | 自动注入 Token,401 触发刷新 |
| 签名拦截 | HMAC-SHA256 签名参数 + 时间戳 + Nonce |
| 加密拦截 | IJK / AES-GCM 整包加密;敏感字段单独加密 |
| 日志拦截 | Release 脱敏;cURL 命令复现 |
| 缓存拦截 | HTTP Cache-Control + 本地策略 |
| 重试拦截 | 指数退避 + 抖动;幂等性校验 |
| 超时分层 | connect 5s / read 10s / total 30s |
| 并发控制 | 同域 6 连接上限;串行队列防风暴 |
| 优先级调度 | UI 请求 > 后台同步;URLSessionTask.priority |
| 取消机制 | CancellationToken / CoroutineScope / CancelToken |
| 断点续传 | Range Header + 本地 offset 持久化 |
| 上传 | multipart/form-data、流式、分片 |
| 下载 | 文件流写盘、原子重命名、断点续传 |
| SSLPinning 轮换 | 多 SPKI Hash 备用,避免换证书全挂 |
6.1.4 错误模型
AppError
├─ NetworkError (无网络/超时/DNS)
├─ ServerError (5xx)
├─ BusinessError (业务码 + 提示文案)
├─ AuthError (401/403,触发登录)
└─ ParseError (JSON 解析失败)关键:HTTP 200 也可能携带业务错误({code: 1001, msg: "余额不足"});统一拦截器识别 code,转 BusinessError。
6.1.5 弱网策略
- 接口幂等设计(POST 也要带 idempotency-key)。
- 关键操作三连:请求 + 本地草稿 + 重试队列。
- 离线队列:失败任务落 SQLite,恢复网络后回放。
6.1.6 安全
- 全站 HTTPS + TLS 1.3 + Pinning。
- 敏感参数加密(RSA 换 AES Key → AES-GCM 加密 body)。
- 请求头加
X-Sign + X-Timestamp + X-Nonce,服务端校验防重放(5min 窗口)。
6.2 登录鉴权模块
6.2.1 鉴权模型
| 模式 | 说明 |
|---|---|
| Session + Cookie | 老式 Web 模式;移动端少用 |
| Bearer Token(JWT) | 无状态、易水平扩展;Token 易被盗 |
| OAuth 2.0 | 三方授权码模式 / PKCE |
| Refresh Token 轮换 | AT 短(15min) + RT 长(30d),RT 用一次换一对 |
| 设备指纹绑定 | RT 与设备 ID 绑定,被盗换设备失效 |
| SSO / CAS | 多 App 共享登录(集团内) |
6.2.2 模块能力清单
AuthModule
├─ 登录入口
│ ├─ 账号密码
│ ├─ 手机验证码(一键登录/本机号认证)
│ ├─ 第三方(微信/QQ/微博/Apple/Google/Facebook)
│ ├─ 邮箱
│ └─ 生物识别(Face ID / 指纹)— 复登
├─ Token 管理
│ ├─ 存储(Keychain / EncryptedSharedPreferences / flutter_secure_storage)
│ ├─ 自动刷新(401 → 刷新 → 重放原请求)
│ ├─ 并发刷新去重(单飞 SingleFlight)
│ └─ 多端互踢(401 + 特定 code → 强制下线)
├─ 登录态分发
│ ├─ 全局状态(StateFlow / Stream / Combine)
│ ├─ 登录态变化通知
│ └─ 未登录拦截(路由 Guard)
├─ 退出登录
│ ├─ 服务端注销 RT
│ ├─ 清理本地(Token / 缓存 / 业务 DB)
│ ├─ 重置路由到登录页
│ └─ 重启网络拦截器
└─ 风控
├─ 异地登录提示
├─ 频次限制
└─ 验证码挑战6.2.3 Token 刷新关键细节
- SingleFlight:多个并发 401 请求只触发一次刷新,其它挂起等待。
- 刷新失败:清空 Token → 路由到登录页;不再无限重试。
- 刷新 RT 时:必须锁定 RT,防止多请求并发用同一个旧 RT(会被服务端撤销)。
- Apple Sign In:必须用
ASAuthorizationAppleIDRequest,且服务端校验identityTokenJWT。
6.2.4 Apple 强制项
- Sign in with Apple:只要支持了三方登录(Google/Facebook/微信),就必须提供 Apple Sign In(仅 iOS 13+ 实机生效)。
- 账号注销:必须提供,Hard Delete。
6.3 图片框架
6.3.1 加载流水线
URL → 内存缓存(LRU) ─命中─→ 显示
└─未命中→ 磁盘缓存 ─命中─→ 解码 → 内存缓存 → 显示
└─未命中→ 网络 → 解码 → 磁盘 + 内存 → 显示6.3.2 关键能力
| 能力 | 关键 |
|---|---|
| 降采样 | 不解码原图,按目标尺寸 downsample;内存节省 90%+ |
| 异步解码 | 子线程解码位图,主线程只渲染 |
| 格式 | WebP / HEIC / AVIF / GIF / APNG |
| 圆角/边框 | 用 cornerRadius + masksToBounds 触发离屏渲染,应改用带 mask 的位图 |
| 过渡动画 | 渐入 / 淡入 |
| 占位/错误图 | placeholder / error widget |
| 进度 | 网络进度回调 |
| 缓存控制 | Cache-Control、ETag、Last-Modified |
| 缓存淘汰 | LRU 内存 + Disk LRU(按大小、按天数) |
| 列表复用 | cell/Item 复用时取消旧请求,避免错位 |
| 优先级 | 可视区域 > 预加载 > 后台 |
| CDN 裁剪 | 客户端按 ImageView 尺寸拼 ?w=200&h=200 |
6.3.3 选型
| 平台 | 首选 | 备注 |
|---|---|---|
| iOS | Kingfisher | SWift 原生、模块化、扩展强 |
| iOS 老项目 | SDWebImage | OC 老牌、稳定 |
| Android | Coil | Kotlin-first、协程、生命周期感知 |
| Android 老项目 | Glide | 老牌稳定 |
| Flutter | extended_image | 功能最全(缓存、手势、裁剪、编辑) |
| Flutter 简单 | cached_network_image | 用法简单 |
6.3.4 长列表优化要点
- 设置
prefetchWindow、itemExtent提升滚动性能。 - 取消不可见项的请求。
- 缩略图占位,原图加载后渐变替换。
- 不在滚动时触发
setState(用NotificationListener判断 idle 才刷新)。
6.4 存储模块
6.4.1 分层选型
| 数据类型 | iOS | Android | Flutter |
|---|---|---|---|
| 小键值 | UserDefaults / Keychain | DataStore (Prefs) / EncryptedSharedPreferences | shared_preferences / flutter_secure_storage |
| 敏感小数据 | Keychain | EncryptedSharedPreferences + Keystore | flutter_secure_storage |
| 结构化 | GRDB / SQLite.swift / SwiftData | Room / SQLDelight | drift / sqflite / isar |
| 对象 | SwiftData / Core Data | Room | realm / isar |
| 大文件 | FileManager + mmap | File + MMKV | path_provider + file |
| KV 高性能 | MMKV / YapDatabase | MMKV | mmkv (Flutter plugin) |
| 全文搜索 | SQLite FTS5 | SQLite FTS4/5 | drift + FTS5 |
6.4.2 封装要点
- 统一抽象:
Storage协议(get/set/delete/observe),底下多实现。 - 加密:敏感字段用 Keychain/Keystore,整体 DB 用 SQLCipher。
- 迁移:版本号 + Migration 脚本;首次安装走
seed。 - 观察:
@FetchRequest(SwiftData)/Flow<List<Entity>>(Room)/Stream(drift)。 - 线程:DB 操作必须在专用队列 / IO Dispatcher / Isolate。
6.5 日志模块
6.5.1 设计
Logger
├─ Level (Debug / Info / Warn / Error / Fatal)
├─ Domain (Net / DB / Auth / Business)
├─ Format (结构化: JSON / 文本)
├─ Sink
│ ├─ Console (开发)
│ ├─ File (按日切分、压缩、上传)
│ ├─ Remote (错误聚合,走 Crashlytics / Sentry)
│ └─ OSLog (Instruments 联动)
└─ Filter (按 Domain / Level / Tag)6.5.2 关键点
- Release 关闭 Debug,开启 Info+ File 滚动(容量上限 5MB×3 文件)。
- 格式:
[time][level][domain][file:line] message {context}。 - 结构化:日志带
event_id/trace_id,方便后端关联。 - 脱敏:手机号、邮箱、Token 中间打码;触发器配置规则。
- 性能:写文件用 mmap 或 async queue;不要阻塞主线程。
- OSLog / Logcat:开发期直接看;上线用文件归档。
iOS 用 os.Logger(统一系统日志,Instruments 联动):
swift
let log = Logger(subsystem: "com.example.app", category: "network")
log.error("HTTP \(statusCode) for \(url)")6.6 路由模块
6.6.1 能力清单
- 注册:Feature 模块自注册路由表(避免中心化耦合)。
- 解析:支持路径参数
/user/:id、查询参数。 - 拦截器:登录守卫、权限校验、埋点、动画。
- 结果回传:
presentForResult。 - DeepLink:统一收口 Universal Link / Scheme / Push / Web Bridge。
- 嵌套导航:Tab + 内部 Stack。
- Web fallback:App 内没装该模块时打开 H5。
6.6.2 抽象
swift
protocol Router {
func register(_ pattern: String, builder: @escaping (Params) -> AnyView)
func route(to url: URL, context: Any?) -> Bool
func canHandle(_ url: URL) -> Bool
}6.6.3 路由表声明式注册
kotlin
@Route(path = "/user/:id")
class UserActivity : Activity()
@Serializable
data class UserRoute(val id: String) : Route6.7 埋点模块
6.7.1 模型
Event
├─ name (e.g. "login_submit")
├─ properties (Map<String, Any>)
├─ user_id (登录后)
├─ device_id (设备稳定 ID)
├─ session_id (启动/前台切换生成)
├─ timestamp (UTC)
└─ trace_id (跨端串联)6.7.2 能力
- 手动埋点 + 全埋点(无码)+ 可视化埋点三种混合。
- 离线缓存:本地 SQLite/Realm,弱网批量上报。
- 批量上报:合并 N 条 / 定时 T 秒 / 大小 B 字节 触发。
- 重试:失败回滚到队列。
- 丢弃策略:超过容量优先丢弃低优先级。
- 合规:用户同意跟踪前不上报广告 ID;IDFA/AAID 可空。
- 统一入口:所有上报走
Tracker.track(...),禁止散落调用第三方 SDK。 - 多平台分发:一个事件同时分发到 Firebase + 自研 + AppsFlyer。
6.8 推送模块
6.8.1 抽象层
PushManager
├─ register() (申请 Token)
├─ onToken(cb)
├─ onMessage(cb) (前台收到)
├─ onNotificationTap(cb) (通知点击)
├─ onBackground(cb) (静默推送 / Data Only)
└─ channel dispatcher
├─ APNs
├─ FCM
├─ HuaweiPush / XiaomiPush / OPPOPush / VIVOPush
└─ Custom (WebSocket)6.8.2 细节
- 统一 Token 上报:每端 Token 不同,后端按
device_type + token维度存储。 - 通知点击跳转:走统一路由,
push_payload = { route, params }。 - 静默推送:iOS
content-available:1;Androiddataonly;用于数据同步。 - 富媒体:iOS
Notification Service Extension解码图;AndroidBigPictureStyle。 - iOS Live Activities / Android Foreground Service:实时场景。
- 权限时机:不要冷启动就申请;先用 In-App Pre-Prompt 解释价值。
- 推送到达率监控:客户端上报收到率,后端聚合分析。
6.9 崩溃与异常
6.9.1 捕获
| 平台 | 机制 |
|---|---|
| iOS | NSSetUncaughtExceptionHandler + signal(SIGABRT/SEGV/...) + Mach 异常 |
| Android (Java) | Thread.setDefaultUncaughtExceptionHandler |
| Android (Native) | sigaction + breakpad |
| Flutter | runZonedGuarded + FlutterError.onError + PlatformDispatcher.instance.onError |
| Dart Isolate | Isolate.current.addErrorListener |
6.9.2 处理流程
1. 异常捕获
2. 收集堆栈、设备、App 版本、User、Session
3. 本地缓存(关键,防止上报失败丢失)
4. 重启主进程 / 友好弹窗
5. 后台批量上报
6. 服务端符号化 + 聚合 + 告警6.9.3 符号化
- iOS:dSYM 与 Build 一一对应;上传 Crashlytics / Sentry。
- Android:
mapping.txt(R8)+ Native.so.debug(Breakpad.sym)。 - Flutter:
flutter symbolize+app.ios.symbols。
6.9.4 监控指标
- 崩溃率:sessions-based(< 0.1% 行业基线)。
- ANR 率(Android 5s 主线程阻塞、iOS 启动卡死 watchdog)。
- OOM 率(iOS Jetsam;Android Low Memory Killer)。
- 自定义用户级影响率。
6.10 UI 组件库与主题
6.10.1 设计令牌(Design Token)
Color
├─ brand.primary / secondary
├─ semantic.success / warning / error / info
├─ text.primary / secondary / disabled
└─ bg.primary / secondary / elevated
Typography
├─ display / headline / title / body / caption / overline
└─ 每级 size / weight / line-height
Spacing
└─ 4 / 8 / 12 / 16 / 24 / 32 (8pt grid)
Radius / Elevation / Motion6.10.2 抽象
kotlin
interface ThemeProvider {
val colors: ColorScheme
val typography: Typography
val shapes: Shapes
}6.10.3 关键
- 暗黑模式:所有颜色定义两套;不用硬编码
Color.black。 - Dynamic Type / Font Scaling:iOS 用系统字号;Android
sp单位;FlutterMediaQuery.textScaleFactor。 - RTL:用
leading/trailing而非left/right。 - 组件库分层:原子(Button)→ 分子(FormField)→ 有机体(LoginForm)→ 模板(Page)。
- 预览与文档:Storybook / SwiftUI Previews / Widget Catalog。
6.11 权限模块
6.11.1 统一封装
Permission
├─ status (notDetermined / denied / restricted / granted)
├─ request() -> Status
└─ openSettings()每类权限独立 Provider;业务调用:
swift
let granted = await Permission.camera.request()
if !granted { showRationaleAndOpenSettings() }6.11.2 关键
- Pre-Prompt:在系统弹窗前,自绘弹窗解释为什么需要。
- Denied 后:跳系统设置;不要无限弹。
- 状态恢复:权限变更后,UI 同步刷新(监听
UIApplication.willEnterForeground)。 - iOS 14+ Local Network / Tracking / Photo Library Limited:注意新增的细化权限。
- Android 13+ Notification / Photo Picker:必须运行时申请。
6.12 设备与运行时上下文
ContextProvider
├─ Network (wifi/cellular/none/unknown + quality)
├─ Battery (level/lowPower/charging)
├─ AppLifecycle (active/inactive/background)
├─ MemoryPressure (warning)
├─ DeviceInfo (model/os/version/locale/timezone)
├─ Display (size/scale/orientation/darkMode)
└─ PermissionStatus (各权限最新状态)业务通过 DI 注入抽象接口订阅;禁止散落调用 UIDevice.current、ConnectivityManager、MediaQuery。
6.13 性能监控
| 指标 | 工具 |
|---|---|
| 启动 | Xcode MetricKit / Firebase Performance / 自研打点 |
| 卡顿 | CADisplayLink 丢帧 / Runloop 状态耗时 / Choreographer / FrameCallback |
| 内存 | task_vm_info.phys_footprint / Debug.MemoryInfo / MemoryUsage |
| 能耗 | MetricKit MXCPUUsage / Energy Log / Android Battery Historian |
| 网络 | 请求耗时 / 成功率 / 重试率 |
| FPS | DisplayLink / vsync |
| 磁盘 | 沙盒大小、缓存大小 |
| 线上 Crash / ANR / OOM | Crashlytics / Sentry / 自研 |
- 线下:Instruments(Time Profiler / Leaks / System Trace)、Android Studio Profiler、Flutter DevTools。
- 线上:APM SDK(自研或第三方),按采样上报,关键路径全量。
6.14 配置中心与 Feature Flag
6.14.1 抽象
ConfigService
├─ getString(key, default)
├─ getBool(key, default)
├─ getInt / getDouble / getJSON
├─ stream(key) (实时监听变化)
└─ sources: local (plist/json) < remote (Firebase Remote Config / 自研)6.14.2 用途
- 远程开关:紧急下线功能、灰度发布。
- A/B 测试:按用户分组。
- 动态文案 / URL / 业务参数:不发包即可调。
- 降级:服务异常时切兜底配置。
6.14.3 关键
- 本地兜底:远程拉取失败时用打包内置 default。
- 缓存策略:本地存最近一次值,启动先用本地,后台异步刷新。
- 变更广播:通过 Stream / Combine / Flow 通知订阅者。
- 审计:每次取值记录来源(local/remote/exp)。
6.15 安全模块
| 维度 | 实现 |
|---|---|
| 传输 | TLS 1.3 + Pinning + HTTPDNS |
| 存储 | Keychain / Keystore / SQLCipher / MMKV 加密模式 |
| 代码 | iOS 宏混淆 / Android ProGuard R8 / Flutter 字符串加密 |
| 反调试 | ptrace PT_DENY_ATTACH / sysctl P_TRACED |
| 越狱/Root | 文件特征检测 / Magisk 检测 |
| Hook 检测 | Frida 端口/线程 / Substrate / Xposed |
| 完整性 | 签名校验 + 服务端校验 |
| 设备指纹 | IDFV/IDFA/Android ID/OAID + 服务端聚合 |
| 防重放 | 时间戳 + Nonce + 签名 |
| App Attest / Play Integrity | 硬件级证书,防作弊 |
| 安全键盘 | 自绘数字键盘,金融场景必用 |
七、跨端混合架构
7.1 Flutter 混合方案
| 方案 | 说明 |
|---|---|
| Add-to-App | 官方,原生工程嵌入 Flutter Module;按需创建 Engine |
| Flutter Boost | 字节,混合栈管理;复用单 Engine,节省内存 |
| flutter_thrio | 类 Boost,更轻量 |
| Multi-Engine | Flutter 3.0+ Engine Group,多页面独立 Engine,互不影响 |
7.2 通信层封装
- 统一
FlutterBridge:所有 Channel 注册到中央管理器,业务侧调用强类型接口(Pigeon 生成)。 - 生命周期联动:原生页面销毁 → 通知 Flutter 释放对应资源(ImageCache、Stream)。
- 内存联动:iOS Memory Warning → Flutter
didHaveMemoryPressure→ 释放图片缓存。 - 线程模型:Flutter UI 线程独立;耗时操作走 Isolate;Channel 默认在主线程,注意切换。
7.3 动态化(受限场景)
| 方案 | 适用 |
|---|---|
| 自研 DSL(JSON 驱动 UI) | 营销活动页 |
| Kraken / Hippy / Sonic | 三方成熟方案 |
| WebView + JS Bridge | 高频改动的活动 / 富文本 |
| 小程序引擎(Taro / uni-app) | 国内多端分发 |
注意:iOS 严禁动态下发可执行代码(除 Apple 例外清单);动态化应走"解释执行"而非"代码下发"。
八、可演进性与技术债
8.1 演进策略
- 架构小步快跑:每迭代一次重构一个模块(Strangler Fig 模式)。
- 抽象稳定后再下沉:先业务跑通,再抽 Core;过早抽象等于负债。
- 接口先行:跨团队约定接口契约,并行开发。
- 兼容窗口:旧 API 标记 deprecated → 灰度 → 下线,给业务至少一个版本窗口。
8.2 技术债管理
| 信号 | 应对 |
|---|---|
| 编译时间 > 10 分钟 | 拆模块、二进制化 |
| PR 改动 50+ 文件 | 模块边界模糊,重新划分 |
| 同样 Bug 反复出现 | 加测试、加 lint 规则 |
| 启动崩溃率上涨 | APM 告警 + 紧急回滚 |
| 业务抱怨"加功能越来越难" | 重构该模块,引入抽象 |
8.3 文档与契约
- 架构决策记录(ADR):每个重大决策写下背景、选项、结论、后果。
- API 契约:OpenAPI / GraphQL Schema / Protobuf,前后端共用。
- 模块 README:模块职责、依赖、对外 API、变更负责人(CODEOWNERS)。
8.4 监控驱动架构
- 上线前先埋 APM / 业务监控 → 再做架构演进。
- 每次重构对比前后指标(崩溃率、性能、包大小)→ 数据驱动决策。
- 设置 SLO(如 P99 启动 < 1.5s、崩溃率 < 0.1%),违反即治理。