当前位置: 首页 > news >正文

Flutter开发实战之CI/CD与发布流程

第12章:CI/CD与发布流程

在前面的章节中,我们学习了Flutter应用开发的各个方面,从基础UI构建到复杂的状态管理,从网络请求到本地存储。现在,我们将探讨一个同样重要但常被忽视的话题:如何将我们精心开发的应用高效、可靠地发布到各大应用商店。

想象一下,你花费了数月时间开发出一款功能完善的Flutter应用,但每次发布新版本时都需要手动打包、签名、上传,这不仅耗时耗力,还容易出错。本章将带你建立一套完整的自动化发布流程,让发布应用变得像点击一个按钮一样简单。

12.1 多环境配置管理

在实际开发中,我们通常需要维护多个环境:开发环境(dev)、测试环境(test)、预发布环境(staging)和生产环境(prod)。每个环境可能使用不同的API地址、数据库连接、第三方服务密钥等配置。

12.1.1 环境配置的重要性

为什么需要多环境配置?想象一下这样的场景:

  • 开发环境:使用本地或开发服务器的API,可以随意测试和调试
  • 测试环境:使用稳定的测试数据,供QA团队进行功能测试
  • 预发布环境:与生产环境配置几乎相同,用于最终验证
  • 生产环境:真实用户使用的环境,配置最为严格

如果没有合理的环境配置管理,你可能会遇到以下问题:

  • 开发时误连生产数据库,造成数据污染
  • 测试环境的配置意外发布到生产环境
  • 不同环境的切换需要手动修改代码

12.1.2 创建环境配置文件

首先,我们在项目根目录下创建不同环境的配置文件:

// lib/config/app_config.dart
class AppConfig {static const String appName = String.fromEnvironment('APP_NAME', defaultValue: 'MyApp');static const String apiBaseUrl = String.fromEnvironment('API_BASE_URL', defaultValue: 'https://api.example.com');static const String environment = String.fromEnvironment('ENVIRONMENT', defaultValue: 'dev');static const bool enableDebugMode = bool.fromEnvironment('DEBUG_MODE', defaultValue: true);static const String analyticsKey = String.fromEnvironment('ANALYTICS_KEY', defaultValue: '');// 环境判断方法static bool get isDevelopment => environment == 'dev';static bool get isProduction => environment == 'prod';static bool get isStaging => environment == 'staging';// 获取完整的API URLstatic String getApiUrl(String endpoint) {return '$apiBaseUrl$endpoint';}
}

然后创建环境特定的配置文件:

// lib/config/environments/dev_config.dart
class DevConfig {static const Map<String, String> config = {'APP_NAME': 'MyApp Dev','API_BASE_URL': 'https://dev-api.example.com','ENVIRONMENT': 'dev','DEBUG_MODE': 'true','ANALYTICS_KEY': 'dev_analytics_key',};
}// lib/config/environments/prod_config.dart
class ProdConfig {static const Map<String, String> config = {'APP_NAME': 'MyApp','API_BASE_URL': 'https://api.example.com','ENVIRONMENT': 'prod','DEBUG_MODE': 'false','ANALYTICS_KEY': 'prod_analytics_key',};
}

12.1.3 使用环境变量启动应用

为了在不同环境下启动应用,我们需要修改启动脚本。在项目根目录创建启动脚本:

# scripts/run_dev.sh
#!/bin/bash
flutter run --dart-define=APP_NAME="MyApp Dev" \--dart-define=API_BASE_URL="https://dev-api.example.com" \--dart-define=ENVIRONMENT="dev" \--dart-define=DEBUG_MODE="true"# scripts/run_prod.sh
#!/bin/bash
flutter run --release \--dart-define=APP_NAME="MyApp" \--dart-define=API_BASE_URL="https://api.example.com" \--dart-define=ENVIRONMENT="prod" \--dart-define=DEBUG_MODE="false"

在应用中使用配置:

// lib/main.dart
import 'package:flutter/material.dart';
import 'config/app_config.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(title: AppConfig.appName,debugShowCheckedModeBanner: AppConfig.enableDebugMode,home: HomeScreen(),);}
}// lib/services/api_service.dart
import '../config/app_config.dart';class ApiService {static Future<Map<String, dynamic>> fetchUserData() async {final url = AppConfig.getApiUrl('/users/profile');if (AppConfig.isDevelopment) {print('DEV: Fetching from $url');}// 网络请求逻辑// ...}
}

12.2 代码签名与证书配置

代码签名是移动应用发布的关键步骤,它确保应用的完整性和来源可信度。简单来说,代码签名就像是给你的应用盖上一个官方印章,证明这个应用确实是你开发的,并且没有被恶意篡改。

12.2.1 Android代码签名

Android使用密钥库(keystore)进行应用签名。我们需要创建一个签名密钥并配置构建脚本。

创建签名密钥
# 创建密钥库文件
keytool -genkey -v -keystore ~/my-release-key.keystore \-alias my-key-alias \-keyalg RSA \-keysize 2048 \-validity 10000

这个命令会询问你一系列问题,包括密码、组织信息等。请务必记住密码和别名,并将密钥库文件保存在安全的地方。

配置签名信息

android/app/build.gradle文件中配置签名信息:

android {...signingConfigs {release {if (project.hasProperty('myapp.signing.keystore')) {storeFile file(project.property('myapp.signing.keystore'))storePassword project.property('myapp.signing.store_password')keyAlias project.property('myapp.signing.key_alias')keyPassword project.property('myapp.signing.key_password')}}}buildTypes {release {signingConfig signingConfigs.releaseminifyEnabled trueuseProguard trueproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}

创建android/gradle.properties文件存储签名配置:

# 签名配置(敏感信息,不要提交到版本控制)
myapp.signing.keystore=../my-release-key.keystore
myapp.signing.store_password=your_store_password
myapp.signing.key_alias=my-key-alias
myapp.signing.key_password=your_key_password

重要提醒: gradle.properties文件包含敏感信息,应该添加到.gitignore文件中,避免提交到版本控制系统。

12.2.2 iOS代码签名

iOS的代码签名相对复杂,需要在苹果开发者中心配置证书、标识符和描述文件。

配置开发者账号
  1. 注册Apple Developer账号:访问developer.apple.com注册账号(年费99美元)
  2. 创建App ID:在开发者中心创建应用标识符
  3. 生成证书:创建开发和发布证书
  4. 创建Provisioning Profile:关联证书、设备和App ID
在Xcode中配置签名

打开ios/Runner.xcworkspace,在Xcode中配置签名:

Target: Runner
-> Signing & Capabilities
-> Team: 选择你的开发团队
-> Bundle Identifier: 输入你的应用包名

对于自动化构建,我们还需要配置ios/Runner/Info.plist

<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleDisplayName</key>
<string>$(APP_DISPLAY_NAME)</string>

12.2.3 证书管理最佳实践

  1. 使用环境变量存储敏感信息
# 在CI/CD系统中设置环境变量
export ANDROID_KEYSTORE_PASSWORD="your_password"
export IOS_CERTIFICATE_PASSWORD="your_password"
  1. 定期更新证书

    • Android密钥库建议25年有效期
    • iOS证书每年需要更新
  2. 备份重要文件

    • 密钥库文件
    • 证书文件
    • 密码信息
  3. 使用专用的签名服务器
    对于企业级应用,考虑使用专门的签名服务器,避免在开发机器上存储生产环境的签名证书。

12.3 GitHub Actions自动化构建

GitHub Actions是GitHub提供的CI/CD服务,可以自动化构建、测试和部署流程。对于Flutter项目,我们可以配置Actions来自动构建Android和iOS应用。

12.3.1 创建基础工作流

在项目根目录创建.github/workflows/build.yml文件:

name: Build and Teston:push:branches: [ main, develop ]pull_request:branches: [ main ]jobs:test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Flutteruses: subosito/flutter-action@v2with:flutter-version: '3.16.0'- name: Install dependenciesrun: flutter pub get- name: Run testsrun: flutter test- name: Analyze coderun: flutter analyzebuild-android:needs: testruns-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Flutteruses: subosito/flutter-action@v2with:flutter-version: '3.16.0'- name: Install dependenciesrun: flutter pub get- name: Build APKrun: flutter build apk --release- name: Upload APKuses: actions/upload-artifact@v3with:name: release-apkpath: build/app/outputs/flutter-apk/app-release.apkbuild-ios:needs: testruns-on: macos-lateststeps:- uses: actions/checkout@v3- name: Setup Flutteruses: subosito/flutter-action@v2with:flutter-version: '3.16.0'- name: Install dependenciesrun: flutter pub get- name: Build iOSrun: flutter build ios --release --no-codesign- name: Upload iOS builduses: actions/upload-artifact@v3with:name: release-iospath: build/ios/iphoneos/Runner.app

12.3.2 配置签名自动化

为了在CI/CD中进行签名,我们需要将签名文件和密码作为secrets存储在GitHub中。

Android签名配置
  1. 上传密钥库文件
# 将密钥库文件转换为base64编码
base64 my-release-key.keystore > keystore.base64
  1. 在GitHub设置secrets

    • ANDROID_KEYSTORE_BASE64:密钥库文件的base64编码
    • ANDROID_KEYSTORE_PASSWORD:密钥库密码
    • ANDROID_KEY_ALIAS:密钥别名
    • ANDROID_KEY_PASSWORD:密钥密码
  2. 更新工作流配置

  build-android-signed:needs: testruns-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Flutteruses: subosito/flutter-action@v2with:flutter-version: '3.16.0'- name: Install dependenciesrun: flutter pub get- name: Decode keystorerun: |echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android/app/my-release-key.keystore- name: Create key.propertiesrun: |cat > android/key.properties << EOFstorePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}storeFile=my-release-key.keystoreEOF- name: Build signed APKrun: flutter build apk --release- name: Build App Bundlerun: flutter build appbundle --release
iOS签名配置

iOS的签名配置更加复杂,需要配置证书和描述文件:

  build-ios-signed:needs: testruns-on: macos-lateststeps:- uses: actions/checkout@v3- name: Setup Flutteruses: subosito/flutter-action@v2with:flutter-version: '3.16.0'- name: Install dependenciesrun: flutter pub get- name: Import certificates<
http://www.dtcms.com/a/300552.html

相关文章:

  • Java AI面试实战:Spring AI与RAG技术落地
  • MySQL - 主从复制与读写分离
  • VILA系列论文解读
  • 预处理详解
  • rust-模块树中引用项的路径
  • PostgreSQL并发控制
  • Android:Reverse 实战 part 2 番外 IDA python
  • Android MQTT 长连接最佳实践技术分享
  • 力扣-76.最小覆盖子串
  • 安卓怎么做一个像QQ一样的开关切换控件
  • Kotlin位运算
  • EMCCD相机与电可调变焦透镜的同步控制系统设计与实现
  • Kotlin递归
  • MYSQL:索引
  • golang设置http代理
  • Flink2.0学习笔记:Stream API 常用转换算子
  • maven <dependencyManagement>标签的作用
  • 基于开源AI智能名片链动2+1模式S2B2C商城小程序的人格品牌化实现路径研究
  • 常用git命令集锦
  • conda和pip安装包时的注意细节,以及下载慢时如何配置镜像地址
  • 积分兑换小程序Java
  • Megatron 中的 TensorParallel, PipelineParallel, ContextParallel,ExpertParallel
  • PHP框架之Laravel框架教程:3. 数据库操作(简要)
  • PowerDesigner 画ER图并生成sql 教程
  • 【学习笔记】MimicGen: 基于人类演示的可扩展机器人学习数据生成系统
  • GIt学习——分布式版本控制工具
  • STL——list
  • 金融科技中的虚拟助手
  • 15.7 DeepSpeed实战:单卡38GB到多卡12GB,3倍效率提升的ZeRO-3配置全解
  • 【专题十五】BFS 解决 FloodFill