You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Flutter与AWS Amplify的离线媒体对象创建及云端同步实现问询

Flutter + AWS Amplify 离线创建带媒体对象并可靠同步方案

1. 离线时先存本地,不等网络

离线状态下不用死等S3返回Key,直接按以下步骤操作:

  • 给Datastore模型新增两个字段:mediaLocalPath(存储本地媒体文件路径)、uploadStatus(标记上传状态:待上传/已上传/上传失败),填充好这些字段后直接调用Amplify.DataStore.save()存入本地存储。
  • 将图片/视频复制到应用专属的文档目录(用path_provider获取路径),避免被系统自动清理。

2. 网络恢复后自动补传媒体

用connectivity_plus包监听网络状态,一旦检测到联网就批量处理待上传内容:

  • 查询Datastore中所有uploadStatus为pending的对象,取出对应的本地媒体路径。
  • 调用Amplify Storage的上传接口,拿到S3的Key后,更新Datastore对象的mediaS3Key字段,将uploadStatus改为completed,再重新保存对象。
  • 上传成功后可删除本地缓存的媒体文件节省空间;若上传失败,将状态改为failed,后续可添加重试逻辑。

3. 解决Datastore偶尔不同步的问题

  • 检查模型Schema:确保@model注解开启同步并配置冲突策略,比如@model(syncEnabled: true, conflictResolution: { strategy: "VERSIONED" }),让本地与云端的版本冲突能自动处理。
  • 不依赖自动同步,网络恢复时主动调用Amplify.DataStore.sync()强制触发同步。
  • 用Amplify.DataStore.observeQuery()监听同步状态,排查日志中的错误(比如字段不匹配、权限配置问题),定位偶尔不同步的根源。

4. 代码片段参考

GraphQL模型定义

type MediaObject @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  title: String!
  mediaLocalPath: String # 离线时存储本地文件路径
  mediaS3Key: String # 联网后存储S3文件Key
  uploadStatus: String! # 标记上传状态:pending/completed/failed
}

离线创建对象代码

import 'package:path_provider/path_provider.dart';
import 'package:amplify_datastore/amplify_datastore.dart';
import 'package:uuid/uuid.dart';

Future<void> createOfflineMedia(String title, File mediaFile) async {
  // 获取应用缓存目录
  final appDir = await getApplicationDocumentsDirectory();
  // 生成唯一文件名避免重复
  final localFilePath = '${appDir.path}/${const Uuid().v4()}_${mediaFile.path.split('/').last}';
  // 复制媒体文件到缓存目录
  await mediaFile.copy(localFilePath);

  // 创建本地对象并保存
  final mediaObj = MediaObject(
    title: title,
    mediaLocalPath: localFilePath,
    uploadStatus: 'pending',
  );
  await Amplify.DataStore.save(mediaObj);
}

网络恢复同步代码

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:amplify_storage_s3/amplify_storage_s3.dart';
import 'package:amplify_datastore/amplify_datastore.dart';
import 'package:uuid/uuid.dart';

// 初始化网络监听
void setupNetworkSync() {
  Connectivity().onConnectivityChanged.listen((result) async {
    if (result != ConnectivityResult.none) {
      await syncPendingMedia();
    }
  });
}

// 同步待上传媒体
Future<void> syncPendingMedia() async {
  // 查询所有待上传对象
  final pendingItems = await Amplify.DataStore.query(MediaObject.classType,
    where: MediaObject.UPLOADSTATUS.eq('pending')
  );

  for (var item in pendingItems) {
    if (item.mediaLocalPath == null) continue;
    final localFile = File(item.mediaLocalPath!);
    if (!await localFile.exists()) continue;

    try {
      // 上传至S3
      final uploadResult = await Amplify.Storage.uploadFile(
        local: localFile,
        key: 'user_media/${const Uuid().v4()}_${localFile.path.split('/').last}',
      );

      // 更新对象信息
      final updatedItem = item.copyWith(
        mediaS3Key: uploadResult.key,
        uploadStatus: 'completed',
        mediaLocalPath: null, // 可选:清除本地路径记录
      );
      await Amplify.DataStore.save(updatedItem);

      // 删除本地缓存文件
      await localFile.delete();
    } catch (e) {
      // 标记上传失败,后续可重试
      final failedItem = item.copyWith(uploadStatus: 'failed');
      await Amplify.DataStore.save(failedItem);
    }
  }

  // 手动触发Datastore同步
  await Amplify.DataStore.sync();
}

额外提醒

  • 给上传失败的对象添加重试次数限制,比如失败3次后通知用户手动重试,避免无限循环。
  • 确保Amplify Auth的用户会话支持离线缓存,否则联网后可能因身份验证问题导致上传失败。
  • 大文件建议使用分块上传,Amplify Storage原生支持该功能,离线时可缓存上传进度,下次联网后继续上传。

内容的提问来源于stack exchange,提问作者Bala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 20:09:24