mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	fix: ios skip posting hash response after detached from engine (#22695)
* skip posting message after detached from engine * review changes * cancel plugin before destroying engine --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
		
							parent
							
								
									46869f664d
								
							
						
					
					
						commit
						cf52b879b1
					
				@ -131,10 +131,13 @@
 | 
				
			|||||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
 | 
					/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
 | 
					/* Begin PBXFileSystemSynchronizedRootGroup section */
 | 
				
			||||||
 | 
							B231F52D2E93A44A00BC45D1 /* Core */ = {
 | 
				
			||||||
 | 
								isa = PBXFileSystemSynchronizedRootGroup;
 | 
				
			||||||
 | 
								path = Core;
 | 
				
			||||||
 | 
								sourceTree = "<group>";
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
		B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
 | 
							B2CF7F8C2DDE4EBB00744BF6 /* Sync */ = {
 | 
				
			||||||
			isa = PBXFileSystemSynchronizedRootGroup;
 | 
								isa = PBXFileSystemSynchronizedRootGroup;
 | 
				
			||||||
			exceptions = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			path = Sync;
 | 
								path = Sync;
 | 
				
			||||||
			sourceTree = "<group>";
 | 
								sourceTree = "<group>";
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
@ -247,6 +250,7 @@
 | 
				
			|||||||
		97C146F01CF9000F007C117D /* Runner */ = {
 | 
							97C146F01CF9000F007C117D /* Runner */ = {
 | 
				
			||||||
			isa = PBXGroup;
 | 
								isa = PBXGroup;
 | 
				
			||||||
			children = (
 | 
								children = (
 | 
				
			||||||
 | 
									B231F52D2E93A44A00BC45D1 /* Core */,
 | 
				
			||||||
				B25D37792E72CA15008B6CA7 /* Connectivity */,
 | 
									B25D37792E72CA15008B6CA7 /* Connectivity */,
 | 
				
			||||||
				B21E34A62E5AF9760031FDB9 /* Background */,
 | 
									B21E34A62E5AF9760031FDB9 /* Background */,
 | 
				
			||||||
				B2CF7F8C2DDE4EBB00744BF6 /* Sync */,
 | 
									B2CF7F8C2DDE4EBB00744BF6 /* Sync */,
 | 
				
			||||||
@ -331,6 +335,7 @@
 | 
				
			|||||||
				F0B57D482DF764BE00DC5BCC /* PBXTargetDependency */,
 | 
									F0B57D482DF764BE00DC5BCC /* PBXTargetDependency */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			fileSystemSynchronizedGroups = (
 | 
								fileSystemSynchronizedGroups = (
 | 
				
			||||||
 | 
									B231F52D2E93A44A00BC45D1 /* Core */,
 | 
				
			||||||
				B2CF7F8C2DDE4EBB00744BF6 /* Sync */,
 | 
									B2CF7F8C2DDE4EBB00744BF6 /* Sync */,
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			name = Runner;
 | 
								name = Runner;
 | 
				
			||||||
@ -521,10 +526,14 @@
 | 
				
			|||||||
			inputFileListPaths = (
 | 
								inputFileListPaths = (
 | 
				
			||||||
				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
 | 
									"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
								inputPaths = (
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
			name = "[CP] Copy Pods Resources";
 | 
								name = "[CP] Copy Pods Resources";
 | 
				
			||||||
			outputFileListPaths = (
 | 
								outputFileListPaths = (
 | 
				
			||||||
				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
 | 
									"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
								outputPaths = (
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
								runOnlyForDeploymentPostprocessing = 0;
 | 
				
			||||||
			shellPath = /bin/sh;
 | 
								shellPath = /bin/sh;
 | 
				
			||||||
			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
 | 
								shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
 | 
				
			||||||
@ -553,10 +562,14 @@
 | 
				
			|||||||
			inputFileListPaths = (
 | 
								inputFileListPaths = (
 | 
				
			||||||
				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 | 
									"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
								inputPaths = (
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
			name = "[CP] Embed Pods Frameworks";
 | 
								name = "[CP] Embed Pods Frameworks";
 | 
				
			||||||
			outputFileListPaths = (
 | 
								outputFileListPaths = (
 | 
				
			||||||
				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 | 
									"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
								outputPaths = (
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
								runOnlyForDeploymentPostprocessing = 0;
 | 
				
			||||||
			shellPath = /bin/sh;
 | 
								shellPath = /bin/sh;
 | 
				
			||||||
			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
 | 
								shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ import UIKit
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    GeneratedPluginRegistrant.register(with: self)
 | 
					    GeneratedPluginRegistrant.register(with: self)
 | 
				
			||||||
    let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
 | 
					    let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
 | 
				
			||||||
    AppDelegate.registerPlugins(binaryMessenger: controller.binaryMessenger)
 | 
					    AppDelegate.registerPlugins(with: controller.engine)
 | 
				
			||||||
    BackgroundServicePlugin.register(with: self.registrar(forPlugin: "BackgroundServicePlugin")!)
 | 
					    BackgroundServicePlugin.register(with: self.registrar(forPlugin: "BackgroundServicePlugin")!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    BackgroundServicePlugin.registerBackgroundProcessing()
 | 
					    BackgroundServicePlugin.registerBackgroundProcessing()
 | 
				
			||||||
@ -51,9 +51,13 @@ import UIKit
 | 
				
			|||||||
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
 | 
					    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  public static func registerPlugins(binaryMessenger: FlutterBinaryMessenger) {
 | 
					  public static func registerPlugins(with engine: FlutterEngine) {
 | 
				
			||||||
    NativeSyncApiSetup.setUp(binaryMessenger: binaryMessenger, api: NativeSyncApiImpl())
 | 
					    NativeSyncApiImpl.register(with: engine.registrar(forPlugin: NativeSyncApiImpl.name)!)
 | 
				
			||||||
    ThumbnailApiSetup.setUp(binaryMessenger: binaryMessenger, api: ThumbnailApiImpl())
 | 
					    ThumbnailApiSetup.setUp(binaryMessenger: engine.binaryMessenger, api: ThumbnailApiImpl())
 | 
				
			||||||
    BackgroundWorkerFgHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: BackgroundWorkerApiImpl())
 | 
					    BackgroundWorkerFgHostApiSetup.setUp(binaryMessenger: engine.binaryMessenger, api: BackgroundWorkerApiImpl())
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  public static func cancelPlugins(with engine: FlutterEngine) {
 | 
				
			||||||
 | 
					    (engine.valuePublished(byPlugin: NativeSyncApiImpl.name) as? NativeSyncApiImpl)?.detachFromEngine()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -95,7 +95,7 @@ class BackgroundWorker: BackgroundWorkerBgHostApi {
 | 
				
			|||||||
    // Register plugins in the new engine
 | 
					    // Register plugins in the new engine
 | 
				
			||||||
    GeneratedPluginRegistrant.register(with: engine)
 | 
					    GeneratedPluginRegistrant.register(with: engine)
 | 
				
			||||||
    // Register custom plugins
 | 
					    // Register custom plugins
 | 
				
			||||||
    AppDelegate.registerPlugins(binaryMessenger: engine.binaryMessenger)
 | 
					    AppDelegate.registerPlugins(with: engine)
 | 
				
			||||||
    flutterApi = BackgroundWorkerFlutterApi(binaryMessenger: engine.binaryMessenger)
 | 
					    flutterApi = BackgroundWorkerFlutterApi(binaryMessenger: engine.binaryMessenger)
 | 
				
			||||||
    BackgroundWorkerBgHostApiSetup.setUp(binaryMessenger: engine.binaryMessenger, api: self)
 | 
					    BackgroundWorkerBgHostApiSetup.setUp(binaryMessenger: engine.binaryMessenger, api: self)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@ -168,6 +168,7 @@ class BackgroundWorker: BackgroundWorkerBgHostApi {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    isComplete = true
 | 
					    isComplete = true
 | 
				
			||||||
 | 
					    AppDelegate.cancelPlugins(with: engine)
 | 
				
			||||||
    engine.destroyContext()
 | 
					    engine.destroyContext()
 | 
				
			||||||
    flutterApi = nil
 | 
					    flutterApi = nil
 | 
				
			||||||
    completionHandler(success)
 | 
					    completionHandler(success)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								mobile/ios/Runner/Core/ImmichPlugin.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								mobile/ios/Runner/Core/ImmichPlugin.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					class ImmichPlugin: NSObject {
 | 
				
			||||||
 | 
					  var detached: Bool
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  override init() {
 | 
				
			||||||
 | 
					    detached = false
 | 
				
			||||||
 | 
					    super.init()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  func detachFromEngine() {
 | 
				
			||||||
 | 
					    self.detached = true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  func completeWhenActive<T>(for completion: @escaping (T) -> Void, with value: T) {
 | 
				
			||||||
 | 
					    guard !self.detached else { return }
 | 
				
			||||||
 | 
					    completion(value)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -17,13 +17,25 @@ struct AssetWrapper: Hashable, Equatable {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NativeSyncApiImpl: NativeSyncApi {
 | 
					class NativeSyncApiImpl: ImmichPlugin, NativeSyncApi, FlutterPlugin {
 | 
				
			||||||
 | 
					  static let name = "NativeSyncApi"
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  static func register(with registrar: any FlutterPluginRegistrar) {
 | 
				
			||||||
 | 
					    let instance = NativeSyncApiImpl()
 | 
				
			||||||
 | 
					    NativeSyncApiSetup.setUp(binaryMessenger: registrar.messenger(), api: instance)
 | 
				
			||||||
 | 
					    registrar.publish(instance)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  func detachFromEngine(for registrar: any FlutterPluginRegistrar) {
 | 
				
			||||||
 | 
					    super.detachFromEngine()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  private let defaults: UserDefaults
 | 
					  private let defaults: UserDefaults
 | 
				
			||||||
  private let changeTokenKey = "immich:changeToken"
 | 
					  private let changeTokenKey = "immich:changeToken"
 | 
				
			||||||
  private let albumTypes: [PHAssetCollectionType] = [.album, .smartAlbum]
 | 
					  private let albumTypes: [PHAssetCollectionType] = [.album, .smartAlbum]
 | 
				
			||||||
  private let recoveredAlbumSubType = 1000000219
 | 
					  private let recoveredAlbumSubType = 1000000219
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  private var hashTask: Task<Void, Error>?
 | 
					  private var hashTask: Task<Void?, Error>?
 | 
				
			||||||
  private static let hashCancelledCode = "HASH_CANCELLED"
 | 
					  private static let hashCancelledCode = "HASH_CANCELLED"
 | 
				
			||||||
  private static let hashCancelled = Result<[HashResult], Error>.failure(PigeonError(code: hashCancelledCode, message: "Hashing cancelled", details: nil))
 | 
					  private static let hashCancelled = Result<[HashResult], Error>.failure(PigeonError(code: hashCancelledCode, message: "Hashing cancelled", details: nil))
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
@ -272,7 +284,7 @@ class NativeSyncApiImpl: NativeSyncApi {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      if Task.isCancelled {
 | 
					      if Task.isCancelled {
 | 
				
			||||||
        return completion(Self.hashCancelled)
 | 
					        return self?.completeWhenActive(for: completion, with: Self.hashCancelled)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
      await withTaskGroup(of: HashResult?.self) { taskGroup in
 | 
					      await withTaskGroup(of: HashResult?.self) { taskGroup in
 | 
				
			||||||
@ -280,7 +292,7 @@ class NativeSyncApiImpl: NativeSyncApi {
 | 
				
			|||||||
        results.reserveCapacity(assets.count)
 | 
					        results.reserveCapacity(assets.count)
 | 
				
			||||||
        for asset in assets {
 | 
					        for asset in assets {
 | 
				
			||||||
          if Task.isCancelled {
 | 
					          if Task.isCancelled {
 | 
				
			||||||
            return completion(Self.hashCancelled)
 | 
					            return self?.completeWhenActive(for: completion, with: Self.hashCancelled)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          taskGroup.addTask {
 | 
					          taskGroup.addTask {
 | 
				
			||||||
            guard let self = self else { return nil }
 | 
					            guard let self = self else { return nil }
 | 
				
			||||||
@ -290,7 +302,7 @@ class NativeSyncApiImpl: NativeSyncApi {
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        for await result in taskGroup {
 | 
					        for await result in taskGroup {
 | 
				
			||||||
          guard let result = result else {
 | 
					          guard let result = result else {
 | 
				
			||||||
            return completion(Self.hashCancelled)
 | 
					            return self?.completeWhenActive(for: completion, with: Self.hashCancelled)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          results.append(result)
 | 
					          results.append(result)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -299,7 +311,7 @@ class NativeSyncApiImpl: NativeSyncApi {
 | 
				
			|||||||
          results.append(HashResult(assetId: missing, error: "Asset not found in library", hash: nil))
 | 
					          results.append(HashResult(assetId: missing, error: "Asset not found in library", hash: nil))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        completion(.success(results))
 | 
					        return self?.completeWhenActive(for: completion, with: .success(results))
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -192,6 +192,7 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
 | 
				
			|||||||
      _cancellationToken.cancel();
 | 
					      _cancellationToken.cancel();
 | 
				
			||||||
      _logger.info("Cleaning up background worker");
 | 
					      _logger.info("Cleaning up background worker");
 | 
				
			||||||
      final cleanupFutures = [
 | 
					      final cleanupFutures = [
 | 
				
			||||||
 | 
					        nativeSyncApi?.cancelHashing(),
 | 
				
			||||||
        workerManager.dispose().catchError((_) async {
 | 
					        workerManager.dispose().catchError((_) async {
 | 
				
			||||||
          // Discard any errors on the dispose call
 | 
					          // Discard any errors on the dispose call
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
@ -201,7 +202,6 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
 | 
				
			|||||||
        _drift.close(),
 | 
					        _drift.close(),
 | 
				
			||||||
        _driftLogger.close(),
 | 
					        _driftLogger.close(),
 | 
				
			||||||
        backgroundSyncManager?.cancel(),
 | 
					        backgroundSyncManager?.cancel(),
 | 
				
			||||||
        nativeSyncApi?.cancelHashing(),
 | 
					 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (_isar.isOpen) {
 | 
					      if (_isar.isOpen) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user