feat(mobile): ios background upload bridge (compile-gated at G3)
Swift 侧(协议与 Android UploadPlugin.kt 逐字一致,编译/真机留 G3): - UploadBridge.swift:通道/方法/事件/失败码常量 + registerTask 参数解析 (镜像 UploadProtocol.kt) - UploadEventBus.swift:单调 seq + 终态 ack 缓存重放(镜像 UploadEventBus.kt),iOS 增强——未 ack 终态落盘(系统后台拉起投递的 回调在进程重启后同样重放,技术方案 §6.2 持久化原生回调) - UploadTaskStore.swift:taskId→URLSession taskIdentifier 映射 plist 持久化 (Application Support;对应 Android WorkManager 自持映射) - UploadPlugin.swift:URLSession background (com.photolive.photo_live.uploads)+ delegate 失败分类(2xx→completed+etag / 403→needsRenew / 4xx→HTTP_4XX / 网络→重试上限后 NETWORK,镜像 UploadPutExecutor/UploadWorker)、原生重试(5 次上限、10s 指数退避)、 进度 500ms 节流、queryTask/cancelTask/ackEvents、静默取消 - AppDelegate.swift:implicit engine 通道注册 + 启动重建会话 + handleEventsForBackgroundURLSession completionHandler 暂存 - Info.plist:UIBackgroundModes 有意不声明(background URLSession 无需; 计划措辞按技术方案 §6.2 修正,见 README-ios.md) - project.pbxproj 登记新 Swift 文件;README-ios.md(Xcode 步骤 + G3 验证 清单:实际文件上传/持久化回调窗口/服务端补偿/重启重联校准/强制退出/ 低电量延迟/100 张批量) Dart:NativeTransport 选择矩阵并入 iOS(Platform.isAndroid || isIOS, FORCE_DART_TRANSPORT 覆盖不变)——协议两侧一致,无新通道代码。 flutter analyze 0 issue;flutter test 219 全绿。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,10 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
||||
7884E8812EC3CC0A00C636F3 /* UploadBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8802EC3CC0A00C636F3 /* UploadBridge.swift */; };
|
||||
7884E8832EC3CC0B00C636F3 /* UploadEventBus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8822EC3CC0B00C636F3 /* UploadEventBus.swift */; };
|
||||
7884E8852EC3CC0C00C636F3 /* UploadTaskStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8842EC3CC0C00C636F3 /* UploadTaskStore.swift */; };
|
||||
7884E8872EC3CC0D00C636F3 /* UploadPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8862EC3CC0D00C636F3 /* UploadPlugin.swift */; };
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
@@ -50,6 +54,10 @@
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
7884E8802EC3CC0A00C636F3 /* UploadBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadBridge.swift; sourceTree = "<group>"; };
|
||||
7884E8822EC3CC0B00C636F3 /* UploadEventBus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadEventBus.swift; sourceTree = "<group>"; };
|
||||
7884E8842EC3CC0C00C636F3 /* UploadTaskStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadTaskStore.swift; sourceTree = "<group>"; };
|
||||
7884E8862EC3CC0D00C636F3 /* UploadPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadPlugin.swift; sourceTree = "<group>"; };
|
||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
@@ -123,6 +131,10 @@
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
|
||||
7884E8802EC3CC0A00C636F3 /* UploadBridge.swift */,
|
||||
7884E8822EC3CC0B00C636F3 /* UploadEventBus.swift */,
|
||||
7884E8842EC3CC0C00C636F3 /* UploadTaskStore.swift */,
|
||||
7884E8862EC3CC0D00C636F3 /* UploadPlugin.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
@@ -284,6 +296,10 @@
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
|
||||
7884E8812EC3CC0A00C636F3 /* UploadBridge.swift in Sources */,
|
||||
7884E8832EC3CC0B00C636F3 /* UploadEventBus.swift in Sources */,
|
||||
7884E8852EC3CC0C00C636F3 /* UploadTaskStore.swift in Sources */,
|
||||
7884E8872EC3CC0D00C636F3 /* UploadPlugin.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user