第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.pswp.cn/news/916707.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916707.shtml
英文地址,请注明出处:http://en.pswp.cn/news/916707.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch 的3种数据迁移方案

在实际工作中&#xff0c;我们经常会遇到需要将自建的 Elasticsearch 迁移上云&#xff0c;或者迁移到其他 ES 集群的情况。这时&#xff0c;选择合适的数据迁移方案就显得尤为重要啦。今天就来给大家介绍三种常用的迁移方案&#xff0c;分别是 COS 快照、logstash 和 elastics…

MySQL 中的“双路排序”与“单路排序”:原理、判别与实战调优

一句话导读 ORDER BY 不能走索引时&#xff0c;MySQL 会在 Server 层做一次 filesort。内部实现分 单路&#xff08;全字段&#xff09; 与 双路&#xff08;rowid&#xff09; 两种&#xff1b;了解它们的触发条件、判别方法与调优思路&#xff0c;是 SQL 性能优化的必修课。一…

OpenLayers 综合案例-信息窗体-弹窗

看过的知识不等于学会。唯有用心总结、系统记录&#xff0c;并通过温故知新反复实践&#xff0c;才能真正掌握一二 作为一名摸爬滚打三年的前端开发&#xff0c;开源社区给了我饭碗&#xff0c;我也将所学的知识体系回馈给大家&#xff0c;助你少走弯路&#xff01; OpenLayers…

GaussDB 开发基本规范

1 集中式1.1数据库价值特性推荐特性分类特性列表说明表类型PARTITION表数据分区存储引擎行存储按行顺序存储表&#xff0c;建议点查&#xff0c;增删改操作较多场景下使用事务事务块显式启动事务单语句事务不显式启动事务&#xff0c;单语句即为事务扩容在线扩容扩节点和数据重…

工作中使用git可能遇到的场景

1.main历史发布版本出问题需要查看&#xff0c;怎么切换历史发布版本&#xff1f;git reset --hard commitid 更新本地库和代码2.A分支的代码已经做过一些功能&#xff0c;想迁移到B分支当前在A分支git checkout B &#xff08;切换到B分支&#xff09;git cherry-pick A的com…

【Spring AI】本地大型语言模型工具-Ollama

Ollama 是一个专注于在本地运行大型语言模型&#xff08;LLM&#xff09;的工具&#xff0c;支持多种开源模型&#xff08;如 Llama 3、Mistral、Gemma 等&#xff09;&#xff0c;提供简单的命令行和 API 接口。<dependency><groupId>org.springframework.ai</…

电机S加减速

STM32步进电机S型加减速算法_stm32___build__-2048 AI社区 以上&#xff0c;电机加减速说的非常清楚&#xff0c;收藏点赞&#xff01;

一、初识 Linux 与基本命令

作者&#xff1a;IvanCodes 日期&#xff1a;2025年7月28日 专栏&#xff1a;Linux教程 思维导图 一、Linux 简介 1.1 什么是 Linux? Linux 是一种自由、开源的类Unix操作系统内核&#xff0c;由林纳斯托瓦兹 (Linus Torvalds) 在1991年首次发布。我们通常所说的 “Linux 系统…

解决angular与jetty websocket 每30s自动断连的问题

背景&#xff1a;前端&#xff1a;angular 12&#xff0c;websocket接口由lib.dom.d.ts提供后端&#xff1a;java&#xff0c;websocket接口由jetty 12提供问题现象&#xff1a;前端连上server后&#xff0c;每隔30s就会断开&#xff0c;由于长时间空闲&#xff0c;会导致webso…

【机器学习深度学习】模型私有化部署与微调训练:赋能特定问题处理能力

目录 前言 一、私有化部署的背景&#xff1a;通用能力 ≠ 企业实用 暴露问题 二、微调训练的核心目的 2.1 动作一&#xff1a;私有化部署&#xff08;Private Deployment&#xff09; 2.2 动作二&#xff1a;领域微调&#xff08;Domain Fine-Tuning&#xff09; 2.3 微…

Seq2Seq学习笔记

Seq2Seq模型概述Seq2Seq&#xff08;Sequence-to-Sequence&#xff09;是一种基于深度学习的序列生成模型&#xff0c;主要用于处理输入和输出均为序列的任务&#xff0c;如机器翻译、文本摘要、对话生成等。其核心思想是将可变长度的输入序列映射为另一个可变长度的输出序列。…

react useId

useId useId 是 React 18 引入的一个内置 Hook&#xff0c;用于生成唯一且稳定的 ID &#xff0c; 主要用于&#xff0c;解决在客户端和服务器端渲染&#xff08;SSR&#xff09;时&#xff0c;动态生成 ID 可能导致的冲突问题&#xff1b; 特别适合用于&#xff0c;需要关联 H…

排水管网实时监测筑牢城市安全防线

排水管网的实时监测工作&#xff0c;强调其对于保障城市安全的重要作用。“排水管网”明确了具体的关注对象&#xff0c;它是城市基础设施的重要组成部分&#xff0c;承担着雨水、污水排放等关键功能。“实时监测”突出了监测的及时性和持续性&#xff0c;意味着能够随时获取排…

SZU大学物理实验报告|电位差计

写在前面&#xff1a;博文里放图片&#xff0c;主要省去了对文档的排版时间&#xff0c;实验还是要自己做的&#xff0c;反正都要去实验室上课&#xff0c;顺带锻炼下动手能力。有些结果是实验手写的&#xff0c;所以看不到&#xff0c;有结果的可以对下结果差的不太多就行&…

RoPE简单解析

文章目录简介拆解一些tricks简介 因为RoPE的优异性能&#xff0c;其已成为各种大模型中位置编码的首选&#xff0c;包括多模态模型&#xff1b;在一些多模态模型或视频理解模型中&#xff0c;甚至会用到多维度RoPE。虽然RoPE已广泛应用&#xff0c;之前也看了不少针对其原理解…

windows 获取 APK 文件的包名和启动 Activity 名称

使用 aapt 命令确保环境变量配置正确&#xff1a;首先需要确保你的系统环境变量中包含了 Android SDK 的 build-tools 目录路径。这是因为 aapt 工具位于该目录下。运行命令&#xff1a; 打开命令提示符&#xff08;CMD&#xff09;&#xff0c;然后输入以下命令来查看 APK 的详…

【Mac版】Linux 入门命令行快捷键+联想记忆

Linux Mac 用户终端命令行快捷键 符号速查全解作为一个刚接触 Linux 和终端的 macOS 用户&#xff0c;常常被命令行的各种快捷键和符号弄得头晕脑胀&#xff0c;本文将带你系统地掌握命令行中最常用的快捷键和符号&#xff0c;并通过逻辑联想帮助你轻松记住每一个组合。一、基…

AUTOSAR Mcal Dio - 模块介绍 + EB配置工具介绍

文章目录1. 模块简介2. 主要功能3. 缩略语4. API接口5. 功能介绍5.1. ChannelGroup5.2. Dio_MaskedWritePort6. 序列图6.1.读GPIO电平6.2. 设置GPIO电平7. EB 工具配置7.1.General7.2.DioPort8. 参考资料1. 模块简介 Dio&#xff0c;全称“Digital Input Output”。Dio模块&am…

ICT模拟零件测试方法--晶体管测试

ICT模拟零件测试方法–晶体管测试 文章目录ICT模拟零件测试方法--晶体管测试晶体管测试晶体管测试配置晶体管测试配置晶体管测量选项晶体管测试 i3070 在线测试软件为每个晶体管提供两种测试&#xff1a; 使用二极管测试对晶体管的两个 PN 结进行测试。这是检查设备存在的快速…

AI算法实现解析-C++实例

基于C++实现的AI 以下是基于C++实现的AI/机器学习相关示例,涵盖基础算法、计算机视觉、自然语言处理等领域,适合不同阶段的学习者参考: 基础机器学习算法 线性回归 使用梯度下降法预测连续值,核心公式: 损失函数: 逻辑回归 二分类问题实现,Sigmoid函数: K-Means…