Browse Source

fix: 修改容量计算方法

Destiny 9 months ago
parent
commit
a5f6100ad1

+ 1 - 0
lib/module/image_picker/image_picker_util.dart

@@ -1,6 +1,7 @@
 import 'dart:io';
 import 'dart:math';
 
+import 'package:classify_photo/classify_photo.dart';
 import 'package:clean/data/bean/photos_type.dart';
 import 'package:clean/model/asset_group.dart';
 import 'package:clean/module/locations_photo/locations_photo_controller.dart';

+ 1 - 0
lib/module/similar_photo/similar_photo_view.dart

@@ -2,6 +2,7 @@ import 'dart:io';
 import 'dart:math';
 import 'package:clean/base/base_page.dart';
 import 'package:clean/data/bean/photos_type.dart';
+import 'package:clean/module/image_picker/image_picker_util.dart';
 import 'package:clean/module/similar_photo/similar_photo_controller.dart';
 import 'package:clean/resource/assets.gen.dart';
 import 'package:clean/router/app_pages.dart';

+ 220 - 88
plugins/classify_photo/ios/Classes/ClassifyPhotoPlugin.swift

@@ -3,9 +3,8 @@ import StoreKit
 import Photos
 import UIKit
 
-public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
-
-  var photoClassifier = ClassifyPhoto()
+public class ClassifyPhotoPlugin : NSObject, FlutterPlugin {
+   var photoClassifier = ClassifyPhoto()
 
   public static func register(with registrar: FlutterPluginRegistrar) {
     let channel = FlutterMethodChannel(name: "classify_photo", binaryMessenger: registrar.messenger())
@@ -20,7 +19,7 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
         self.getScreenshots(flutterResult: result)
     case "getBlurryPhotos":
         self.getBlurryPhotos(flutterResult: result)
-    case "getPeoplePhotos":
+    case "getPeoplePhotos"  :
         self.getPeoplePhotos(flutterResult: result)
     case "getSimilarPhotos":
         self.getSimilarPhotos(flutterResult: result)
@@ -864,99 +863,232 @@ extension ClassifyPhotoPlugin {
 //    }
     
     private func calculatePhotosSize(assetIds: [String], completion: @escaping FlutterResult) {
+        
         // 使用与调用者相同的QoS级别
-        DispatchQueue.global(qos: .userInitiated).async {
-            let assets = PHAsset.fetchAssets(withLocalIdentifiers: assetIds, options: nil)
-            
-            // 使用原子操作确保线程安全
-            let totalSize = Atomic<Int64>(0)
-            
-            // 创建一个与调用者相同QoS的组
-            let processingGroup = DispatchGroup()
-            
-            // 创建一个与调用者相同QoS的队列,确保所有操作都有明确的QoS
-            let processingQueue = DispatchQueue(label: "com.yourapp.photosize.processing",
-                                                qos: .userInitiated,
-                                                attributes: .concurrent)
-            
-            // 控制并发数量
-            let semaphore = DispatchSemaphore(value: 4)
-            
-            // 分批处理资源
-            let batchSize = 20
-            let totalCount = assets.count
-            
-            // 如果没有资产,直接返回
-            if totalCount == 0 {
-                DispatchQueue.main.async {
-                    completion(0)
+            DispatchQueue.global(qos: .userInitiated).async {
+                let assets = PHAsset.fetchAssets(withLocalIdentifiers: assetIds, options: nil)
+                
+                // 将 PHFetchResult 转换为数组
+                var assetArray: [PHAsset] = []
+                assets.enumerateObjects { (asset, _, _) in
+                    assetArray.append(asset)
                 }
-                return
-            }
-            
-            for batchStart in stride(from: 0, to: totalCount, by: batchSize) {
-                let end = min(batchStart + batchSize, totalCount)
                 
-                processingGroup.enter()
-                // 确保使用明确QoS的队列
-                processingQueue.async {
-                    autoreleasepool {
-                        var batchSize: Int64 = 0
-                        
-                        for i in batchStart..<end {
-                            // 使用带超时的等待,避免无限期阻塞
-                            // 重要:在同一个队列中等待和信号,避免优先级反转
-                            let waitResult = semaphore.wait(timeout: .now() + 5)
-                            
-                            defer {
-                                // 确保信号量总是被释放
-                                if waitResult != .timedOut {
-                                    semaphore.signal()
-                                }
-                            }
-                            
-                            // 如果等待超时,跳过当前资源
-                            if waitResult == .timedOut {
-                                print("警告: 等待资源超时,跳过资源")
-                                continue
-                            }
-                            
-                            let asset = assets.object(at: i)
-                            
-                            // 使用资源管理器获取大小
-                            PHAssetResource.assetResources(for: asset).forEach { resource in
-                                if let fileSize = resource.value(forKey: "fileSize") as? CLong {
-                                    batchSize += Int64(fileSize)
-                                }
-                            }
-                        }
-                        
-                        // 更新总大小
-                        totalSize.mutate { $0 += batchSize }
+                // 使用 ClassifyPhoto 中的方法计算大小
+                self.photoClassifier.calculateAssetsSize(assetArray) { sizeInfo in
+                    DispatchQueue.main.async {
+                        // 返回总大小
+                        completion(sizeInfo.totalSize)
                     }
-                    
-                    processingGroup.leave()
                 }
             }
-            
-            // 使用带超时的等待,避免无限期阻塞
-            let waitResult = processingGroup.wait(timeout: .now() + 30)
-            
-            // 返回结果到主线程
-            DispatchQueue.main.async {
-                if waitResult == .timedOut {
-                    print("警告: 处理照片大小超时")
-                    completion(FlutterError(code: "TIMEOUT",
-                                            message: "计算照片大小超时",
-                                            details: nil))
-                } else {
-                    completion(totalSize.value)
-                }
-            }
-        }
+        
+//        // 使用与调用者相同的QoS级别
+//        DispatchQueue.global(qos: .userInitiated).async {
+//            let assets = PHAsset.fetchAssets(withLocalIdentifiers: assetIds, options: nil)
+//            
+//            // 如果没有资产,直接返回
+//            if assets.count == 0 {
+//                DispatchQueue.main.async {
+//                    completion(0)
+//                }
+//                return
+//            }
+//            
+//            // 使用原子操作确保线程安全
+//            let totalSize = Atomic<Int64>(0)
+//            let processedCount = Atomic<Int>(0)
+//            
+//            // 创建一个与调用者相同QoS的组
+//            let processingGroup = DispatchGroup()
+//            
+//            // 创建一个与调用者相同QoS的队列
+//            let processingQueue = DispatchQueue(label: "com.yourapp.photosize.processing",
+//                                               qos: .userInitiated,
+//                                               attributes: .concurrent)
+//            
+//            // 遍历所有资产
+//            for i in 0..<assets.count {
+//                processingGroup.enter()
+//                
+//                // 使用DispatchWorkItem明确指定QoS
+//                let workItem = DispatchWorkItem(qos: .userInitiated) {
+//                    let asset = assets.object(at: i)
+//                    
+//                    // 获取资源
+//                    let resources = PHAssetResource.assetResources(for: asset)
+//                    var assetSize: Int64 = 0
+//                    
+//                    // 计算资源大小
+//                    for resource in resources {
+//                        if let fileSize = resource.value(forKey: "fileSize") as? CLong {
+//                            assetSize += Int64(fileSize)
+//                        }
+//                    }
+//                    
+//                    // 更新总大小
+//                    totalSize.mutate { $0 += assetSize }
+//                    
+//                    // 更新处理计数
+//                    processedCount.mutate { $0 += 1 }
+//                    
+//                    processingGroup.leave()
+//                }
+//                
+//                let workItem = DispatchWorkItem(qos: .userInitiated) {
+//                    let asset = assets.object(at: i)
+//                    var assetSize: Int64 = 0
+//                    
+//                    // 获取所有相关资源
+//                    let resources = PHAssetResource.assetResources(for: asset)
+//                    
+//                    // 对每个资源使用PHAssetResourceManager获取准确大小
+//                    let resourceManager = PHAssetResourceManager.default()
+//                    let resourcesGroup = DispatchGroup()
+//                    
+//                    for resource in resources {
+//                        resourcesGroup.enter()
+//                        
+//                        // 尝试获取准确的文件大小
+//                        let options = PHAssetResourceRequestOptions()
+//                        options.isNetworkAccessAllowed = true
+//                        
+//                        resourceManager.requestDataForAssetResource(resource, options: options) { (data, _, _) in
+//                            if let data = data {
+//                                assetSize += Int64(data.count)
+//                            } else if let fileSize = resource.value(forKey: "fileSize") as? CLong {
+//                                // 回退到元数据中的大小
+//                                assetSize += Int64(fileSize)
+//                            }
+//                            resourcesGroup.leave()
+//                        }
+//                    }
+//                    
+//                    // 等待所有资源处理完成
+//                    resourcesGroup.wait()
+//                    
+//                    // 更新总大小
+//                    totalSize.mutate { $0 += assetSize }
+//                    processedCount.mutate { $0 += 1 }
+//                    
+//                    processingGroup.leave()
+//                }
+//                
+//                // 在指定QoS的队列上执行任务
+//                processingQueue.async(execute: workItem)
+//            }
+//            
+//            // 使用带超时的等待,避免无限期阻塞
+//            let waitResult = processingGroup.wait(timeout: .now() + 30)
+//            
+//            // 返回结果到主线程
+//            DispatchQueue.main.async {
+//                if waitResult == .timedOut {
+//                    print("警告: 处理照片大小超时,已处理 \(processedCount.value)/\(assets.count) 个资源")
+//                    completion(FlutterError(code: "TIMEOUT",
+//                                           message: "计算照片大小超时",
+//                                           details: nil))
+//                } else {
+//                    completion(totalSize.value)
+//                }
+//            }
+//        }
     }
     
 //    private func calculatePhotosSize(assetIds: [String], completion: @escaping FlutterResult) {
+//        // 使用与调用者相同的QoS级别
+//        DispatchQueue.global(qos: .userInitiated).async {
+//            let assets = PHAsset.fetchAssets(withLocalIdentifiers: assetIds, options: nil)
+//            
+//            // 使用原子操作确保线程安全
+//            let totalSize = Atomic<Int64>(0)
+//            
+//            // 创建一个与调用者相同QoS的组
+//            let processingGroup = DispatchGroup()
+//            
+//            // 创建一个与调用者相同QoS的队列,确保所有操作都有明确的QoS
+//            let processingQueue = DispatchQueue(label: "com.yourapp.photosize.processing",
+//                                                qos: .userInitiated,
+//                                                attributes: .concurrent)
+//            
+//            // 控制并发数量
+//            let semaphore = DispatchSemaphore(value: 4)
+//            
+//            // 分批处理资源
+//            let batchSize = 20
+//            let totalCount = assets.count
+//            
+//            // 如果没有资产,直接返回
+//            if totalCount == 0 {
+//                DispatchQueue.main.async {
+//                    completion(0)
+//                }
+//                return
+//            }
+//            
+//            for batchStart in stride(from: 0, to: totalCount, by: batchSize) {
+//                let end = min(batchStart + batchSize, totalCount)
+//                
+//                processingGroup.enter()
+//                // 确保使用明确QoS的队列
+//                processingQueue.async {
+//                    autoreleasepool {
+//                        var batchSize: Int64 = 0
+//                        
+//                        for i in batchStart..<end {
+//                            // 使用带超时的等待,避免无限期阻塞
+//                            // 重要:在同一个队列中等待和信号,避免优先级反转
+//                            let waitResult = semaphore.wait(timeout: .now() + 5)
+//                            
+//                            defer {
+//                                // 确保信号量总是被释放
+//                                if waitResult != .timedOut {
+//                                    semaphore.signal()
+//                                }
+//                            }
+//                            
+//                            // 如果等待超时,跳过当前资源
+//                            if waitResult == .timedOut {
+//                                print("警告: 等待资源超时,跳过资源")
+//                                continue
+//                            }
+//                            
+//                            let asset = assets.object(at: i)
+//                            
+//                            // 使用资源管理器获取大小
+//                            PHAssetResource.assetResources(for: asset).forEach { resource in
+//                                if let fileSize = resource.value(forKey: "fileSize") as? CLong {
+//                                    batchSize += Int64(fileSize)
+//                                }
+//                            }
+//                        }
+//                        
+//                        // 更新总大小
+//                        totalSize.mutate { $0 += batchSize }
+//                    }
+//                    
+//                    processingGroup.leave()
+//                }
+//            }
+//            
+//            // 使用带超时的等待,避免无限期阻塞
+//            let waitResult = processingGroup.wait(timeout: .now() + 30)
+//            
+//            // 返回结果到主线程
+//            DispatchQueue.main.async {
+//                if waitResult == .timedOut {
+//                    print("警告: 处理照片大小超时")
+//                    completion(FlutterError(code: "TIMEOUT",
+//                                            message: "计算照片大小超时",
+//                                            details: nil))
+//                } else {
+//                    completion(totalSize.value)
+//                }
+//            }
+//        }
+//    }
+    
+//    private func calculatePhotosSize(assetIds: [String], completion: @escaping FlutterResult) {
 //        // 使用与调用者相同的QoS级别,避免优先级反转
 //        DispatchQueue.global(qos: .userInitiated).async {
 //            let assets = PHAsset.fetchAssets(withLocalIdentifiers: assetIds, options: nil)

+ 1 - 1
pubspec.yaml

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 # In Windows, build-name is used as the major, minor, and patch parts
 # of the product and file versions while build-number is used as the build suffix.
-version: 1.4.0+36
+version: 1.4.0+39
 
 environment:
   sdk: ^3.6.0