Flutter: 多平台发布与商店审核

📋 前置知识:需要先掌握以下内容

1. 你将学到


2. 一个被拒审的真实故事


3. 多平台发布流程


4. Android 发布


5. iOS 发布


6. Web 发布


7. 隐私合规


8. 完整示例:ShopApp 发布清单


9. ShopApp Release Checklist v1.2.3

Bob 按清单准备后,App Store 和 Google Play 首次提审即通过,Web 版 1 小时内上线。

100%
graph TD
    REL[Release Process] --> ANDROID2[Android AAB]
    REL --> IOS2[iOS IPA]
    REL --> WEB2[Web PWA]
    ANDROID2 --> PC[Play Console]
    IOS2 --> ASC[App Store Connect]
    WEB2 --> FH[Firebase Hosting / Vercel]
    PC --> REVIEW1[Google Review]
    ASC --> REVIEW2[Apple Review]
    REVIEW1 --> LIVE1[Live on Google Play]
    REVIEW2 --> LIVE2[Live on App Store]
    FH --> LIVE3[Live on Web]

(1) 签名与构建

▶ 示例:生成 Keystore

BASH
# Generate signing keystore
keytool -genkey -v -keystore shopapp-release.jks \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -alias shopapp

# Verify keystore
keytool -list -v -keystore shopapp-release.jks -alias shopapp

build.gradle 签名配置

GROOVY
// android/app/build.gradle
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    defaultConfig {
        applicationId "com.shopapp.app"
        minSdkVersion 21
        targetSdkVersion 34
        versionCode 42
        versionName "1.2.3"
    }
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['keyFile'] ? file(keystoreProperties['keyFile']) : null
            storePassword keystoreProperties['keyPassword']
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

构建与发布

BASH
# Build release AAB (Android App Bundle)
flutter build appbundle --release
# Output: build/app/outputs/bundle/release/app-release.aab

# Build release APK (for testing)
flutter build apk --release

# Upload to Play Console manually or via CI/CD

(2) Play Console 上架清单

项目 要求
Application ID 唯一包名 com.shopapp.app
AAB 文件 签名的 release bundle
图标 512x512 PNG
截图 手机+7 寸平板各 2-8 张
隐私政策 URL 必须可访问
内容分级 填写 IARC 问卷
目标受众 选择年龄范围

(1) Apple Developer 配置

步骤 操作
1. 注册 Apple Developer Program ($99/年)
2. 证书 创建 Distribution Certificate
3. Profile 创建 App Store Provisioning Profile
4. App ID 注册 Bundle Identifier
5. App Record App Store Connect 创建应用

Xcode 构建配置

XML
<!-- ios/Runner/Info.plist -->
`<key>`CFBundleShortVersionString</key>
`<string>`1.2.3</string>
`<key>`CFBundleVersion</key>
`<string>`42</string>
`<key>`NSAppTransportSecurity</key>
`<dict>`
    `<key>`NSAllowsArbitraryLoads</key>
    `<false/>`
`</dict>`
`<key>`NSUserTrackingUsageDescription</key>
`<string>`We use tracking to personalize your shopping experience.</string>

构建与上传

BASH
# Build IPA
flutter build ipa --release \
  --export-options-plist=ios/ExportOptions.plist
# Output: build/ios/ipa/shopapp.ipa

# Upload via Xcode or command line
xcrun altool --upload-app \
  --type ios \
  --file build/ios/ipa/shopapp.ipa \
  --apiKey YOUR_API_KEY \
  --apiIssuer YOUR_ISSUER_ID
# Or via Transporter app

(2) App Store Connect 上架清单

| Bundle ID | 与 Xcode 项目一致 | | IPA 文件 | Release 构建 | | 截图 | 6.7"/6.5"/5.5" 三种尺寸 | | 预览视频 | 可选,≤30s | | 描述 | ≤4000 字符 |

▶ 示例:Apple 隐私清单合规

DART
import 'package:flutter/material.dart';
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
import 'package:firebase_analytics/firebase_analytics.dart';

// ⚙️ 依赖:app_tracking_transparency: ^0.2.0, firebase_analytics: ^10.0.0(添加到 dependencies)

Future<void> requestTrackingPermission() async {
  final status = await AppTrackingTransparency.requestTrackingAuthorization();
  if (status == TrackingStatus.authorized) {
    await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true);
  } else {
    await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(false);
  }
}

输出:

TEXT 📖 仅展示
App Tracking Transparency dialog displayed
Status: authorized (or denied)
Analytics collection enabled/disabled accordingly

(1) 合规要求对比

平台 必备项
Google Play 隐私政策 / 数据安全表单 / 内容分级
App Store 隐私政策 / ATT / 加密合规声明
Web (PWA) GDPR Cookie 同意 / 隐私政策

(2) 隐私合规清单

发布前检查

三平台发布清单

(1) Android

(2) iOS

(3) Web

(4) Post-release

❓ 常见问题

Q AAB 和 APK 有什么区别?
A AAB (Android App Bundle) 是上传格式,Google Play 自动生成优化的 APK。AAB 体积更小,只包含设备需要的资源。
Q App Store 审核一般多久?
A 首次提交通常 24-48 小时,更新通常 12-24 小时。被拒后重新提交需再次等待。
Q 版本号 versionCode 和 versionName 怎么管理?
A versionCode 必须递增(整数),每次发布 +1;versionName 是用户可见的(如 1.2.3)。用 SemVer 规范。
Q Web 版需要备案吗?
A 中国大陆服务器需要 ICP 备案。海外服务器(Firebase/Vercel)不需要。
Q GDPR 合规需要做什么?
A 1) 首次启动弹隐私同意;2) 提供数据删除入口;3) 隐私政策链接;4) 数据最小化收集;5) 用户可撤销同意。
Q 被 App Store 拒审后怎么办?
A 仔细阅读拒审原因,修改后重新提交。常见原因:缺失隐私政策、ATT 未弹窗、崩溃、内容违规。

📖 小节


(1) 示例:版本号发布节奏

TEXT 📖 仅展示
1.0.0  →  MVP 上线(首次)
1.0.1  →  紧急 Bug 修复(patch)
1.1.0  →  新功能(minor)
1.2.3  →  ShopApp 发布(minor + patch)
2.0.0  →  重大重构(major)

输出:

TEXT 📖 仅展示
SemVer: MAJOR.MINOR.PATCH
- MAJOR 破坏性变更
- MINOR 兼容新增
- PATCH 兼容修复

(2) 示例:Firebase Crashlytics 集成

DART
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'dart:ui' show PlatformDispatcher;

// ⚙️ 依赖:firebase_core: ^2.0.0, firebase_crashlytics: ^3.0.0(添加到 dependencies)
// ShopApp 来自项目 lib/app.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  FlutterError.onError = (details) {
    FirebaseCrashlytics.instance.recordFlutterFatalError(details);
  };

  PlatformDispatcher.instance.onError = (error, stack) {
    FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
    return true;
  };

  runApp(const ShopApp());
}

输出:

TEXT 📖 仅展示
Crashlytics initialized
Fatal errors auto-reported
Non-fatal errors auto-reported

(3) 示例:发布监控仪表盘

BASH
# Firebase Crashlytics
firebase functions:log --only publishMonitor
# Expected output:
# {"status":"ok","version":"1.2.3","crashRate":"0.05%"}

输出:

TEXT 📖 仅展示
Crash rate after rollout:
- 1h: 0.05% (baseline 0.10%)
- 24h: 0.04% (healthy)
- ANR rate: 0.01% (acceptable)

📝 作业

  1. 基础题(难度⭐):为ShopApp生成Android Keystore并配置build.gradle签名,成功构建release AAB
  2. 进阶题(难度⭐⭐):完成ShopApp双平台发布准备——Android AAB签名+iOS证书配置,编写多平台发布清单
  3. 挑战题(难度⭐⭐⭐):实现ShopApp全平台发布流程(Android+iOS+Web),包含隐私合规声明、多渠道截图生成、App Store描述撰写

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏