【Flutter x 鸿蒙】第八篇:打包发布、应用上架与运营监控

【Flutter x 鸿蒙】第八篇:打包发布、应用上架与运营监控

在完成了Flutter应用的开发、性能优化后,接下来就是将其打包发布到应用商店,并建立完善的运营监控体系。本篇将系统讲解从打包发布到上架运营的全流程。

一、Flutter应用打包发布

1.1 Android平台打包

环境准备与配置

首先确保Flutter SDK、Android Studio和Android SDK已正确安装,并通过flutter doctor验证环境完整性。

应用信息配置

android/app/build.gradle中配置应用基本信息:

复制代码
android {
    defaultConfig {
        applicationId "com.example.myapp"  // 包名,需全局唯一
        minSdkVersion 21
        targetSdkVersion 34
        versionCode 1  // 内部版本号,每次更新需递增
        versionName "1.0.0"  // 用户可见版本号
    }
}

应用图标配置

将不同分辨率的图标放入对应目录:

  • android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png

生成签名密钥

使用keytool工具生成签名密钥库:

复制代码
keytool -genkey -v -keystore ~/upload-keystore.jks \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -alias upload

配置签名信息

android/key.properties文件中配置密钥信息:

复制代码
storePassword=your_store_password
keyPassword=your_key_password
keyAlias=upload
storeFile=/Users/yourusername/upload-keystore.jks

android/app/build.gradle中配置签名:

复制代码
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
    
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true  // 启用代码混淆
            shrinkResources true  // 移除未使用的资源
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

打包命令

生成APK文件:

复制代码
flutter build apk --release

生成App Bundle(推荐):

复制代码
flutter build appbundle --release

1.2 iOS平台打包

环境要求

  • macOS系统
  • Xcode开发工具
  • Apple开发者账号(年费$99)

应用配置

ios/Runner/Info.plist中配置应用信息:

复制代码
<key>CFBundleName</key>
<string>My App</string>
<key>CFBundleDisplayName</key>
<string>My App</string>
<key>CFBundleIdentifier</key>
<string>com.example.myapp</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>

证书与描述文件配置

  1. 在Apple Developer后台创建App ID
  2. 生成Distribution证书
  3. 创建App Store描述文件
  4. 在Xcode中配置签名

打包命令

复制代码
flutter build ipa --release

或在Xcode中:

  1. 选择Product > Archive
  2. 在Organizer中选择Distribute App
  3. 选择App Store Connect分发方式

二、鸿蒙应用打包发布

2.1 环境准备

开发工具

  • DevEco Studio(鸿蒙官方IDE)
  • HarmonyOS SDK

项目配置

config.jsonapp.json5中配置应用信息:

复制代码
{
  "app": {
    "bundleName": "com.example.myapp",
    "vendor": "example",
    "versionCode": 1,
    "versionName": "1.0.0"
  }
}

2.2 签名证书配置

生成密钥和证书请求文件

在DevEco Studio中:

  1. 选择Build > Generate Key and CSR
  2. 填写密钥库信息(.p12文件)
  3. 生成证书请求文件(.csr)

申请发布证书

在AppGallery Connect平台:

  1. 登录华为开发者账号
  2. 证书管理中创建发布证书
  3. 上传CSR文件并下载证书(.cer)

申请发布Profile

  1. 在AppGallery Connect中创建应用
  2. HAP Provision Profile管理中创建Profile
  3. 关联证书和App ID
  4. 下载Profile文件(.p7b)

配置签名信息

在DevEco Studio中:

  1. 打开File > Project Structure
  2. Signing Configs中配置: Store File:.p12文件 Store Password:密钥库密码 Key alias:密钥别名 Key password:密钥密码 Profile file:.p7b文件 Certpath file:.cer文件

2.3 打包命令

复制代码
# 编译打包
hvigor build --mode release

# 或使用DevEco Studio
Build > Build Hap(s)/APP(s) > Build APP(s)

三、应用上架流程

3.1 Google Play上架

准备工作

  1. 注册Google Play开发者账号(一次性费用$25)
  2. 在Google Play Console创建应用
  3. 准备应用元数据(名称、描述、截图等)

上传应用

  1. 发布管理 > 正式版中创建新版本
  2. 上传AAB文件
  3. 填写版本信息
  4. 提交审核

审核要点

  • 应用必须符合Google Play政策
  • 权限声明必须合理
  • 隐私政策必须完整
  • 截图和描述必须准确

3.2 App Store上架

准备工作

  1. 注册Apple开发者账号(年费$99)
  2. 在App Store Connect创建应用
  3. 准备应用元数据

上传应用

  1. 使用Xcode或Transporter上传IPA文件
  2. 在App Store Connect中配置应用信息
  3. 提交审核

审核要点

  • 应用必须符合App Store审核指南
  • 必须提供隐私政策链接
  • 截图必须真实反映应用功能
  • 年龄分级必须准确

3.3 华为应用市场上架

准备工作

  1. 注册华为开发者账号
  2. 在AppGallery Connect创建应用
  3. 准备应用元数据

上传应用

  1. 应用信息中填写基本信息
  2. 上传已签名的HAP包
  3. 填写版本信息
  4. 提交审核

审核要点

  • 应用必须符合华为应用市场审核规范
  • 必须提供隐私政策
  • 必须通过安全检测

四、应用内更新机制

4.1 Flutter应用内更新

版本检测

复制代码
import 'package:package_info_plus/package_info_plus.dart';
import 'package:http/http.dart' as http;

class UpdateChecker {
  static Future<bool> checkUpdate() async {
    final packageInfo = await PackageInfo.fromPlatform();
    final currentVersion = packageInfo.version;
    
    final response = await http.get(Uri.parse('https://api.example.com/version'));
    final data = json.decode(response.body);
    final latestVersion = data['version'];
    
    return _compareVersions(latestVersion, currentVersion) > 0;
  }
  
  static int _compareVersions(String v1, String v2) {
    final parts1 = v1.split('.');
    final parts2 = v2.split('.');
    
    for (int i = 0; i < parts1.length; i++) {
      final num1 = int.tryParse(parts1[i]) ?? 0;
      final num2 = int.tryParse(parts2[i]) ?? 0;
      
      if (num1 > num2) return 1;
      if (num1 < num2) return -1;
    }
    
    return 0;
  }
}

下载安装

复制代码
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'package:dio/dio.dart';

class UpdateManager {
  static Future<void> downloadAndInstall(String url) async {
    final dio = Dio();
    final directory = await getApplicationDocumentsDirectory();
    final savePath = '${directory.path}/update.apk';
    
    await dio.download(url, savePath, onReceiveProgress: (received, total) {
      final progress = (received / total * 100).toInt();
      print('下载进度: $progress%');
    });
    
    await OpenFile.open(savePath);
  }
}

4.2 鸿蒙应用内更新

版本检测

复制代码
import bundleManager from '@ohos.bundle.bundleManager';

async function checkUpdate(): Promise<boolean> {
  const bundleInfo = await bundleManager.getBundleInfo(
    'com.example.myapp',
    bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
  );
  
  const currentVersion = bundleInfo.versionCode;
  
  // 请求服务器获取最新版本
  const response = await fetch('https://api.example.com/version');
  const data = await response.json();
  const latestVersion = data.versionCode;
  
  return latestVersion > currentVersion;
}

下载安装

复制代码
import downloadManager from '@ohos.downloadManager';

async function downloadAndInstall(url: string) {
  const downloadId = await downloadManager.addDownloadTask({
    url: url,
    destinationPath: '/data/storage/el2/base/scratch/update.hap',
    fileName: 'update.hap',
    extraData: {
      resumeEnabled: true  // 启用断点续传
    }
  });
  
  downloadManager.on('downloadProgressChanged', (taskId, progress) => {
    console.log(`下载进度: ${progress}%`);
  });
  
  downloadManager.on('downloadCompleted', async (taskId) => {
    await bundleManager.installBundle(
      '/data/storage/el2/base/scratch/update.hap',
      {
        installFlag: bundleManager.InstallFlag.INSTALL_FLAG_FORCE_OVERWRITE
      }
    );
  });
}

五、应用安全加固

5.1 Flutter应用加固

代码混淆

android/app/build.gradle中启用混淆:

复制代码
buildTypes {
  release {
    minifyEnabled true
    shrinkResources true
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  }
}

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.devicelocale.** { *; }
-keep class com.google.firebase.** { *; }

Dart代码混淆

复制代码
flutter build apk --release --obfuscate --split-debug-info=./build/app/outputs/symbols

5.2 鸿蒙应用加固

整包加固

在DevEco Studio中:

  1. 选择Build > Generate Key and CSR
  2. 生成密钥库文件
  3. 使用华为提供的加固工具对HAP包进行加固

SO库加固

对于包含SO库的应用,可以使用第三方加固工具:

复制代码
# 使用加固工具对SO库进行保护
java -jar hap-sign-tool.jar --protect \
  --input app.hap \
  --output app-protected.hap \
  --config protection-config.json

六、应用性能监控

6.1 Flutter性能监控

集成Firebase Crashlytics

pubspec.yaml中添加依赖:

复制代码
dependencies:
  firebase_crashlytics: ^3.0.0

main.dart中初始化:

复制代码
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  
  FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError;
  
  runZonedGuarded(() {
    runApp(MyApp());
  }, (error, stackTrace) {
    FirebaseCrashlytics.instance.recordError(error, stackTrace);
  });
}

手动上报错误

复制代码
try {
  // 业务代码
} catch (error, stackTrace) {
  FirebaseCrashlytics.instance.recordError(error, stackTrace);
}

性能监控

复制代码
import 'package:firebase_performance/firebase_performance.dart';

class PerformanceMonitor {
  static Future<void> trackNetworkRequest(String url) async {
    final metric = FirebasePerformance.instance.newHttpMetric(url, HttpMethod.Get);
    await metric.start();
    
    try {
      final response = await http.get(Uri.parse(url));
      metric
        ..responseCode = response.statusCode
        ..responseContentType = response.headers['content-type']
        ..responsePayloadSize = response.bodyBytes.length;
    } finally {
      await metric.stop();
    }
  }
}

6.2 鸿蒙性能监控

集成APMS服务

config.json中配置:

复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "用于性能监控数据上报"
      }
    ]
  }
}

手动上报性能数据

复制代码
import agconnect from '@ohos.agconnect';
import { APMS } from '@ohos.agconnect.apms';

const apms = APMS.getInstance(agconnect.instance());

// 上报自定义事件
apms.customEvent('user_login', {
  'user_id': '123456',
  'login_type': 'mobile'
});

// 上报性能指标
apms.trace('network_request', async (trace) => {
  trace.start();
  await fetch('https://api.example.com/data');
  trace.stop();
});

崩溃监控

复制代码
import faultLogger from '@ohos.faultLogger';

// 监听崩溃事件
faultLogger.on('fault', (faultInfo) => {
  console.error('应用崩溃:', faultInfo);
  // 上报到服务器
  reportCrash(faultInfo);
});

七、灰度发布与A/B测试

7.1 灰度发布策略

用户分群策略

复制代码
class UserSegment {
  static bool isInGrayRelease(String userId) {
    // 基于用户ID哈希分桶
    final hash = _hashString(userId);
    return hash % 100 < 10;  // 10%灰度
  }
  
  static int _hashString(String input) {
    var hash = 0;
    for (int i = 0; i < input.length; i++) {
      hash = (hash << 5) - hash + input.codeUnitAt(i);
      hash = hash & hash; // Convert to 32bit integer
    }
    return hash.abs();
  }
}

版本控制

复制代码
class FeatureFlag {
  static const String newFeature = 'new_feature';
  
  static Future<bool> isEnabled(String feature, String userId) async {
    final response = await http.get(Uri.parse(
      'https://api.example.com/features?feature=$feature&user=$userId'
    ));
    final data = json.decode(response.body);
    return data['enabled'] ?? false;
  }
}

7.2 A/B测试实现

实验配置

复制代码
class ABTest {
  static Future<String> getVariant(String experimentId, String userId) async {
    final response = await http.get(Uri.parse(
      'https://api.example.com/experiments?experiment=$experimentId&user=$userId'
    ));
    final data = json.decode(response.body);
    return data['variant'] ?? 'control';
  }
}

UI变体渲染

复制代码
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<String>(
      future: ABTest.getVariant('homepage_layout', 'user123'),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          final variant = snapshot.data!;
          if (variant == 'variant_a') {
            return LayoutA();
          } else {
            return LayoutB();
          }
        }
        return LoadingSpinner();
      }
    );
  }
}

八、运营数据分析

8.1 关键指标监控

用户增长指标

复制代码
class AnalyticsService {
  static void trackUserRegistration(String userId) {
    // 上报用户注册事件
    FirebaseAnalytics.instance.logEvent(
      name: 'user_registration',
      parameters: {
        'user_id': userId,
        'timestamp': DateTime.now().millisecondsSinceEpoch,
      },
    );
  }
  
  static void trackDailyActiveUsers() {
    // 每日活跃用户统计
    FirebaseAnalytics.instance.logEvent(
      name: 'dau',
      parameters: {
        'date': DateTime.now().toIso8601String().split('T')[0],
      },
    );
  }
}

业务转化指标

复制代码
class ConversionTracker {
  static void trackPurchase(String userId, double amount, String productId) {
    FirebaseAnalytics.instance.logEvent(
      name: 'purchase',
      parameters: {
        'user_id': userId,
        'amount': amount,
        'product_id': productId,
        'currency': 'CNY',
      },
    );
  }
  
  static void trackConversion(String funnelName, int step) {
    FirebaseAnalytics.instance.logEvent(
      name: 'funnel_step',
      parameters: {
        'funnel_name': funnelName,
        'step': step,
        'timestamp': DateTime.now().millisecondsSinceEpoch,
      },
    );
  }
}

8.2 数据看板搭建

Firebase控制台

  1. 在Firebase控制台创建项目
  2. 配置事件和用户属性
  3. 创建自定义报告和仪表盘

自定义数据看板

复制代码
class DashboardService {
  static Future<Map<String, dynamic>> getDashboardData() async {
    final dauResponse = await http.get(Uri.parse('https://api.example.com/metrics/dau'));
    final revenueResponse = await http.get(Uri.parse('https://api.example.com/metrics/revenue'));
    final crashResponse = await http.get(Uri.parse('https://api.example.com/metrics/crash'));
    
    return {
      'dau': json.decode(dauResponse.body),
      'revenue': json.decode(revenueResponse.body),
      'crash_rate': json.decode(crashResponse.body),
    };
  }
}

九、总结与最佳实践

9.1 打包发布最佳实践

  1. 版本管理:遵循语义化版本规范(major.minor.patch)
  2. 签名安全:妥善保管签名密钥,定期轮换
  3. 测试覆盖:上架前进行全面测试(功能、性能、兼容性)
  4. 灰度发布:先小范围灰度,验证稳定后再全量

9.2 监控运营最佳实践

  1. 实时监控:建立7×24小时监控体系
  2. 告警机制:设置合理的告警阈值和通知渠道
  3. 数据驱动:基于数据分析做决策,持续优化产品
  4. 用户反馈:建立用户反馈收集和处理机制

9.3 持续优化

  1. 定期复盘:每周/每月复盘关键指标
  2. A/B测试:对新功能进行A/B测试验证效果
  3. 技术债务:定期清理技术债务,保持代码健康
  4. 安全审计:定期进行安全审计和漏洞修复

通过本篇的学习,你应该已经掌握了Flutter和鸿蒙应用的打包发布、上架运营全流程。从代码编写到用户使用,每一个环节都需要精心设计和持续优化,才能打造出高质量的应用产品。

相关推荐
小白|2 小时前
【OpenHarmony × Flutter】混合开发核心难题:如何精准同步 Stage 模型与 Flutter 页面的生命周期?(附完整解决方案)
flutter
张风捷特烈2 小时前
Flutter TolyUI 框架#11 | 标签 tolyui_tag
前端·flutter·ui kit
晚霞的不甘2 小时前
[鸿蒙2025领航者闯关]: Flutter + OpenHarmony 安全开发实战:从数据加密到权限管控的全链路防护
安全·flutter·harmonyos
松☆2 小时前
创建混合工程:OpenHarmony Stage 模型 + Flutter 模块标准结构详解
flutter
小白|2 小时前
【OpenHarmony × Flutter】混合开发高阶实战:如何统一管理跨平台状态?Riverpod + ArkTS 共享数据流架构详解
flutter·架构
灰灰勇闯IT2 小时前
[鸿蒙2025领航者闯关] 鸿蒙6.0星盾安全架构实战:打造金融级支付应用的安全防护
安全·harmonyos·安全架构
kirk_wang2 小时前
Flutter connectivity_plus 在鸿蒙端的完整适配指南:从原理到实践
flutter·移动开发·跨平台·arkts·鸿蒙
禁默2 小时前
[鸿蒙2025领航者闯关] 鸿蒙 6 特性实战闯关:金融支付应用的安全升级之路
安全·金融·harmonyos·鸿蒙2025领航者闯关·鸿蒙6实战
国服第二切图仔2 小时前
基于Electron for 鸿蒙开发的现代化颜色选择器
microsoft·electron·harmonyos