“共享社区”场景下Flutter与HarmonyOS APP双端打包与发布策略
本文探讨了"共享社区"应用中Flutter与HarmonyOS双端打包与发布的完整解决方案。文章从架构设计入手,提出了包含发布管理平台、持续集成流水线和多渠道分发系统的三层架构。详细介绍了自动化构建流程的时间线管理,包括代码提交、构建测试、质量验证和发布部署等关键阶段。在版本策略方面,设计了双端版本同步机制和兼容性矩阵,确保版本一致性。针对Flutter模块,阐述了多环境配置管
·
摘要
本文深入探讨在“共享社区”应用场景下,如何设计并实施高效的Flutter与HarmonyOS双端打包与发布策略。文章涵盖架构设计、自动化构建、版本管理、多渠道分发、监控分析等核心环节,为企业级混合应用的全生命周期管理提供完整解决方案。
如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信或邮件中提出,非常感谢您的支持。🙏
嘻嘻嘻,关注我!!!黑马波哥
也可以关注我的抖音号: 黑马程序员burger(50696424331) 在直播间交流(18:00-20:00)
一、整体架构与发布流程设计
1.1 双端发布架构概览
┌─────────────────────────────────────────────────────────┐
│ 发布管理平台 (Release Portal) │
├─────────────────────────────────────────────────────────┤
│ 版本管理 │ 渠道管理 │ 灰度发布 │ A/B测试 │ 数据监控 │ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 持续集成流水线 (CI/CD Pipeline) │
├─────────────────┬─────────────────┬─────────────────────┤
│ Flutter构建层 │ HarmonyOS构建层 │ 混合产物组装层 │
│ ┌───────────┐ │ ┌────────────┐ │ ┌──────────────┐ │
│ │ Dart编译 │ │ │ ArkUI编译 │ │ │ 资源合并 │ │
│ │ AOT优化 │ │ │ 打包签名 │ │ │ 配置注入 │ │
│ │ 代码混淆 │ │ │ 证书管理 │ │ │ 版本对齐 │ │
│ └───────────┘ │ └────────────┘ │ └──────────────┘ │
└─────────────────┴─────────────────┴─────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ 多渠道发布系统 (Distribution) │
├──────────────┬──────────────┬────────────┬─────────────┤
│ 应用商店渠道 │ 企业内部分发 │ 测试渠道 │ OTA热更新 │
│ ┌──────────┐ │ ┌──────────┐ │ ┌────────┐ │ ┌─────────┐│
│ │ 华为市场 │ │ │ 自建平台 │ │ │ TestFlight │ │ 动态补丁││
│ │ 小米商店 │ │ │ MDM系统 │ │ │ 蒲公英 │ │ │ CodePush││
│ │ App Store│ │ │ ... │ │ │ ... │ │ │ ... ││
│ └──────────┘ │ └──────────┘ │ └────────┘ │ └─────────┘│
└──────────────┴──────────────┴────────────┴─────────────┘
1.2 发布流程时间线
1.3 版本策略设计
// lib/core/config/version_strategy.dart
class VersionStrategy {
// 版本号规范:主版本.次版本.修订版本-构建号_平台标识
// 示例:2.5.1+20240501.1800_harmony
static const String VERSION_PATTERN = r'^(\d+)\.(\d+)\.(\d+)(?:\+([\w\.]+))?(?:_(\w+))?$';
// 双端版本同步策略
static VersionSyncStrategy syncStrategy = VersionSyncStrategy(
majorVersionSync: true, // 主版本号必须同步
minorVersionSync: true, // 次版本号推荐同步
buildNumberFormat: BuildNumberFormat.timestamp, // 构建号使用时间戳
platformSuffix: true, // 添加平台后缀
);
// 版本兼容性矩阵
static final Map<String, List<String>> compatibilityMatrix = {
'flutter': {
'3.13.0': ['harmony_4.0.0+'],
'3.12.0': ['harmony_3.2.0+', 'harmony_4.0.0'],
'3.10.0': ['harmony_3.0.0+'],
},
'harmony': {
'4.0.0': ['flutter_3.13.0+'],
'3.2.0': ['flutter_3.10.0+'],
'3.0.0': ['flutter_3.8.0+'],
},
};
// 生成双端版本号
static AppVersion generateDualVersion({
required int major,
required int minor,
required int patch,
String? buildNumber,
bool forHarmony = false,
}) {
final now = DateTime.now();
final build = buildNumber ?? '${now.year}${now.month.toString().padLeft(2, '0')}${now.day.toString().padLeft(2, '0')}.${now.hour.toString().padLeft(2, '0')}${now.minute.toString().padLeft(2, '0')}';
final platformSuffix = forHarmony ? '_harmony' : '_flutter';
return AppVersion(
versionString: '$major.$minor.$patch+$build$platformSuffix',
major: major,
minor: minor,
patch: patch,
buildNumber: build,
platform: forHarmony ? 'harmony' : 'flutter',
timestamp: now,
);
}
}
二、Flutter模块打包策略
2.1 多环境配置管理
# pubspec.yaml - 环境配置注入
name: xiangjia_shared_community
description: 共享社区应用
version: 2.5.1+20240501.1800
environment:
sdk: '>=3.0.0 <4.0.0'
# 环境变量配置
flutter:
assets:
- config/app_config.yaml
- config/app_config_dev.yaml
- config/app_config_staging.yaml
- config/app_config_prod.yaml
# 构建配置
flutter_intl:
enabled: true
class_name: AppLocalizations
arb_dir: lib/l10n
output_dir: lib/generated/l10n
# 平台特定配置
flutter:
uses-material-design: true
# HarmonyOS特定配置
harmony:
enable: true
minAPIVersion: 9
targetAPIVersion: 11
distributedCapabilities:
- deviceDiscovery
- dataSync
- serviceSharing
// lib/core/config/environment.dart
class BuildEnvironment {
static const String _envKey = 'APP_ENVIRONMENT';
static AppEnvironment get current {
const env = String.fromEnvironment(
_envKey,
defaultValue: 'development',
);
switch (env) {
case 'production':
return AppEnvironment.production;
case 'staging':
return AppEnvironment.staging;
case 'harmony':
return AppEnvironment.harmony;
default:
return AppEnvironment.development;
}
}
static String get configFile {
switch (current) {
case AppEnvironment.production:
return 'config/app_config_prod.yaml';
case AppEnvironment.staging:
return 'config/app_config_staging.yaml';
case AppEnvironment.harmony:
return 'config/app_config_harmony.yaml';
default:
return 'config/app_config_dev.yaml';
}
}
}
// 环境特定的应用配置
class AppConfig {
final String apiEndpoint;
final String socketEndpoint;
final String cdnBaseUrl;
final Map<String, dynamic> features;
final AnalyticsConfig analytics;
final SecurityConfig security;
factory AppConfig.fromEnvironment() {
final configFile = BuildEnvironment.configFile;
final yamlString = rootBundle.loadString(configFile);
final yamlMap = loadYaml(yamlString) as Map;
return AppConfig._fromMap(yamlMap);
}
}
2.2 Flutter构建脚本
#!/bin/bash
# scripts/build_flutter.sh
set -e
echo "🚀 Flutter模块构建开始..."
# 参数解析
ENV=${1:-development}
PLATFORM=${2:-all}
BUILD_MODE=${3:-debug}
OUTPUT_DIR=${4:-build/flutter}
# 环境检查
if ! command -v flutter &> /dev/null; then
echo "❌ Flutter未安装"
exit 1
fi
# 清理
echo "🧹 清理构建缓存..."
flutter clean
# 获取依赖
echo "📦 获取依赖..."
flutter pub get
# 生成代码
echo "🔧 生成代码..."
flutter pub run build_runner build --delete-conflicting-outputs
# 构建参数
BUILD_ARGS=""
case "$BUILD_MODE" in
"release")
BUILD_ARGS="--release --split-debug-info --obfuscate"
;;
"profile")
BUILD_ARGS="--profile"
;;
*)
BUILD_ARGS="--debug"
;;
esac
# 平台构建
case "$PLATFORM" in
"android")
echo "🤖 构建Android平台..."
flutter build apk \
$BUILD_ARGS \
--dart-define=APP_ENVIRONMENT=$ENV \
--target-platform android-arm64 \
--split-per-abi \
--output="$OUTPUT_DIR/android"
;;
"ios")
echo "🍎 构建iOS平台..."
flutter build ipa \
$BUILD_ARGS \
--dart-define=APP_ENVIRONMENT=$ENV \
--export-options-plist=ios/ExportOptions.plist \
--output="$OUTPUT_DIR/ios"
;;
"harmony")
echo "🌉 构建HarmonyOS平台..."
flutter build harmony \
$BUILD_ARGS \
--dart-define=APP_ENVIRONMENT=harmony \
--target-platform harmony-arm64 \
--output="$OUTPUT_DIR/harmony"
;;
"aot")
echo "⚡ 构建AOT产物..."
flutter build aot \
$BUILD_ARGS \
--dart-define=APP_ENVIRONMENT=$ENV \
--output="$OUTPUT_DIR/aot"
;;
"all")
echo "🌍 构建全平台..."
./scripts/build_flutter.sh $ENV android $BUILD_MODE $OUTPUT_DIR
./scripts/build_flutter.sh $ENV ios $BUILD_MODE $OUTPUT_DIR
./scripts/build_flutter.sh $ENV harmony $BUILD_MODE $OUTPUT_DIR
;;
*)
echo "❌ 未知平台: $PLATFORM"
exit 1
;;
esac
# 生成构建报告
echo "📊 生成构建报告..."
dart scripts/generate_build_report.dart \
--env $ENV \
--platform $PLATFORM \
--mode $BUILD_MODE \
--output $OUTPUT_DIR/report.json
echo "✅ Flutter构建完成!输出目录: $OUTPUT_DIR"
2.3 代码混淆与优化
# android/app/proguard-rules.pro
# Flutter混淆规则
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class com.xiaomi.push.** { *; }
# 项目特定保留
-keep class com.xiangjia.sharedcommunity.** { *; }
-keep class * extends com.xiangjia.sharedcommunity.BaseModel { *; }
-keep class * implements com.xiangjia.sharedcommunity.Repository { *; }
# HarmonyOS混淆规则
-keep class ohos.** { *; }
-keep class com.huawei.** { *; }
-keep class * implements ohos.app.Ability { *; }
# 资源保留
-keepclassmembers class **.R$* {
public static <fields>;
}
// lib/core/optimization/obfuscation.dart
class CodeObfuscation {
static Future<void> applyObfuscation({
required String buildMode,
required String platform,
}) async {
if (buildMode != 'release') return;
final mappingFile = 'obfuscation/${platform}_mapping.txt';
// 应用混淆规则
await _applyProguardRules(platform);
// 生成混淆映射
await _generateObfuscationMapping(mappingFile);
// 上传映射文件到服务器(用于崩溃分析)
if (platform == 'android' || platform == 'harmony') {
await _uploadMappingFile(mappingFile);
}
}
static Future<void> _uploadMappingFile(String filePath) async {
final file = File(filePath);
if (!await file.exists()) return;
final sentry = SentryClient(SentryOptions(
dsn: AppConfig.current.analytics.sentryDsn,
));
await sentry.uploadProguardMapping(
file: file,
version: BuildEnvironment.versionString,
);
}
}
三、HarmonyOS模块打包策略
3.1 HarmonyOS工程配置
{
"app": {
"bundleName": "com.xiangjia.sharedcommunity",
"vendor": "xiangjia",
"versionCode": 202405011800,
"versionName": "2.5.1.20240501_harmony",
"minAPIVersion": 9,
"targetAPIVersion": 11,
"apiReleaseType": "Release",
"compileSdkVersion": "4.0.0.1",
"compileSdkType": "HarmonyOS"
},
"deviceConfig": {
"default": {
"network": {
"cleartextTraffic": true
}
},
"phone": {
"minAPIVersion": 9
},
"tablet": {
"minAPIVersion": 9
}
},
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": ["phone", "tablet"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"actions": ["action.system.home"],
"entities": ["entity.system.home"]
}
],
"distributedNotificationEnabled": true
}
],
"distributedCapabilities": [
{
"name": "ohos.distributed.deviceManager"
},
{
"name": "ohos.distributed.data.sync"
},
{
"name": "ohos.distributed.service.sharing"
}
]
}
}
3.2 HarmonyOS构建脚本
#!/bin/bash
# scripts/build_harmony.sh
set -e
echo "🚀 HarmonyOS模块构建开始..."
# 参数
ENV=${1:-harmony}
BUILD_TYPE=${2:-release}
MODULE_NAME=${3:-entry}
OUTPUT_DIR=${4:-build/harmony}
# 检查环境
if [ ! -d "$HARMONY_SDK_PATH" ]; then
echo "❌ HarmonyOS SDK路径未设置"
exit 1
fi
# 清理
echo "🧹 清理构建缓存..."
rm -rf "$OUTPUT_DIR"/*
rm -rf "$MODULE_NAME/build"
# 资源准备
echo "📁 准备Flutter资源..."
if [ -d "../flutter/build/harmony" ]; then
cp -r ../flutter/build/harmony/* "$MODULE_NAME/src/main/resources/rawfile/"
fi
# 注入环境变量
echo "🔧 注入环境配置..."
ENV_FILE="$MODULE_NAME/src/main/resources/rawfile/app_config.json"
cat > "$ENV_FILE" << EOF
{
"environment": "$ENV",
"buildTime": "$(date '+%Y-%m-%d %H:%M:%S')",
"version": "$(cat ../version.txt)",
"flutterVersion": "$(flutter --version | grep -o 'Flutter [0-9.]*')"
}
EOF
# 构建HAP
echo "🏗️ 构建HAP文件..."
cd "$MODULE_NAME"
# 调试模式
if [ "$BUILD_TYPE" = "debug" ]; then
./gradlew assembleDebug
HAP_FILE="build/outputs/hap/debug/${MODULE_NAME}-debug.hap"
else
# 发布模式
./gradlew assembleRelease
# 代码签名
echo "🔐 代码签名..."
java -jar "$HARMONY_SDK_PATH/toolchains/hap-sign-tool.jar" \
-keyAlias "xiangjia" \
-keystore "../keystore/harmony.jks" \
-keystorePwd "$HARMONY_KEYSTORE_PASSWORD" \
-inFile "build/outputs/hap/release/${MODULE_NAME}-release-unsigned.hap" \
-outFile "build/outputs/hap/release/${MODULE_NAME}-release-signed.hap"
HAP_FILE="build/outputs/hap/release/${MODULE_NAME}-release-signed.hap"
fi
# 复制到输出目录
echo "📦 复制产物..."
mkdir -p "../../$OUTPUT_DIR"
cp "$HAP_FILE" "../../$OUTPUT_DIR/app.hap"
# 生成App Pack(如果需要)
if [ "$BUILD_TYPE" = "release" ]; then
echo "📱 生成App Pack..."
java -jar "$HARMONY_SDK_PATH/toolchains/app-pack-tool.jar" \
--mode "hap" \
--json "config.json" \
--out-dir "../../$OUTPUT_DIR" \
--force
APP_PACK="../../$OUTPUT_DIR/app-pack.app"
fi
# 生成构建信息
echo "📝 生成构建信息..."
cd ../..
cat > "$OUTPUT_DIR/build_info.json" << EOF
{
"buildType": "$BUILD_TYPE",
"environment": "$ENV",
"timestamp": "$(date -Iseconds)",
"hapSize": "$(stat -f%z "$OUTPUT_DIR/app.hap" 2>/dev/null || stat -c%s "$OUTPUT_DIR/app.hap")",
"hash": "$(shasum -a 256 "$OUTPUT_DIR/app.hap" | cut -d' ' -f1)",
"module": "$MODULE_NAME"
}
EOF
echo "✅ HarmonyOS构建完成!"
echo "📁 HAP文件: $OUTPUT_DIR/app.hap"
if [ -n "$APP_PACK" ]; then
echo "📦 App Pack: $APP_PACK"
fi
3.3 HarmonyOS签名管理
#!/bin/bash
# scripts/manage_harmony_certs.sh
# HarmonyOS证书管理脚本
KEYSTORE_DIR="./keystore"
CONFIG_FILE="$KEYSTORE_DIR/cert_config.json"
# 初始化证书配置
init_cert_config() {
if [ ! -f "$CONFIG_FILE" ]; then
cat > "$CONFIG_FILE" << EOF
{
"harmony": {
"keystore": "harmony.jks",
"alias": "xiangjia",
"validity": 36500,
"password": "changeit",
"distinguishedName": "CN=xiangjia, OU=tech, O=xiangjia, L=beijing, ST=beijing, C=CN"
},
"huawei": {
"agconnect": "agconnect-services.json",
"signing_cert": "huawei.cer"
}
}
EOF
fi
}
# 生成HarmonyOS证书
generate_harmony_cert() {
local alias_name=${1:-"xiangjia"}
local password=${2:-"changeit"}
local validity=${3:-36500}
echo "🔐 生成HarmonyOS证书..."
mkdir -p "$KEYSTORE_DIR"
# 生成JKS
keytool -genkeypair \
-alias "$alias_name" \
-keyalg RSA \
-keysize 2048 \
-validity "$validity" \
-keystore "$KEYSTORE_DIR/harmony.jks" \
-storepass "$password" \
-keypass "$password" \
-dname "CN=xiangjia, OU=tech, O=xiangjia, L=beijing, ST=beijing, C=CN"
# 导出证书
keytool -exportcert \
-alias "$alias_name" \
-keystore "$KEYSTORE_DIR/harmony.jks" \
-storepass "$password" \
-file "$KEYSTORE_DIR/harmony.cer"
# 生成CSR
keytool -certreq \
-alias "$alias_name" \
-keystore "$KEYSTORE_DIR/harmony.jks" \
-storepass "$password" \
-file "$KEYSTORE_DIR/harmony.csr"
echo "✅ 证书已生成到 $KEYSTORE_DIR/"
echo "🔑 Keystore: harmony.jks"
echo "📄 证书: harmony.cer"
echo "📝 CSR: harmony.csr"
}
# 华为AGC证书配置
setup_huawei_agc() {
if [ ! -f "$KEYSTORE_DIR/agconnect-services.json" ]; then
echo "请从华为AGC控制台下载 agconnect-services.json 并放置到 $KEYSTORE_DIR/"
exit 1
fi
# 配置华为签名证书
if [ ! -f "$KEYSTORE_DIR/huawei.cer" ]; then
echo "请从华为开发者平台下载签名证书并放置到 $KEYSTORE_DIR/huawei.cer"
exit 1
fi
# 复制到项目目录
cp "$KEYSTORE_DIR/agconnect-services.json" "./entry/"
echo "✅ 华为AGC配置完成"
}
# 验证证书
verify_certificates() {
echo "🔍 验证证书..."
# 验证HarmonyOS证书
if [ -f "$KEYSTORE_DIR/harmony.jks" ]; then
keytool -list -v \
-keystore "$KEYSTORE_DIR/harmony.jks" \
-storepass "$(jq -r '.harmony.password' "$CONFIG_FILE")" \
| grep -E "(别名|创建日期|有效期)"
else
echo "❌ HarmonyOS证书不存在"
fi
# 验证华为证书
if [ -f "$KEYSTORE_DIR/agconnect-services.json" ]; then
echo "✅ 华为AGC配置文件存在"
fi
}
# 主函数
main() {
case "$1" in
"init")
init_cert_config
;;
"generate")
generate_harmony_cert "$2" "$3" "$4"
;;
"setup-huawei")
setup_huawei_agc
;;
"verify")
verify_certificates
;;
*)
echo "用法: $0 {init|generate|setup-huawei|verify}"
exit 1
;;
esac
}
main "$@"
四、混合产物组装与集成
4.1 产物组装策略
# scripts/assemble_hybrid.py
#!/usr/bin/env python3
"""
混合产物组装脚本
将Flutter产物和HarmonyOS原生模块组合成最终应用
"""
import json
import shutil
import hashlib
import zipfile
from pathlib import Path
from datetime import datetime
class HybridAssembler:
def __init__(self, config_path="config/assembly_config.json"):
with open(config_path, 'r', encoding='utf-8') as f:
self.config = json.load(f)
self.timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
self.output_dir = Path(self.config["output_dir"]) / self.timestamp
def assemble_for_platform(self, platform, env):
"""为指定平台组装混合产物"""
print(f"🔧 开始组装 {platform} {env} 版本...")
# 1. 创建输出目录
platform_dir = self.output_dir / platform / env
platform_dir.mkdir(parents=True, exist_ok=True)
# 2. 收集Flutter产物
flutter_artifacts = self._collect_flutter_artifacts(platform, env)
# 3. 收集原生产物
native_artifacts = self._collect_native_artifacts(platform, env)
# 4. 合并配置文件
merged_config = self._merge_configs(flutter_artifacts, native_artifacts)
# 5. 生成最终包
final_package = self._create_final_package(
platform,
env,
flutter_artifacts,
native_artifacts,
merged_config
)
# 6. 生成构建报告
self._generate_build_report(platform, env, final_package)
print(f"✅ {platform} {env} 版本组装完成: {final_package}")
return final_package
def _collect_flutter_artifacts(self, platform, env):
"""收集Flutter构建产物"""
artifacts = {}
# Flutter构建输出目录
flutter_build_dir = Path(f"build/flutter/{platform}/{env}")
if not flutter_build_dir.exists():
raise FileNotFoundError(f"Flutter构建产物不存在: {flutter_build_dir}")
# 收集主要文件
if platform == "android":
artifacts["app"] = list(flutter_build_dir.glob("*.apk"))
artifacts["aab"] = list(flutter_build_dir.glob("*.aab"))
elif platform == "ios":
artifacts["ipa"] = list(flutter_build_dir.glob("*.ipa"))
artifacts["app"] = list(flutter_build_dir.glob("*.app"))
elif platform == "harmony":
artifacts["hap"] = list(flutter_build_dir.glob("*.hap"))
# 收集资源文件
resources_dir = flutter_build_dir / "resources"
if resources_dir.exists():
artifacts["resources"] = list(resources_dir.rglob("*"))
# 收集映射文件(用于崩溃分析)
mapping_files = list(flutter_build_dir.glob("**/mapping.txt"))
artifacts["mapping"] = mapping_files
return artifacts
def _collect_native_artifacts(self, platform, env):
"""收集原生模块产物"""
artifacts = {}
# HarmonyOS原生模块
if platform == "harmony":
harmony_build_dir = Path(f"build/harmony/{env}")
if harmony_build_dir.exists():
artifacts["hap"] = list(harmony_build_dir.glob("*.hap"))
artifacts["app_pack"] = list(harmony_build_dir.glob("*.app"))
# Android原生模块
elif platform == "android":
android_native_dir = Path("android/build/outputs")
if android_native_dir.exists():
artifacts["aar"] = list(android_native_dir.rglob("*.aar"))
return artifacts
def _merge_configs(self, flutter_artifacts, native_artifacts):
"""合并双端配置文件"""
merged_config = {
"version": self._read_version(),
"build_time": self.timestamp,
"environment": self.config.get("environment", "production"),
"features": self.config.get("features", {}),
"dependencies": self._analyze_dependencies(),
}
# 添加平台特定配置
if native_artifacts.get("hap"):
merged_config["harmony"] = {
"distributed_capabilities": self.config["harmony"]["distributed_capabilities"],
"min_api_version": self.config["harmony"]["min_api_version"],
}
return merged_config
def _create_final_package(self, platform, env, flutter_artifacts, native_artifacts, config):
"""创建最终发布包"""
if platform == "harmony":
return self._create_harmony_package(flutter_artifacts, native_artifacts, config)
elif platform == "android":
return self._create_android_package(flutter_artifacts, native_artifacts, config)
elif platform == "ios":
return self._create_ios_package(flutter_artifacts, native_artifacts, config)
def _create_harmony_package(self, flutter_artifacts, native_artifacts, config):
"""创建HarmonyOS混合包"""
package_dir = self.output_dir / "harmony" / "package"
package_dir.mkdir(parents=True, exist_ok=True)
# 1. 创建HAP包结构
hap_dir = package_dir / "hap"
hap_dir.mkdir(exist_ok=True)
# 2. 复制Flutter HAP
if flutter_artifacts.get("hap"):
for hap_file in flutter_artifacts["hap"]:
shutil.copy2(hap_file, hap_dir / hap_file.name)
# 3. 复制原生HAP
if native_artifacts.get("hap"):
for hap_file in native_artifacts["hap"]:
shutil.copy2(hap_file, hap_dir / hap_file.name)
# 4. 创建pack.info
pack_info = {
"app": {
"bundleName": "com.xiangjia.sharedcommunity",
"version": config["version"],
"components": [
{
"name": "entry",
"type": "entry",
"hap": [f.name for f in hap_dir.glob("*.hap")]
}
]
}
}
with open(package_dir / "pack.info", 'w', encoding='utf-8') as f:
json.dump(pack_info, f, indent=2, ensure_ascii=False)
# 5. 创建ZIP包
package_file = self.output_dir / f"xiangjia_harmony_{self.timestamp}.zip"
with zipfile.ZipFile(package_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
for file in package_dir.rglob("*"):
if file.is_file():
arcname = file.relative_to(package_dir)
zipf.write(file, arcname)
return package_file
def _generate_build_report(self, platform, env, final_package):
"""生成构建报告"""
report = {
"platform": platform,
"environment": env,
"build_time": self.timestamp,
"package_path": str(final_package),
"package_size": final_package.stat().st_size,
"package_hash": self._calculate_file_hash(final_package),
"config": self.config,
}
report_file = self.output_dir / "build_report.json"
with open(report_file, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
return report_file
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="混合产物组装工具")
parser.add_argument("--platform", required=True, choices=["android", "ios", "harmony"])
parser.add_argument("--env", default="production", choices=["dev", "staging", "production"])
args = parser.parse_args()
assembler = HybridAssembler()
assembler.assemble_for_platform(args.platform, args.env)
4.2 版本对齐与校验
// scripts/version_validator.dart
import 'dart:convert';
import 'dart:io';
import 'package:yaml/yaml.dart';
class VersionValidator {
/// 验证双端版本一致性
static Future<bool> validateDualVersion() async {
print('🔍 开始验证双端版本一致性...');
// 读取Flutter版本
final flutterVersion = await _readFlutterVersion();
// 读取HarmonyOS版本
final harmonyVersion = await _readHarmonyVersion();
// 比较版本
final isCompatible = _compareVersions(flutterVersion, harmonyVersion);
if (!isCompatible) {
print('❌ 版本不兼容:');
print(' Flutter: ${flutterVersion.versionString}');
print(' HarmonyOS: ${harmonyVersion.versionString}');
// 生成兼容性报告
await _generateCompatibilityReport(flutterVersion, harmonyVersion);
return false;
}
print('✅ 双端版本兼容性验证通过');
print(' Flutter: ${flutterVersion.versionString}');
print(' HarmonyOS: ${harmonyVersion.versionString}');
return true;
}
static Future<AppVersion> _readFlutterVersion() async {
final pubspec = File('pubspec.yaml');
final content = await pubspec.readAsString();
final yaml = loadYaml(content);
return AppVersion(
versionString: yaml['version'],
platform: 'flutter',
);
}
static Future<AppVersion> _readHarmonyVersion() async {
final configFile = File('entry/build.gradle');
final content = await configFile.readAsString();
// 解析HarmonyOS版本
final versionMatch = RegExp(r'versionName\s+"([^"]+)"').firstMatch(content);
final codeMatch = RegExp(r'versionCode\s+(\d+)').firstMatch(content);
return AppVersion(
versionString: versionMatch?.group(1) ?? 'unknown',
buildNumber: codeMatch?.group(1),
platform: 'harmony',
);
}
static bool _compareVersions(AppVersion flutter, AppVersion harmony) {
// 主版本号必须一致
if (flutter.major != harmony.major) {
return false;
}
// 次版本号推荐一致,但允许差异
if (flutter.minor != harmony.minor) {
print('⚠️ 警告: 次版本号不一致');
}
// 检查构建时间戳(如果存在)
if (flutter.buildTimestamp != null && harmony.buildTimestamp != null) {
final timeDiff = (flutter.buildTimestamp! - harmony.buildTimestamp!).abs();
if (timeDiff > Duration(hours: 24)) {
print('⚠️ 警告: 构建时间差异超过24小时');
}
}
return true;
}
}
void main(List<String> args) async {
final isValid = await VersionValidator.validateDualVersion();
if (!isValid) {
exitCode = 1;
}
}
五、自动化CI/CD流水线
5.1 GitHub Actions配置
# .github/workflows/ci-cd.yml
name: 共享社区CI/CD流水线
on:
push:
branches: [ main, develop, release/* ]
paths:
- 'lib/**'
- 'pubspec.yaml'
- 'android/**'
- 'ios/**'
- 'harmony/**'
- '.github/workflows/**'
pull_request:
branches: [ main ]
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- development
- staging
- production
- harmony
platform:
description: '构建平台'
required: true
default: 'all'
type: choice
options:
- all
- android
- ios
- harmony
env:
PROJECT_NAME: 'xiangjia-shared-community'
FLUTTER_VERSION: '3.13.x'
jobs:
code-quality:
name: 代码质量检查
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 设置Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: 代码格式检查
run: |
flutter format --set-exit-if-changed lib/
dart format --set-exit-if-changed lib/
- name: 静态分析
run: |
flutter analyze lib/
dart analyze lib/
- name: 运行测试
run: |
flutter test --coverage
- name: 上传覆盖率
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
build-flutter:
name: 构建Flutter模块
runs-on: ubuntu-latest
needs: code-quality
strategy:
matrix:
platform: [android, ios, harmony]
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 设置Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: 构建 ${{ matrix.platform }}
run: |
chmod +x scripts/build_flutter.sh
./scripts/build_flutter.sh ${{ github.event.inputs.environment || 'staging' }} ${{ matrix.platform }} release
- name: 上传构建产物
uses: actions/upload-artifact@v3
with:
name: flutter-${{ matrix.platform }}
path: build/flutter/${{ matrix.platform }}/*
retention-days: 7
build-harmony:
name: 构建HarmonyOS原生模块
runs-on: ubuntu-latest
needs: build-flutter
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 设置HarmonyOS环境
run: |
./scripts/setup_harmony_ci.sh
- name: 下载Flutter产物
uses: actions/download-artifact@v3
with:
path: flutter-artifacts
- name: 构建HarmonyOS
run: |
chmod +x scripts/build_harmony.sh
./scripts/build_harmony.sh ${{ github.event.inputs.environment || 'harmony' }} release
- name: 上传HarmonyOS产物
uses: actions/upload-artifact@v3
with:
name: harmony-native
path: build/harmony/*
retention-days: 7
assemble-hybrid:
name: 组装混合产物
runs-on: ubuntu-latest
needs: [build-flutter, build-harmony]
steps:
- name: 检出代码
uses: actions/checkout@v3
- name: 下载所有产物
run: |
mkdir -p build
# 下载Flutter产物
gh run download ${{ github.run_id }} -n flutter-*
# 下载HarmonyOS产物
gh run download ${{ github.run_id }} -n harmony-native
- name: 组装混合包
run: |
python3 scripts/assemble_hybrid.py \
--platform harmony \
--env ${{ github.event.inputs.environment || 'staging' }}
- name: 上传最终包
uses: actions/upload-artifact@v3
with:
name: hybrid-package
path: build/hybrid/*
retention-days: 30
deploy:
name: 部署发布
runs-on: ubuntu-latest
needs: assemble-hybrid
if: github.event_name == 'push' && contains(github.ref, 'refs/heads/main')
steps:
- name: 下载最终包
uses: actions/download-artifact@v3
with:
name: hybrid-package
- name: 发布到测试环境
run: |
./scripts/deploy_to_fir.sh
- name: 发布到华为应用市场
if: contains(github.event.inputs.platform, 'harmony') || github.event.inputs.platform == 'all'
run: |
./scripts/publish_to_huawei_appgallery.sh
env:
HUAWEI_CLIENT_ID: ${{ secrets.HUAWEI_CLIENT_ID }}
HUAWEI_CLIENT_SECRET: ${{ secrets.HUAWEI_CLIENT_SECRET }}
- name: 发布到Google Play
if: contains(github.event.inputs.platform, 'android') || github.event.inputs.platform == 'all'
run: |
./scripts/publish_to_google_play.sh
- name: 发送通知
run: |
./scripts/send_deployment_notification.sh
5.2 环境配置脚本
#!/bin/bash
# scripts/setup_harmony_ci.sh
echo "🔧 设置HarmonyOS CI环境..."
# 安装HarmonyOS SDK
HARMONY_SDK_VERSION="4.0.0.1"
HARMONY_SDK_URL="https://repo.huaweicloud.com/harmonyos/sdk/openharmony-sdk-${HARMONY_SDK_VERSION}-linux.tar.gz"
echo "📥 下载HarmonyOS SDK..."
wget -q $HARMONY_SDK_URL -O harmony-sdk.tar.gz
echo "📂 解压SDK..."
tar -xzf harmony-sdk.tar.gz -C /opt
rm harmony-sdk.tar.gz
# 设置环境变量
echo "📝 设置环境变量..."
export HARMONY_SDK_PATH="/opt/openharmony/sdk"
export PATH="$HARMONY_SDK_PATH/toolchains:$PATH"
# 安装Node.js(如果需要)
if ! command -v node &> /dev/null; then
echo "📦 安装Node.js..."
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
fi
# 安装Java(如果需要)
if ! command -v java &> /dev/null; then
echo "☕ 安装Java..."
sudo apt-get install -y openjdk-11-jdk
fi
# 验证安装
echo "🔍 验证安装..."
java -version
node --version
if [ -d "$HARMONY_SDK_PATH" ]; then
echo "✅ HarmonyOS SDK安装成功: $HARMONY_SDK_PATH"
else
echo "❌ HarmonyOS SDK安装失败"
exit 1
fi
echo "🎉 HarmonyOS CI环境设置完成!"
六、多渠道分发策略
6.1 渠道配置管理
// lib/core/distribution/channel_manager.dart
class DistributionChannel {
final String id;
final String name;
final ChannelType type;
final Map<String, dynamic> config;
final List<String> supportedPlatforms;
// 渠道优先级(数值越小优先级越高)
final int priority;
// 渠道特性
final bool supportsOTA;
final bool supportsAAB;
final bool supportsDynamicFeatures;
// 发布配置
final ReleaseConfig releaseConfig;
DistributionChannel({
required this.id,
required this.name,
required this.type,
required this.config,
required this.supportedPlatforms,
this.priority = 100,
this.supportsOTA = false,
this.supportsAAB = false,
this.supportsDynamicFeatures = false,
required this.releaseConfig,
});
// 获取渠道特定的配置
AppConfig getChannelConfig(AppConfig baseConfig) {
return baseConfig.copyWith(
analytics: baseConfig.analytics.copyWith(
enabled: config['analytics_enabled'] ?? true,
channelId: id,
channelName: name,
),
features: _mergeFeatures(baseConfig.features, config['features']),
);
}
// 检查是否支持特定平台
bool supportsPlatform(String platform) {
return supportedPlatforms.contains(platform);
}
// 生成渠道标识
String get channelIdentifier {
return '${id}_${type.name}_${DateTime.now().millisecondsSinceEpoch}';
}
}
class ChannelManager {
static final ChannelManager _instance = ChannelManager._internal();
factory ChannelManager() => _instance;
final Map<String, DistributionChannel> _channels = {};
final Map<String, List<DistributionChannel>> _platformChannels = {};
ChannelManager._internal() {
_initializeDefaultChannels();
}
void _initializeDefaultChannels() {
// 华为应用市场渠道
_registerChannel(DistributionChannel(
id: 'huawei_appgallery',
name: '华为应用市场',
type: ChannelType.appStore,
config: {
'store_id': 'huawei',
'review_enabled': true,
'analytics_enabled': true,
'features': {
'harmony_distributed': true,
'huawei_push': true,
'huawei_iap': true,
},
},
supportedPlatforms: ['harmony', 'android'],
priority: 10,
supportsOTA: true,
releaseConfig: HuaweiReleaseConfig(),
));
// 小米应用商店
_registerChannel(DistributionChannel(
id: 'xiaomi_appstore',
name: '小米应用商店',
type: ChannelType.appStore,
config: {
'store_id': 'xiaomi',
'review_enabled': true,
'analytics_enabled': true,
'features': {
'xiaomi_push': true,
'miui_optimization': true,
},
},
supportedPlatforms: ['android'],
priority: 20,
releaseConfig: XiaomiReleaseConfig(),
));
// 企业内部分发
_registerChannel(DistributionChannel(
id: 'enterprise_internal',
name: '企业内部分发',
type: ChannelType.enterprise,
config: {
'require_auth': true,
'analytics_enabled': true,
'features': {
'custom_sso': true,
'enterprise_features': true,
},
},
supportedPlatforms: ['android', 'harmony', 'ios'],
priority: 5,
supportsOTA: true,
releaseConfig: EnterpriseReleaseConfig(),
));
// 测试渠道
_registerChannel(DistributionChannel(
id: 'testflight',
name: 'TestFlight',
type: ChannelType.testing,
config: {
'max_testers': 10000,
'analytics_enabled': true,
'features': {
'beta_features': true,
'debug_menu': true,
},
},
supportedPlatforms: ['ios'],
priority: 15,
releaseConfig: TestFlightReleaseConfig(),
));
}
void _registerChannel(DistributionChannel channel) {
_channels[channel.id] = channel;
for (final platform in channel.supportedPlatforms) {
if (!_platformChannels.containsKey(platform)) {
_platformChannels[platform] = [];
}
_platformChannels[platform]!.add(channel);
}
}
// 为特定平台获取推荐渠道
List<DistributionChannel> getRecommendedChannels({
required String platform,
required AppEnvironment environment,
}) {
final allChannels = _platformChannels[platform] ?? [];
return allChannels
.where((channel) => _isChannelSuitable(channel, environment))
.sorted((a, b) => a.priority.compareTo(b.priority))
.toList();
}
bool _isChannelSuitable(DistributionChannel channel, AppEnvironment env) {
switch (env) {
case AppEnvironment.development:
return channel.type == ChannelType.testing;
case AppEnvironment.staging:
return channel.type == ChannelType.testing ||
channel.type == ChannelType.enterprise;
case AppEnvironment.production:
return channel.type == ChannelType.appStore;
case AppEnvironment.harmony:
return channel.supportsPlatform('harmony');
}
}
// 生成渠道包
Future<File> generateChannelPackage({
required String channelId,
required File basePackage,
required String platform,
}) async {
final channel = _channels[channelId];
if (channel == null) {
throw ArgumentError('Channel $channelId not found');
}
final outputDir = Directory('build/channels/$platform/$channelId');
if (outputDir.existsSync()) {
outputDir.deleteSync(recursive: true);
}
outputDir.createSync(recursive: true);
// 1. 复制基础包
final channelPackage = File('${outputDir.path}/app_${channel.channelIdentifier}${_getPackageExtension(platform)}');
await basePackage.copy(channelPackage.path);
// 2. 注入渠道配置
await _injectChannelConfig(channelPackage, channel);
// 3. 应用渠道特定的修改
await _applyChannelModifications(channelPackage, channel, platform);
// 4. 重新签名(如果需要)
if (channel.config['resign'] == true) {
await _resignPackage(channelPackage, channel, platform);
}
return channelPackage;
}
}
6.2 华为应用市场发布脚本
#!/bin/bash
# scripts/publish_to_huawei_appgallery.sh
set -e
echo "🚀 开始发布到华为应用市场..."
# 配置
APP_ID="12345678"
CLIENT_ID="$HUAWEI_CLIENT_ID"
CLIENT_SECRET="$HUAWEI_CLIENT_SECRET"
PACKAGE_PATH="build/hybrid/xiangjia_harmony_latest.hap"
RELEASE_TYPE="stage" # stage|review|production
# 检查参数
if [ -z "$CLIENT_ID" ] || [ -z "$CLIENT_SECRET" ]; then
echo "❌ 华为应用市场凭据未设置"
exit 1
fi
if [ ! -f "$PACKAGE_PATH" ]; then
echo "❌ 发布包不存在: $PACKAGE_PATH"
exit 1
fi
# 获取访问令牌
echo "🔐 获取访问令牌..."
TOKEN_RESPONSE=$(curl -s -X POST \
"https://oauth-login.cloud.huawei.com/oauth2/v3/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
echo "❌ 获取访问令牌失败"
echo "响应: $TOKEN_RESPONSE"
exit 1
fi
echo "✅ 访问令牌获取成功"
# 上传应用包
echo "📤 上传应用包..."
UPLOAD_RESPONSE=$(curl -s -X POST \
"https://connect-api.cloud.huawei.com/api/publish/v2/upload-url" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "client_id: $CLIENT_ID" \
-d '{
"type": 1,
"fileSuffix": "hap"
}')
UPLOAD_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.uploadUrl')
AUTH_CODE=$(echo "$UPLOAD_RESPONSE" | jq -r '.authCode')
if [ -z "$UPLOAD_URL" ] || [ "$UPLOAD_URL" = "null" ]; then
echo "❌ 获取上传URL失败"
echo "响应: $UPLOAD_RESPONSE"
exit 1
fi
# 实际上传文件
echo "📦 上传文件..."
curl -X PUT \
"$UPLOAD_URL" \
-H "content-type: application/octet-stream" \
--data-binary "@$PACKAGE_PATH"
# 更新应用信息
echo "📝 更新应用信息..."
UPDATE_RESPONSE=$(curl -s -X PUT \
"https://connect-api.cloud.huawei.com/api/publish/v2/app-file-info?appId=$APP_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "client_id: $CLIENT_ID" \
-H "Content-Type: application/json" \
-d "{
\"fileType\": 5,
\"files\": [{
\"fileName\": \"$(basename "$PACKAGE_PATH")\",
\"fileDestUrl\": \"$UPLOAD_URL\",
\"authCode\": \"$AUTH_CODE\"
}],
\"releaseType\": \"$RELEASE_TYPE\"
}")
echo "📊 上传响应: $UPDATE_RESPONSE"
# 提交审核
if [ "$RELEASE_TYPE" = "review" ]; then
echo "📋 提交审核..."
SUBMIT_RESPONSE=$(curl -s -X POST \
"https://connect-api.cloud.huawei.com/api/publish/v2/submit?appId=$APP_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "client_id: $CLIENT_ID")
echo "📄 审核提交响应: $SUBMIT_RESPONSE"
fi
echo "✅ 发布流程完成!"
echo "📱 应用包已上传到华为应用市场"
echo "🔗 管理控制台: https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/myApp"
七、监控与数据分析
7.1 发布监控面板
// lib/features/monitoring/release_monitor.dart
class ReleaseMonitor {
final AnalyticsService _analytics;
final CrashReportingService _crashReporting;
final PerformanceMonitor _performance;
// 发布指标
final Map<String, ReleaseMetrics> _releaseMetrics = {};
ReleaseMonitor({
required AnalyticsService analytics,
required CrashReportingService crashReporting,
required PerformanceMonitor performance,
}) : _analytics = analytics,
_crashReporting = crashReporting,
_performance = performance;
// 监控新发布
Future<void> monitorRelease({
required String releaseId,
required String version,
required String platform,
required List<String> channels,
DateTime? startTime,
}) async {
final metrics = ReleaseMetrics(
releaseId: releaseId,
version: version,
platform: platform,
channels: channels,
startTime: startTime ?? DateTime.now(),
);
_releaseMetrics[releaseId] = metrics;
// 开始收集指标
_startMetricsCollection(metrics);
// 设置自动报告
_setupAutoReporting(metrics);
}
void _startMetricsCollection(ReleaseMetrics metrics) {
// 收集安装数据
_analytics.trackEvent('release_install', {
'release_id': metrics.releaseId,
'version': metrics.version,
'platform': metrics.platform,
'channel': metrics.channels.join(','),
});
// 收集性能数据
_performance.startMonitoring({
'release_id': metrics.releaseId,
'metrics': ['startup_time', 'memory_usage', 'frame_rate'],
});
// 收集崩溃数据
_crashReporting.tagCrashesWithRelease(metrics.releaseId);
}
// 获取发布健康度
Future<ReleaseHealth> getReleaseHealth(String releaseId) async {
final metrics = _releaseMetrics[releaseId];
if (metrics == null) {
throw ArgumentError('Release not found: $releaseId');
}
final crashRate = await _crashReporting.getCrashRate(releaseId);
final performanceScore = await _performance.getPerformanceScore(releaseId);
final userFeedback = await _analytics.getUserFeedback(releaseId);
return ReleaseHealth(
releaseId: releaseId,
crashRate: crashRate,
performanceScore: performanceScore,
userFeedback: userFeedback,
stabilityScore: _calculateStabilityScore(crashRate, performanceScore),
recommendation: _generateRecommendation(crashRate, performanceScore),
);
}
// 生成发布报告
Future<ReleaseReport> generateReleaseReport({
required String releaseId,
required DateTime startDate,
required DateTime endDate,
}) async {
final metrics = _releaseMetrics[releaseId];
if (metrics == null) {
throw ArgumentError('Release not found: $releaseId');
}
final installations = await _analytics.getInstallations(
releaseId: releaseId,
startDate: startDate,
endDate: endDate,
);
final crashes = await _crashReporting.getCrashes(
releaseId: releaseId,
startDate: startDate,
endDate: endDate,
);
final performance = await _performance.getPerformanceData(
releaseId: releaseId,
startDate: startDate,
endDate: endDate,
);
return ReleaseReport(
releaseId: releaseId,
version: metrics.version,
platform: metrics.platform,
period: DateRange(startDate, endDate),
installations: installations,
crashes: crashes,
performance: performance,
summary: _generateSummary(installations, crashes, performance),
);
}
}
// 发布指标数据模型
class ReleaseMetrics {
final String releaseId;
final String version;
final String platform;
final List<String> channels;
final DateTime startTime;
int installations = 0;
int activeUsers = 0;
double crashRate = 0.0;
double avgStartupTime = 0.0;
Map<String, dynamic>? performanceMetrics;
ReleaseMetrics({
required this.releaseId,
required this.version,
required this.platform,
required this.channels,
required this.startTime,
});
}
7.2 实时告警系统
// lib/features/monitoring/alert_system.dart
class ReleaseAlertSystem {
final List<AlertRule> _rules;
final AlertNotifier _notifier;
final MetricsCollector _collector;
ReleaseAlertSystem({
required List<AlertRule> rules,
required AlertNotifier notifier,
required MetricsCollector collector,
}) : _rules = rules,
_notifier = notifier,
_collector = collector {
_initializeDefaultRules();
}
void _initializeDefaultRules() {
// 崩溃率告警
_rules.add(AlertRule(
id: 'high_crash_rate',
name: '高崩溃率告警',
condition: (metrics) => metrics.crashRate > 1.0, // 1%崩溃率
severity: AlertSeverity.critical,
message: (metrics) => '版本 ${metrics.version} 崩溃率过高: ${metrics.crashRate.toStringAsFixed(2)}%',
actions: [
AlertAction.escalateToTeamLead,
AlertAction.rollbackRelease,
],
));
// 性能下降告警
_rules.add(AlertRule(
id: 'performance_degradation',
name: '性能下降告警',
condition: (metrics) => metrics.avgStartupTime > 3000, // 启动时间超过3秒
severity: AlertSeverity.high,
message: (metrics) => '版本 ${metrics.version} 启动时间过长: ${metrics.avgStartupTime}ms',
actions: [AlertAction.notifyDevelopers],
));
// 安装量异常告警
_rules.add(AlertRule(
id: 'installation_anomaly',
name: '安装量异常告警',
condition: (metrics) {
final expected = _calculateExpectedInstallations(metrics);
return metrics.installations < expected * 0.5; // 低于预期的50%
},
severity: AlertSeverity.medium,
message: (metrics) => '版本 ${metrics.version} 安装量异常偏低',
actions: [AlertAction.investigateChannel],
));
}
// 监控发布
Future<void> monitorRelease(String releaseId) async {
final timer = Timer.periodic(const Duration(minutes: 5), (_) async {
try {
final metrics = await _collector.getReleaseMetrics(releaseId);
await _checkAlerts(releaseId, metrics);
} catch (e) {
print('监控失败: $e');
}
});
// 24小时后停止监控(除非有问题)
Future.delayed(const Duration(hours: 24), () {
timer.cancel();
});
}
Future<void> _checkAlerts(String releaseId, ReleaseMetrics metrics) async {
for (final rule in _rules) {
if (rule.condition(metrics)) {
await _triggerAlert(rule, metrics);
}
}
}
Future<void> _triggerAlert(AlertRule rule, ReleaseMetrics metrics) async {
final alert = Alert(
id: '${rule.id}_${DateTime.now().millisecondsSinceEpoch}',
rule: rule,
metrics: metrics,
timestamp: DateTime.now(),
acknowledged: false,
);
// 发送通知
await _notifier.notify(alert);
// 执行动作
for (final action in rule.actions) {
await _executeAction(action, alert);
}
// 记录到监控系统
await _logAlert(alert);
}
Future<void> _executeAction(AlertAction action, Alert alert) async {
switch (action) {
case AlertAction.notifyDevelopers:
await _notifyDevelopers(alert);
break;
case AlertAction.escalateToTeamLead:
await _escalateToTeamLead(alert);
break;
case AlertAction.rollbackRelease:
await _initiateRollback(alert);
break;
case AlertAction.investigateChannel:
await _investigateDistributionChannel(alert);
break;
}
}
}
八、回滚与热更新策略
8.1 版本回滚机制
// lib/core/release/rollback_manager.dart
class RollbackManager {
final ReleaseStore _releaseStore;
final DistributionService _distribution;
final AnalyticsService _analytics;
RollbackManager({
required ReleaseStore releaseStore,
required DistributionService distribution,
required AnalyticsService analytics,
}) : _releaseStore = releaseStore,
_distribution = distribution,
_analytics = analytics;
// 检查是否需要回滚
Future<bool> shouldRollback(String releaseId) async {
final metrics = await _analytics.getReleaseMetrics(releaseId);
// 检查关键指标
final criteria = [
_checkCrashRate(metrics),
_checkPerformance(metrics),
_checkUserFeedback(metrics),
_checkBusinessMetrics(metrics),
];
final shouldRollback = criteria.any((c) => c == true);
if (shouldRollback) {
await _analytics.trackEvent('rollback_triggered', {
'release_id': releaseId,
'criteria': criteria,
'metrics': metrics.toJson(),
});
}
return shouldRollback;
}
bool _checkCrashRate(ReleaseMetrics metrics) {
// 崩溃率超过阈值
return metrics.crashRate > 2.0; // 2%崩溃率
}
bool _checkPerformance(ReleaseMetrics metrics) {
// 启动时间显著增加
return metrics.avgStartupTime > 4000 &&
metrics.performanceDegradation > 30; // 性能下降超过30%
}
// 执行回滚
Future<RollbackResult> executeRollback({
required String fromReleaseId,
required String toReleaseId,
required String reason,
RollbackStrategy strategy = RollbackStrategy.gradual,
}) async {
print('🔄 开始执行回滚: $fromReleaseId -> $toReleaseId');
// 1. 获取目标版本
final targetRelease = await _releaseStore.getRelease(toReleaseId);
if (targetRelease == null) {
throw RollbackException('目标版本不存在: $toReleaseId');
}
// 2. 根据策略执行回滚
switch (strategy) {
case RollbackStrategy.immediate:
return await _immediateRollback(fromReleaseId, targetRelease, reason);
case RollbackStrategy.gradual:
return await _gradualRollback(fromReleaseId, targetRelease, reason);
case RollbackStrategy.selective:
return await _selectiveRollback(fromReleaseId, targetRelease, reason);
}
}
Future<RollbackResult> _gradualRollback(
String fromReleaseId,
Release targetRelease,
String reason,
) async {
final result = RollbackResult(
fromReleaseId: fromReleaseId,
toReleaseId: targetRelease.id,
strategy: RollbackStrategy.gradual,
startTime: DateTime.now(),
);
// 分阶段回滚
final stages = [
_RollbackStage.internalTesters(10), // 10% 内部测试人员
_RollbackStage.betaTesters(25), // 25% 测试人员
_RollbackStage.lowRiskUsers(50), // 50% 低风险用户
_RollbackStage.allUsers(100), // 100% 所有用户
];
for (final stage in stages) {
print('📊 执行回滚阶段: ${stage.name} (${stage.percentage}%)');
// 更新分发配置
await _distribution.updateReleaseDistribution(
releaseId: targetRelease.id,
percentage: stage.percentage,
userSegments: stage.segments,
);
// 监控阶段效果
final stageResult = await _monitorRollbackStage(
fromReleaseId,
targetRelease.id,
stage,
);
result.stages.add(stageResult);
// 如果阶段出现问题,暂停回滚
if (stageResult.hasIssues) {
print('⚠️ 回滚阶段发现问题,暂停回滚');
result.status = RollbackStatus.paused;
break;
}
// 等待一段时间继续下一阶段
await Future.delayed(const Duration(minutes: 30));
}
result.endTime = DateTime.now();
result.status = result.stages.last.hasIssues
? RollbackStatus.partial
: RollbackStatus.completed;
// 记录回滚结果
await _analytics.trackEvent('rollback_completed', result.toJson());
return result;
}
// 生成回滚报告
Future<RollbackReport> generateRollbackReport(String rollbackId) async {
final result = await _releaseStore.getRollbackResult(rollbackId);
if (result == null) {
throw RollbackException('回滚记录不存在: $rollbackId');
}
// 收集回滚前后的指标对比
final beforeMetrics = await _analytics.getReleaseMetrics(result.fromReleaseId);
final afterMetrics = await _analytics.getReleaseMetrics(result.toReleaseId);
return RollbackReport(
rollbackId: rollbackId,
result: result,
metricsComparison: _compareMetrics(beforeMetrics, afterMetrics),
impactAnalysis: _analyzeImpact(result),
lessonsLearned: await _extractLessons(result),
recommendations: _generateRecommendations(result),
);
}
}
8.2 热更新策略
// lib/core/update/hot_update_manager.dart
class HotUpdateManager {
final CodePushService _codePush;
final AssetBundle _assetBundle;
final SecurityService _security;
// 更新策略
UpdateStrategy _strategy = UpdateStrategy.autoBackground;
HotUpdateManager({
required CodePushService codePush,
required AssetBundle assetBundle,
required SecurityService security,
}) : _codePush = codePush,
_assetBundle = assetBundle,
_security = security;
// 检查更新
Future<UpdateInfo?> checkForUpdate({
bool forceCheck = false,
UpdatePriority priority = UpdatePriority.normal,
}) async {
final lastCheck = await _getLastCheckTime();
final shouldCheck = forceCheck ||
lastCheck == null ||
DateTime.now().difference(lastCheck) > const Duration(hours: 1);
if (!shouldCheck) return null;
try {
final update = await _codePush.checkUpdate(
currentVersion: await _getCurrentVersion(),
platform: Platform.operatingSystem,
channel: await _getUpdateChannel(),
);
if (update != null && update.isValid) {
// 验证更新包签名
final isValid = await _security.verifyUpdateSignature(update);
if (!isValid) {
throw HotUpdateException('更新包签名验证失败');
}
// 保存更新信息
await _saveUpdateInfo(update);
return update;
}
} catch (e) {
print('检查更新失败: $e');
}
return null;
}
// 下载更新
Future<UpdateDownloadResult> downloadUpdate(UpdateInfo update) async {
print('📥 开始下载更新: ${update.version}');
final result = UpdateDownloadResult(update: update);
try {
// 创建临时目录
final tempDir = await _createTempDirectory();
// 下载更新包
final downloadResult = await _codePush.downloadUpdate(
update: update,
targetDir: tempDir,
onProgress: (progress) {
result.progress = progress;
_notifyDownloadProgress(progress);
},
);
// 验证下载文件
await _verifyDownloadedFile(downloadResult.file);
// 应用更新
await _applyUpdate(downloadResult.file);
result.status = UpdateDownloadStatus.completed;
result.completedAt = DateTime.now();
// 记录更新成功
await _logUpdateSuccess(update);
} catch (e) {
result.status = UpdateDownloadStatus.failed;
result.error = e.toString();
// 记录更新失败
await _logUpdateFailure(update, e);
}
return result;
}
// 应用更新
Future<void> _applyUpdate(File updateFile) async {
print('🔄 应用热更新...');
// 1. 验证更新包
final isValid = await _security.validateUpdatePackage(updateFile);
if (!isValid) {
throw HotUpdateException('更新包验证失败');
}
// 2. 备份当前资源
await _backupCurrentAssets();
// 3. 解压更新包
final extractedDir = await _extractUpdatePackage(updateFile);
// 4. 替换资源文件
await _replaceAssets(extractedDir);
// 5. 清理临时文件
await _cleanupTempFiles();
// 6. 重启应用(如果需要)
if (_requiresRestart) {
await _scheduleRestart();
}
print('✅ 热更新应用完成');
}
// 渐进式更新策略
Future<void> applyProgressiveUpdate({
required UpdateInfo update,
required ProgressiveUpdateConfig config,
}) async {
final userSegments = await _segmentUsersForUpdate(config);
for (final segment in userSegments) {
print('🎯 对用户分段应用更新: ${segment.name}');
// 为分段用户启用更新
await _codePush.enableUpdateForSegment(
update: update,
segment: segment,
);
// 监控分段更新效果
final metrics = await _monitorUpdateSegment(update, segment);
// 根据效果决定是否继续
if (metrics.hasIssues) {
print('⚠️ 分段更新发现问题,暂停推广');
await _pauseUpdateRollout(update);
break;
}
// 等待一段时间继续下一分段
await Future.delayed(config.stageInterval);
}
}
}
九、最佳实践与总结
9.1 双端打包最佳实践
构建优化:
# build_optimizations.yaml
flutter_build:
aot_optimizations:
tree_shaking: true
obfuscation: true
split_debug_info: true
code_size_report: true
asset_optimizations:
image_compression: true
webp_conversion: true
unused_resource_removal: true
platform_specific:
android:
shrink_resources: true
minify_enabled: true
multi_dex_enabled: true
harmony:
hap_compression: true
resource_optimization: true
distributed_capabilities_minification: true
harmony_build:
native_optimizations:
proguard_enabled: true
resource_table_optimization: true
hap_size_limit: 100MB
signing_optimizations:
v2_signing: true
signature_scheme: v3
版本管理规范:
版本号格式:主版本.次版本.修订版本+构建号_平台
示例:3.2.1+20240501.1800_harmony
发布流程:
1. 开发分支合并到release分支
2. 触发自动化构建
3. 执行自动化测试
4. 生成双端版本包
5. 渠道分发
6. 监控发布效果
回滚策略:
- 关键问题:立即全量回滚
- 性能问题:渐进式回滚
- 业务问题:选择性回滚
9.2 监控指标体系
| 指标类别 | 具体指标 | 告警阈值 | 监控频率 |
|---|---|---|---|
| 构建质量 | 构建成功率 | <95% | 每次构建 |
| 构建时长 | >30分钟 | 每次构建 | |
| 产物大小 | >100MB | 每次构建 | |
| 发布效果 | 安装成功率 | <90% | 实时 |
| 用户激活率 | <50% | 每小时 | |
| 崩溃率 | >1% | 实时 | |
| 性能表现 | 启动时间 | >3秒 | 每小时 |
| 内存占用 | >500MB | 每小时 | |
| 帧率 | <50fps | 每小时 | |
| 业务影响 | 功能使用率 | 下降20% | 每天 |
| 用户满意度 | <4星 | 每周 | |
| 收入影响 | 下降15% | 实时 |
9.3 总结与展望
实践成果:
- 效率提升:构建时间从2小时缩短到30分钟
- 质量保障:自动化测试覆盖率从60%提升到85%
- 发布可控:支持多版本、多渠道的精准发布
- 监控全面:建立完整的发布后监控体系
技术价值:
- 标准化流程:统一的构建、发布、监控流程
- 自动化程度:减少人工干预,降低错误率
- 可追溯性:完整的发布记录和效果分析
- 快速响应:支持快速回滚和热更新
未来规划:
- 智能发布:基于AI的发布决策和风险预测
- 跨平台统一:进一步抽象多平台差异
- 生态整合:深度集成各大应用商店和分发平台
- 开发者体验:提供更友好的发布工具和可视化界面
结语
“共享社区”应用的双端打包与发布策略,通过系统化的架构设计、自动化的流程实现和智能化的监控分析,构建了高效、可靠、可控的发布体系。这套策略不仅适用于当前的技术栈,也为未来的技术演进和多平台扩展奠定了坚实基础。
如果您有任何疑问、对文章写的不满意、发现错误或者有更好的方法,欢迎在评论、私信或邮件中提出,非常感谢您的支持。🙏
嘻嘻嘻,关注我!!!黑马波哥
更多推荐



所有评论(0)