App 开发概览
App 开发技术全景
三大技术路线对比
App 开发主要分为三大技术路线:原生开发、跨平台开发和混合开发。
原生开发
原生开发针对特定平台,使用平台官方语言和工具链进行开发。Android 端使用 Kotlin 或 Java 语言,配合 Android Studio 和 Gradle 构建系统;iOS 端使用 Swift 或 Objective-C 语言,配合 Xcode 和 CocoaPods/SPM 包管理。
原生开发的优势在于性能最佳、可完整访问平台所有 API 和新特性、用户体验最贴近平台规范。劣势是开发成本高,需要维护两套独立的代码库,功能迭代周期长。
跨平台开发
跨平台开发使用单一语言编写业务逻辑,编译或运行时转换为各平台可执行的代码。主流方案包括 Flutter(Dart 语言)、React Native(JavaScript/TypeScript)、uni-app(Vue.js)和 Taro(React/Vue)。
跨平台开发的核心价值在于代码复用率高(通常可达 60%-90%)、开发效率高、热更新能力强。劣势在于性能无法完全媲美原生、平台差异需要适配处理、调试复杂度较高。
混合开发
混合开发基于 WebView 容器,通过 JSBridge 桥接原生能力。代表框架包括 Cordova、Ionic、Capacitor 以及直接使用 WebView 的方案。
混合开发的优势在于 Web 技术栈完全复用、开发成本低、部署灵活;劣势是性能受 WebView 渲染能力限制、复杂交互体验不佳、不适合高性能场景。
技术选型决策矩阵
| 维度 | 原生开发 | Flutter | React Native | uni-app/Taro | 混合开发 |
|---|---|---|---|---|---|
| 性能体验 | 最优 | 极优(自渲染) | 良好(JSI 桥接) | 中等(小程序/WebView) | 一般(WebView) |
| 开发效率 | 低(双端) | 中(单语言) | 中(单语言+生态) | 高(前端技术栈) | 高(Web 技术栈) |
| 热更新 | 不支持 | 支持(Debug) | 支持(Metro) | 支持(小程序/H5) | 支持 |
| 原生能力 | 完全访问 | 插件生态 | 原生模块 | 插件市场 | JSBridge |
| UI 一致性 | 平台原生 | 高度一致 | 接近原生 | 平台适配 | Web 样式 |
| 社区生态 | 官方生态 | 快速增长 | 成熟稳定 | 国内活跃 | 日趋萎缩 |
| 企业应用 | 广泛应用 | 快速普及 | Meta 背书 | 国内主流 | 存量项目 |
| 学习成本 | 高(双语言) | 中(Dart 新学) | 中(React 基础) | 低(Vue/React) | 低(Web 基础) |
| 包体积 | 较小 | 较大(引擎约 6MB) | 中等 | 较小 | 中等 |
| 开发成本 | 高 | 中 | 中 | 低 | 低 |
App 开发整体流水线
一个完整的 App 项目从立项到上线运营通常经过以下阶段:
需求阶段:产品需求文档撰写、功能原型设计、技术可行性评估、需求评审。
UI 设计阶段:交互原型设计、视觉设计(Sketch/Figma/Adobe XD)、设计规范制定、切图与标注交付。
前后端开发阶段:前后端并行开发,前端负责 App UI 和交互实现,后端负责 API 接口和数据服务。
测试阶段:单元测试、集成测试、UI 自动化测试、性能测试、安全测试、兼容性测试(真机矩阵)、Beta 测试。
构建阶段:代码混淆与加固、资源压缩、版本号管理、渠道包构建、签名打包。
上架阶段:应用商店账号准备、元数据填写、隐私政策审核、App 审核提交、审核问题修复与重新提交。
运营阶段:崩溃监控(Crashlytics/Sentry)、性能监控(APM)、用户反馈收集、A/B 测试、版本迭代更新。
开发环境搭建
Android 开发环境
Android 开发环境的核心组件包括 JDK、Android Studio、Android SDK、Gradle 和 Android Gradle Plugin(AGP)。
JDK 版本要求
Android 项目对 JDK 版本有明确要求。Android Gradle Plugin 8.x 要求 JDK 17 及以上,建议使用 JDK 17 LTS:
# 检查 JDK 版本
java -version
# 推荐使用 Amazon Corretto 或 Eclipse Temurin JDK 17Android Studio 安装
从 Android Studio 官方网站下载安装包,安装过程中注意勾选 Android SDK、Android Virtual Device(AVD)等组件。首次启动后,通过 SDK Manager 安装所需的 SDK 版本:
# 通过 sdkmanager 命令行
sdkmanager "platforms;android-34" "build-tools;34.0.0"
sdkmanager "ndk;25.2.9519653"
sdkmanager "emulator"Gradle 与 AGP
项目根目录的 build.gradle.kts 配置 Gradle 和 AGP 版本:
// build.gradle.kts (Project 级别)
plugins {
id("com.android.application") version "8.2.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
}gradle/wrapper/gradle-wrapper.properties 指定 Gradle 版本:
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip模拟器
推荐使用 Android Studio 自带的 AVD Manager 创建模拟器,也可使用 Genymotion 获得更好的性能。创建模拟器时选择合适的系统镜像(建议 x86_64 架构以获得最佳性能):
# 命令行创建模拟器
avdmanager create avd -n pixel_6 -k "system-images;android-34;google_apis;x86_64" -d pixel_6创建第一个 Android 项目
# 使用 Android Studio 创建项目
# File > New > New Project > Empty Views Activity
# 或使用命令行模板项目目录结构
MyApplication/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/example/myapp/
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── ...
│ │ │ ├── res/
│ │ │ │ ├── layout/
│ │ │ │ │ └── activity_main.xml
│ │ │ │ ├── values/
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── themes.xml
│ │ │ │ ├── drawable/
│ │ │ │ ├── mipmap/
│ │ │ │ └── ...
│ │ │ └── AndroidManifest.xml
│ │ └── test/ # 单元测试
│ │ └── androidTest/ # 仪器化测试
│ ├── build.gradle.kts # Module 级别构建配置
│ └── proguard-rules.pro
├── build.gradle.kts # Project 级别构建配置
├── settings.gradle.kts
└── gradle/
└── wrapper/
└── gradle-wrapper.propertiesHello World 示例
// MainActivity.kt
package com.example.myapp
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}<!-- res/layout/activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>iOS 开发环境
iOS 开发必须在 macOS 系统上进行。核心工具链为 Xcode,它集成了 IDE、编译器、模拟器和调试器。
Xcode 安装
从 Mac App Store 下载安装 Xcode。Xcode 包含 iOS SDK、Swift 编译器、Interface Builder、Instruments 性能分析工具等。
SwiftUI 与 UIKit
iOS 开发目前有两种 UI 框架选择。SwiftUI 是声明式 UI 框架,代码更简洁、易于维护;UIKit 是传统命令式框架,生态成熟、兼容性更好。SwiftUI 适用于 iOS 16+ 项目和新应用,UIKit 适用于需兼容低版本或复杂自定义 UI 的项目。
// SwiftUI 示例
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, World!")
}
.padding()
}
}包管理器对比
| 特性 | Swift Package Manager | CocoaPods | Carthage |
|---|---|---|---|
| 集成方式 | Xcode 原生集成 | Podfile + workspace | Cartfile + 框架二进制 |
| 依赖解析 | 自动 | 自动 | 手动 |
| 编译方式 | 源码编译 | 源码编译 | 预编译二进制 |
| 主流支持 | 官方推荐、增长快 | 生态最丰富 | 日趋萎缩 |
// Package.swift - SPM 配置
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "MyApp",
dependencies: [
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.8.0"),
.package(url: "https://github.com/onevcat/Kingfisher.git", from: "7.0.0"),
]
)# Podfile - CocoaPods 配置
platform :ios, '16.0'
use_frameworks!
target 'MyApp' do
pod 'Alamofire', '~> 5.8'
pod 'Kingfisher', '~> 7.0'
end模拟器与真机调试
Xcode 自带模拟器,支持各种 iPhone/iPad 机型模拟。真机调试需要:
- 注册 Apple Developer 账号(个人 $99/年 或 企业)
- 在 Apple Developer Center 创建 App ID 和 Bundle Identifier
- 生成开发证书(Certificate Signing Request - 私钥认证)
- 创建 Provisioning Profile(将 App ID + 证书 + 测试设备关联)
- 在 Xcode Signing & Capabilities 中配置 Team 和 Provisioning Profile
创建 HelloWorld 项目
在 Xcode 中选择 File > New > Project > iOS > App,选择 SwiftUI 和 Swift,填写项目名称和 Bundle Identifier。
HelloWorld/
├── HelloWorld/
│ ├── HelloWorldApp.swift # @main App 入口
│ ├── ContentView.swift # 主视图
│ ├── Assets.xcassets # 资源目录
│ └── Info.plist # 应用配置信息
├── HelloWorld.xcodeproj/ # Xcode 项目文件
└── HelloWorldTests/ # 单元测试// HelloWorldApp.swift
import SwiftUI
@main
struct HelloWorldApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
// AppDelegate.swift
class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
return true
}
}Flutter 环境
Flutter 是 Google 开源的跨平台 UI 框架,使用 Dart 语言,通过 Skia 引擎自渲染实现跨平台。
Flutter SDK 安装
# 从 Flutter 官网下载 SDK 并解压
# 配置环境变量 PATH 指向 flutter/bin 目录
# 验证安装
flutter doctor
# 输出应显示 Android toolchain、iOS toolchain(仅 macOS)、
# Chrome(Web 开发)、Android Studio、VS Code 等状态均为绿色Dart 语言
Dart 是一种类型安全的编程语言,同时支持 JIT(开发期热重载)和 AOT(发布期高性能编译)。Flutter 3.x 使用 Dart 3.x,支持空安全、Records、Patterns 等现代语言特性。
// 基础 Dart 语法示例
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorSchemeSeed: Colors.blue,
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}IDE 和插件
- Android Studio:安装 Flutter 和 Dart 插件
- VS Code:安装 Flutter 扩展(含 Dart 支持),提供代码补全、热重载、调试等功能
- Flutter DevTools:性能分析、Widget 树检查、内存分析、网络请求追踪
创建项目
flutter create my_app
cd my_app
flutter run项目目录结构
my_app/
├── lib/
│ ├── main.dart # 入口文件
│ ├── app.dart # App 根组件
│ ├── models/ # 数据模型
│ ├── screens/ # 页面
│ ├── widgets/ # 可复用组件
│ └── services/ # 服务层(网络/本地)
├── test/ # 单元测试和 Widget 测试
│ └── widget_test.dart
├── pubspec.yaml # 依赖配置文件
├── android/ # Android 原生工程
├── ios/ # iOS 原生工程
├── web/ # Web 平台代码
└── build/ # 构建产物pubspec.yaml 示例:
name: my_app
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=3.2.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.6
provider: ^6.1.1
dio: ^5.4.0
shared_preferences: ^2.2.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.1React Native 环境
React Native 是 Meta 开源的跨平台框架,使用 React 声明式 UI 模型,通过 JavaScript Interface(JSI)与原生模块通信。
Node.js 安装
React Native 开发依赖 Node.js(建议 LTS 版本 18 或 20):
# 安装 nvm(Windows 使用 nvm-windows)
nvm install 20
nvm use 20
# 验证
node --version
npm --versionReact Native CLI 与 Expo 对比
| 特性 | React Native CLI | Expo |
|---|---|---|
| 原生模块 | 完全访问 | 通过 Expo Modules API |
| 开发体验 | 需 Xcode/Android Studio | Expo Go 快速预览 |
| 配置复杂度 | 手动配置 | 零配置 |
| 热更新 | Metro HMR | 支持(EAS Update) |
| 发布 | 手动签名打包 | EAS Build 云构建 |
| 适用场景 | 需要深度原生定制 | 快速原型、纯 RN 项目 |
创建项目
# React Native CLI
npx @react-native-community/cli init MyApp
# Expo
npx create-expo-app MyApp
cd MyApp
npx expo startAndroid 端配置
React Native 的 Android 端使用 Gradle 构建系统。android/build.gradle 和 android/app/build.gradle 分别配置项目和模块级参数。注意 Kotlin 版本、AGP 版本、NDK 版本和 minSdkVersion / targetSdkVersion 的匹配。
// android/build.gradle
buildscript {
ext {
buildToolsVersion = "34.0.0"
minSdkVersion = 23
compileSdkVersion = 34
targetSdkVersion = 34
ndkVersion = "25.1.8937393"
kotlinVersion = "1.9.20"
}
// ...
}iOS 端配置
iOS 端依赖 CocoaPods。React Native 项目中的 ios/Podfile 管理原生依赖。首次运行需执行 pod install:
# ios/Podfile
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, min_ios_version_supported
prepare_react_native_project!
target 'MyApp' do
config = use_native_modules!
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true,
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
endcd ios
pod install
cd ..Metro Bundler
Metro 是 React Native 的 JavaScript 打包器,负责 JS 代码的打包、转换和热更新。运行 npx react-native start 启动 Metro,它默认监听 8081 端口。
Hermes 引擎
Hermes 是 Meta 为 React Native 优化的 JavaScript 引擎。启用 Hermes 可显著减少 App 启动时间、降低内存占用、减小包体积:
// android/app/build.gradle
project.ext.react = [
enableHermes: true // 启用 Hermes
]# ios/Podfile
use_react_native!(
:hermes_enabled => true
)项目目录结构
MyApp/
├── src/
│ ├── App.tsx # 应用根组件
│ ├── components/ # 可复用组件
│ ├── screens/ # 页面
│ ├── navigation/ # 导航配置
│ ├── services/ # 网络/存储服务
│ └── utils/ # 工具函数
├── android/ # Android 原生工程
├── ios/ # iOS 原生工程
├── __tests__/ # 测试
├── index.js # 入口文件
├── package.json
├── metro.config.js # Metro 打包配置
├── babel.config.js # Babel 编译配置
└── tsconfig.json # TypeScript 配置// App.tsx
import React from 'react';
import { SafeAreaView, Text, StyleSheet } from 'react-native';
const App: React.FC = () => {
return (
<SafeAreaView style={styles.container}>
<Text>Hello, React Native!</Text>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
export default App;应用架构模式
MVC(Model-View-Controller)
MVC 是经典的架构模式,将应用分为三个核心层:
- Model:数据和业务逻辑层,管理数据状态和操作
- View:UI 展示层,负责界面的呈现
- Controller:控制层,处理用户输入、更新 Model 和 View
在 Android 早期开发中,Activity/Fragment 同时承担 Controller 和部分 View 的职责,导致类文件臃肿。MVC 的典型问题是 Model 和 View 之间存在耦合,Controller 容易变得过于庞大。
// Android MVC 示例
// Model
data class User(val name: String, val email: String)
// Controller (Activity)
class UserControllerActivity : AppCompatActivity() {
private lateinit var userModel: User
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
textView = findViewById(R.id.textView)
loadUser()
}
private fun loadUser() {
// 从网络加载数据
ApiService.getUser { user ->
userModel = user
textView.text = "${user.name} - ${user.email}"
}
}
}MVP(Model-View-Presenter)
MVP 通过引入 Presenter 层解决了 MVC 的测试性问题。View 定义接口,Presenter 持有 View 接口引用,Model 与 View 完全解耦。
优势在于 Presenter 可独立进行单元测试(不依赖 Android 框架),View 职责单一。劣势是每个页面都需要定义 View 接口,导致接口膨胀;Presenter 中仍然存在大量 UI 逻辑。
// MVP 示例
// View 接口
interface UserView {
fun showLoading()
fun hideLoading()
fun showUser(user: User)
fun showError(message: String)
}
// Presenter
class UserPresenter(private val view: UserView) {
fun loadUser(userId: String) {
view.showLoading()
ApiService.getUser(userId) { result ->
view.hideLoading()
result.onSuccess { user ->
view.showUser(user)
}.onFailure { error ->
view.showError(error.message ?: "Unknown error")
}
}
}
}
// Activity 实现 View 接口
class UserActivity : AppCompatActivity(), UserView {
private lateinit var presenter: UserPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
presenter = UserPresenter(this)
presenter.loadUser("123")
}
override fun showLoading() { /* 显示 ProgressBar */ }
override fun hideLoading() { /* 隐藏 ProgressBar */ }
override fun showUser(user: User) { /* 渲染 UI */ }
override fun showError(message: String) { /* 显示错误 */ }
}MVVM(Model-View-ViewModel)
MVVM 是当前主流的架构模式,ViewModel 通过观察者模式或数据绑定将数据变化自动推送到 View。
Android MVVM
Android 官方推荐使用 ViewModel + StateFlow/LiveData + DataBinding(或 Jetpack Compose 的 Observable 状态):
// ViewModel
class UserViewModel : ViewModel() {
private val _user = MutableStateFlow<User?>(null)
val user: StateFlow<User?> = _user.asStateFlow()
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
private val repository = UserRepository()
fun loadUser(userId: String) {
viewModelScope.launch {
_isLoading.value = true
try {
_user.value = repository.getUser(userId)
} catch (e: Exception) {
// 处理异常
} finally {
_isLoading.value = false
}
}
}
}
// Compose UI
@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
val user by viewModel.user.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
if (isLoading) {
CircularProgressIndicator()
} else {
user?.let {
Text("${it.name} - ${it.email}")
}
}
}iOS MVVM
SwiftUI 与 Combine 框架天然支持 MVVM,通过 @Published 属性和 ObservableObject 协议实现双向绑定:
// ViewModel
class UserViewModel: ObservableObject {
@Published var user: User?
@Published var isLoading = false
private let repository = UserRepository()
func loadUser(userId: String) {
isLoading = true
repository.getUser(userId) { [weak self] result in
DispatchQueue.main.async {
self?.isLoading = false
switch result {
case .success(let user):
self?.user = user
case .failure(let error):
// 处理错误
break
}
}
}
}
}
// View
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
VStack {
if viewModel.isLoading {
ProgressView()
} else if let user = viewModel.user {
Text("\(user.name) - \(user.email)")
}
}
.onAppear {
viewModel.loadUser(userId: "123")
}
}
}Flutter MVVM
Flutter 没有内置的 MVVM 框架,通常结合 setState、Provider、Riverpod、BLoC 等状态管理方案:
// ViewModel (使用 Provider)
class UserViewModel extends ChangeNotifier {
User? _user;
bool _isLoading = false;
User? get user => _user;
bool get isLoading => _isLoading;
final UserRepository _repository = UserRepository();
Future<void> loadUser(String userId) async {
_isLoading = true;
notifyListeners();
try {
_user = await _repository.getUser(userId);
} catch (e) {
// 处理异常
} finally {
_isLoading = false;
notifyListeners();
}
}
}
// View (Widget)
class UserScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final viewModel = context.watch<UserViewModel>();
if (viewModel.isLoading) {
return const CircularProgressIndicator();
}
return Text('${viewModel.user?.name} - ${viewModel.user?.email}');
}
}Clean Architecture
Clean Architecture 由 Robert C. Martin 提出,核心原则是依赖反转(Dependency Inversion),即高层模块不依赖低层模块,二者都依赖抽象接口。
典型的 Clean Architecture 分为三层:
domain 层:最内层,包含业务实体(Entity)、用例(UseCase)和仓库接口(Repository Interface)。该层不依赖任何框架,纯粹使用 Kotlin/Dart/Swift 标准库。
// domain 层示例 - Kotlin
// Entity
data class User(val id: String, val name: String, val email: String)
// Repository 接口
interface UserRepository {
suspend fun getUser(id: String): User
suspend fun saveUser(user: User)
}
// UseCase
class GetUserUseCase(private val repository: UserRepository) {
suspend operator fun invoke(id: String): User {
return repository.getUser(id)
}
}data 层:实现 domain 层定义的接口,负责数据获取和存储。包含 Repository 实现、数据源(Data Source,如 Room DAO、Retrofit API)、数据映射(DTO -> Entity)。
// data 层示例
// Data Source
interface UserRemoteDataSource {
suspend fun fetchUser(id: String): UserDTO
}
// Repository 实现
class UserRepositoryImpl(
private val remoteDataSource: UserRemoteDataSource,
private val localDataSource: UserLocalDataSource
) : UserRepository {
override suspend fun getUser(id: String): User {
return try {
val dto = remoteDataSource.fetchUser(id)
dto.toEntity()
} catch (e: Exception) {
localDataSource.getCachedUser(id)
}
}
}presentation 层:UI 相关代码,包含 ViewModel、Compose/SwiftUI/Widget 等。该层依赖 domain 层的 UseCase。
Clean Architecture 的层级依赖规则:外层可以依赖内层,内层不依赖外层。数据流向为 presentation -> domain -> data。
Android 推荐架构
Android 官方推荐基于 Jetpack 组件的 MVVM + Clean Architecture 分层:
UI Layer:使用 Jetpack Compose 或 View Binding 构建 UI。ViewModel 通过 StateFlow 暴露 UI 状态,UI 通过 collectAsState 订阅状态变化。
Data Layer:Repository 模式统一管理数据来源。数据来源包括 Room 数据库(本地持久化)、Retrofit 网络请求(远程数据)、DataStore(轻量配置)。
架构数据流:
UI (Compose) -> ViewModel (StateFlow) -> Repository -> DataSource (Room + Retrofit)// 完整示例
// DataSource
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: String): UserEntity
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: UserEntity)
}
interface UserApi {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: String): UserResponse
}
// Repository
class UserRepository(
private val userDao: UserDao,
private val userApi: UserApi
) {
fun getUser(id: String): Flow<Result<User>> = flow {
// 先从本地获取缓存
val cached = userDao.getUser(id)
if (cached != null) emit(Result.success(cached.toDomain()))
// 再从网络获取最新数据
try {
val response = userApi.getUser(id)
userDao.insertUser(response.toEntity())
emit(Result.success(response.toDomain()))
} catch (e: Exception) {
if (cached == null) emit(Result.failure(e))
}
}
}
// ViewModel
class UserViewModel(
private val repository: UserRepository
) : ViewModel() {
val user: StateFlow<UiState<User>> = repository.getUser("123")
.map { UiState.Success(it.getOrNull()) }
.catch { emit(UiState.Error(it.message)) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), UiState.Loading)
}
// UI
sealed class UiState<out T> {
object Loading : UiState<Nothing>()
data class Success<T>(val data: T?) : UiState<T>()
data class Error(val message: String) : UiState<Nothing>()
}iOS 推荐架构
iOS 推荐架构有以下几种主流方案:
SwiftUI + Combine + MVVM
这是 Apple 官方推荐的模式。View 声明式描述 UI,ViewModel 作为 ObservableObject,通过 @Published 和 @StateObject 管理状态。
// Model
struct User: Codable, Identifiable {
let id: String
let name: String
let email: String
}
// Repository
protocol UserRepositoryProtocol {
func fetchUser(id: String) async throws -> User
}
class UserRepository: UserRepositoryProtocol {
func fetchUser(id: String) async throws -> User {
let url = URL(string: "https://api.example.com/users/\(id)")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
}
// ViewModel
@MainActor
class UserViewModel: ObservableObject {
@Published var user: User?
@Published var isLoading = false
@Published var error: Error?
private let repository: UserRepositoryProtocol
init(repository: UserRepositoryProtocol = UserRepository()) {
self.repository = repository
}
func loadUser(id: String) async {
isLoading = true
error = nil
do {
user = try await repository.fetchUser(id: id)
} catch {
self.error = error
}
isLoading = false
}
}
// View
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
Group {
if viewModel.isLoading {
ProgressView()
} else if let error = viewModel.error {
Text("Error: \(error.localizedDescription)")
} else if let user = viewModel.user {
VStack {
Text(user.name).font(.title)
Text(user.email).font(.body)
}
}
}
.task {
await viewModel.loadUser(id: "123")
}
}
}Clean Swift(VIP)
Clean Swift 是 Uncle Bob Clean Architecture 在 iOS 领域的实践变体,也称为 VIP 模式。VIP 是 View-Interactor-Presenter 的缩写,强调单向数据流和严格的责任分离。
VIPER
VIPER 是另一种组件级架构模式,包含 View、Interactor、Presenter、Entity、Router 五个组件。每个组件职责单一,测试性极佳,但文件数量较多,适合大型团队和复杂模块。
App 开发核心概念
生命周期
Android 生命周期
Activity 的生命周期包含六个核心回调:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Activity 创建,执行初始化。可接收 savedInstanceState 恢复状态
}
override fun onStart() {
super.onStart()
// Activity 可见但不可交互
}
override fun onResume() {
super.onResume()
// Activity 位于前台,可交互
}
override fun onPause() {
super.onPause()
// Activity 部分可见(如对话框弹出),保存轻量状态
}
override fun onStop() {
super.onStop()
// Activity 不可见,释放资源
}
override fun onDestroy() {
super.onDestroy()
// Activity 销毁,清理所有资源
}
}Fragment 生命周期在 Activity 生命周期基础上增加了 onAttach、onCreateView、onViewCreated、onDestroyView、onDetach 等回调。
iOS 生命周期
iOS 应用生命周期通过 UIApplicationDelegate 和 UISceneDelegate(iOS 13+)管理:
// AppDelegate - 应用级生命周期
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 应用启动完成,执行初始化
return true
}
}
// SceneDelegate - 场景级生命周期
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneWillEnterForeground(_ scene: UIScene) {
// 场景即将进入前台
}
func sceneDidBecomeActive(_ scene: UIScene) {
// 场景变为活跃状态
}
func sceneWillResignActive(_ scene: UIScene) {
// 场景即将进入非活跃状态
}
func sceneDidEnterBackground(_ scene: UIScene) {
// 场景已进入后台
}
}Flutter 生命周期
Flutter 通过 WidgetsBindingObserver 监听应用生命周期:
class MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
// 应用位于前台
break;
case AppLifecycleState.inactive:
// 应用处于非活跃状态(如来电)
break;
case AppLifecycleState.paused:
// 应用进入后台
break;
case AppLifecycleState.detached:
// 应用即将被销毁
break;
}
}
}React Native 生命周期
React Native 通过 AppState API 监听应用生命周期:
import React, { useEffect, useRef } from 'react';
import { AppState, AppStateStatus } from 'react-native';
const App: React.FC = () => {
const appState = useRef(AppState.currentState);
useEffect(() => {
const subscription = AppState.addEventListener('change',
(nextAppState: AppStateStatus) => {
if (appState.current.match(/inactive|background/) &&
nextAppState === 'active') {
console.log('应用回到前台');
}
if (nextAppState === 'background') {
console.log('应用进入后台');
}
appState.current = nextAppState;
}
);
return () => {
subscription.remove();
};
}, []);
return (
// 应用内容
);
};页面导航
Android 导航
Android 官方推荐使用 Navigation Component,它基于 Jetpack Navigation 库,通过 NavHost 和 NavController 管理页面跳转:
// 在 build.gradle.kts 中添加依赖
// implementation("androidx.navigation:navigation-compose:2.7.6")
// Compose 中使用 Navigation
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") {
HomeScreen(
onNavigateToDetail = { id ->
navController.navigate("detail/$id")
}
)
}
composable(
"detail/{id}",
arguments = listOf(navArgument("id") { type = NavType.StringType })
) { backStackEntry ->
val id = backStackEntry.arguments?.getString("id") ?: ""
DetailScreen(id)
}
}
}<!-- XML 方式使用 Navigation Component -->
<!-- res/navigation/nav_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.HomeFragment">
<action
android:id="@+id/action_home_to_detail"
app:destination="@id/detailFragment" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.example.DetailFragment">
<argument android:name="id" app:argType="string" />
</fragment>
</navigation>iOS 导航
SwiftUI 使用 NavigationStack(iOS 16+)和 NavigationLink 进行导航管理:
struct ContentView: View {
var body: some View {
NavigationStack {
HomeView()
.navigationDestination(for: String.self) { id in
DetailView(id: id)
}
}
}
}
struct HomeView: View {
var body: some View {
List(users) { user in
NavigationLink(value: user.id) {
Text(user.name)
}
}
.navigationTitle("用户列表")
}
}UIKit 使用 UINavigationController 管理导航栈,通过 pushViewController 和 popViewController 进行页面跳转。
Flutter 导航
Flutter Navigator 2.0 结合 GoRouter 是目前推荐的导航方案:
// 使用 GoRouter
final router = GoRouter(
initialLocation: '/home',
routes: [
GoRoute(
path: '/home',
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: '/detail/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return DetailScreen(id: id);
},
),
],
);
// 在 MaterialApp 中使用
MaterialApp.router(
routerConfig: router,
// ...
)
// 导航
context.go('/detail/123');
context.pop();React Native 导航
React Navigation 是 React Native 社区最主流的导航方案:
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
type RootStackParamList = {
Home: undefined;
Detail: { id: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
const Tab = createBottomTabNavigator();
// Stack Navigator
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
);
}
// Bottom Tab Navigator
function AppNavigator() {
return (
<Tab.Navigator>
<Tab.Screen name="HomeTab" component={HomeStack} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
// 使用 NavigationContainer
export default function App() {
return (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
}
// 导航跳转
navigation.navigate('Detail', { id: '123' });
navigation.goBack();本地存储
各平台提供的本地存储方案对比:
| 维度 | Android | iOS | Flutter | React Native |
|---|---|---|---|---|
| 轻量键值 | SharedPreferences / DataStore | UserDefaults | SharedPreferences | AsyncStorage |
| 安全存储 | EncryptedSharedPreferences | Keychain | flutter_secure_storage | react-native-keychain |
| 关系型数据库 | Room (SQLite) | CoreData / SQLite | sqflite / drift | react-native-sqlite-storage |
| 高性能 KV | MMKV | MMKV | MMKV | MMKV |
SharedPreferences / UserDefaults
// Android SharedPreferences
val prefs = context.getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
prefs.edit()
.putString("token", "abc123")
.putInt("count", 42)
.apply()
val token = prefs.getString("token", "")// iOS UserDefaults
UserDefaults.standard.set("abc123", forKey: "token")
UserDefaults.standard.set(42, forKey: "count")
let token = UserDefaults.standard.string(forKey: "token") ?? ""// Flutter SharedPreferences
final prefs = await SharedPreferences.getInstance();
await prefs.setString('token', 'abc123');
await prefs.setInt('count', 42);
final token = prefs.getString('token') ?? '';// React Native AsyncStorage
import AsyncStorage from '@react-native-async-storage/async-storage';
await AsyncStorage.setItem('token', 'abc123');
const token = await AsyncStorage.getItem('token');Room 数据库
Room 是 Android 官方推荐的 SQLite ORM 框架,提供编译时 SQL 校验:
// Entity
@Entity(tableName = "users")
data class UserEntity(
@PrimaryKey val id: String,
val name: String,
val email: String
)
// DAO
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: String): UserEntity?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(users: List<UserEntity>)
}
// Database
@Database(entities = [UserEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
// 使用
val db = Room.databaseBuilder(
context,
AppDatabase::class.java,
"app_database"
).build()CoreData
CoreData 是 Apple 官方的对象图管理和持久化框架:
import CoreData
// 创建持久化容器
let container = NSPersistentContainer(name: "AppModel")
container.loadPersistentStores { _, error in
if let error = error {
fatalError("CoreData 加载失败: \(error)")
}
}
// 保存数据
let context = container.viewContext
let user = UserEntity(context: context)
user.id = "123"
user.name = "张三"
try? context.save()
// 查询数据
let request = UserEntity.fetchRequest()
request.predicate = NSPredicate(format: "id == %@", "123")
let users = try? context.fetch(request) as? [UserEntity]MMKV 高性能 KV 存储
MMKV 基于 mmap 内存映射文件,性能远优于 SharedPreferences,适合存储高频读写的数据:
// Android MMKV
val kv = MMKV.defaultMMKV()
kv.encode("token", "abc123")
kv.encode("count", 42)
val token = kv.decodeString("token", "")调试与测试
调试工具
Android Studio Profiler
Android Studio 内置的 Profiler 工具集提供以下性能分析能力:
- CPU Profiler:跟踪方法执行时间、识别性能瓶颈。支持 Sample Java Methods、Trace Java Methods 和 System Trace 三种模式
- Memory Profiler:实时查看堆内存使用、检测内存泄漏、生成 Heap Dump 并分析对象引用链
- Network Profiler:监控网络请求的时序、数据量、状态码,支持抓包查看请求/响应详情
- Energy Profiler:分析 App 的能耗情况,定位高耗电操作
使用 Android Studio Profiler 时建议在真机上运行以获得最准确的性能数据。Heap Dump 文件可使用 Memory Analyzer(MAT)进行深度分析。
Chrome DevTools
Chrome DevTools 是 React Native 和 Flutter Web 开发的主要调试工具:
- Elements:查看 DOM 结构(Web 端)
- Console:查看日志输出,支持断点调试 JavaScript/Dart
- Network:网络请求监控
- Performance:页面渲染性能分析
- Sources:源码断点调试
- Memory:堆内存快照与分析
- Application:本地存储、Cookies 等数据查看
Flutter DevTools
Flutter DevTools 是 Flutter 专用的全功能调试套件:
# 启动 DevTools
flutter pub global activate devtools
dart devtools
# 或在 IDE 中直接点击 Open DevTools 按钮Flutter DevTools 提供以下功能:
- Widget Inspector:可视化浏览 Widget 树,查看布局约束、属性值和渲染边界
- Timeline:帧渲染性能分析,识别 UI 线程和光栅线程的耗时任务
- CPU Profiler:Dart 方法级别的 CPU 时间分析
- Memory View:内存使用情况、GC 频率、对象分配追踪
- Network View:HTTP 请求监控,查看请求/响应头和体
- Logging View:应用日志输出
- App Size:分析 App 包体积组成
React Native Debugger
React Native 的调试工具链:
- React Native DevTools:基于 Chrome DevTools,支持 JS 断点调试、Console 日志查看
- React DevTools:查看 React 组件树、Props 和 State 变化、组件渲染性能分析
- Flipper:Meta 出品的移动端调试平台,集成日志、网络、数据库、布局检查等功能
- React Native CLI 调试菜单:摇晃设备或
Cmd+D(模拟器)打开调试菜单
性能分析工具
- Systrace:Android 系统级跟踪工具,分析 UI 渲染、进程调度等系统行为
- Instruments:macOS 性能分析工具,支持 Time Profiler、Allocations、Leaks 等模板
- Perfetto:Android 下一代性能追踪工具,替代 Systrace,支持更长时间的录制和更丰富的 Trace 类型
内存分析
- MAT(Memory Analyzer Tool):Java/Kotlin 堆分析工具,自动检测内存泄漏、计算 Retained Size
- LeakCanary:Android 内存泄漏自动检测库,提供泄漏路径分析
- Xcode Memory Graph Debugger:可视化查看 iOS 对象引用关系,检测循环引用
网络调试
- Charles Proxy:跨平台 HTTP/HTTPS 抓包工具,支持断点修改请求/响应、限速模拟
- Proxyman:macOS 原生抓包工具,支持 HTTP/HTTPS、WebSocket 抓包
- Stetho:Facebook 开源的 Android 调试工具,支持在 Chrome DevTools 中查看网络请求、数据库和 SharedPreferences
测试体系
单元测试
单元测试验证单个方法或类的行为是否符合预期,不依赖 Android/iOS 框架。
// Android JUnit 4 + MockK
class UserViewModelTest {
private val repository = mockk<UserRepository>()
private val viewModel = UserViewModel(repository)
@Test
fun `loadUser should update user state`() = runTest {
val user = User("1", "张三", "zhangsan@example.com")
coEvery { repository.getUser("1") } returns user
viewModel.loadUser("1")
assertEquals(user, viewModel.user.value)
}
}// iOS XCTest
final class UserViewModelTests: XCTestCase {
var viewModel: UserViewModel!
var mockRepository: MockUserRepository!
override func setUp() {
super.setUp()
mockRepository = MockUserRepository()
viewModel = UserViewModel(repository: mockRepository)
}
func testLoadUserSuccess() async {
let user = User(id: "1", name: "张三", email: "zhangsan@example.com")
mockRepository.mockUser = user
await viewModel.loadUser(id: "1")
XCTAssertEqual(viewModel.user?.name, "张三")
}
}// Flutter 单元测试
void main() {
test('UserViewModel loads user correctly', () async {
final repository = MockUserRepository();
when(() => repository.getUser('1'))
.thenAnswer((_) async => User(id: '1', name: '张三', email: 'zhangsan@example.com'));
final viewModel = UserViewModel(repository: repository);
await viewModel.loadUser('1');
expect(viewModel.user?.name, '张三');
});
}Widget / UI 测试
// Flutter Widget 测试
void main() {
testWidgets('UserScreen shows user name', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(home: UserScreen(userId: '1')),
);
// 等待异步加载完成
await tester.pumpAndSettle();
expect(find.text('张三'), findsOneWidget);
});
}// Android Compose UI 测试
@Test
fun userScreen_showsUser() {
composeTestRule.setContent {
UserScreen(viewModel = viewModel)
}
composeTestRule.onNodeWithText("张三").assertIsDisplayed()
}// iOS XCUITest
func testUserViewShowsName() {
let app = XCUIApplication()
app.launch()
let nameLabel = app.staticTexts["张三"]
XCTAssertTrue(nameLabel.waitForExistence(timeout: 5))
}集成测试
// Flutter Integration Test
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Full app flow test', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
// 验证首页显示
expect(find.text('用户列表'), findsOneWidget);
// 点击用户进入详情
await tester.tap(find.text('张三'));
await tester.pumpAndSettle();
// 验证详情页显示
expect(find.text('zhangsan@example.com'), findsOneWidget);
});
}// React Native Detox 测试
describe('UserFlow', () => {
beforeAll(async () => {
await device.launchApp();
});
it('should show user detail after tap', async () => {
await expect(element(by.text('用户列表'))).toBeVisible();
await element(by.text('张三')).tap();
await expect(element(by.text('zhangsan@example.com'))).toBeVisible();
});
});持续集成
GitHub Actions 矩阵构建
使用 GitHub Actions 的 Matrix 策略同时构建 Android 和 iOS 包:
name: App CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Run Android tests
run: ./gradlew testDebugUnitTest
build:
needs: test
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
include:
- os: ubuntu-latest
platform: android
build_command: ./gradlew assembleRelease
- os: macos-latest
platform: ios
build_command: xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -configuration Release
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Build ${{ matrix.platform }}
run: ${{ matrix.build_command }}Fastlane 自动化
Fastlane 是移动端 CI/CD 工具,可自动化证书管理、截图、构建和上传:
# Fastfile
default_platform(:android)
platform :android do
desc "构建并上传到 Firebase App Distribution"
lane :beta do
gradle(task: "assembleRelease")
firebase_app_distribution(
app: "1:123456789:android:abc123",
testers: "testers@example.com",
release_notes: "版本 #{get_version_name} 的 Beta 构建"
)
end
desc "构建并上传到 Google Play"
lane :production do
gradle(task: "assembleRelease")
upload_to_play_store(
track: "production",
release_status: "completed"
)
end
end
platform :ios do
desc "自动签名并构建"
lane :build do
match(type: "appstore") # 自动管理证书和 Provisioning Profile
gym(scheme: "MyApp") # 构建归档
end
desc "上传到 TestFlight"
lane :beta do
build
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end
end# Matchfile - 证书管理
git_url("https://github.com/company/ios-certs")
type("development")
app_identifier(["com.example.myapp"])分发平台
- TestFlight:Apple 官方 Beta 测试平台,支持内部和外部测试者,上限 10,000 人
- Firebase App Distribution:Google 的 Beta 分发平台,支持 Android 和 iOS,无测试人数上限
- Google Play Console:Android 正式发布平台,支持阶段性发布、A/B 测试、应用内评论
- App Store Connect:iOS 正式发布平台,支持 phased release、App 审核状态跟踪