Преглед изворни кода

Merge branch 'master' into v8

# Conflicts:
#	Kingfisher.xcodeproj/project.pbxproj
#	Tests/KingfisherTests/ImageCacheTests.swift
#	Tests/KingfisherTests/ImageDataProviderTests.swift
onevcat пре 2 година
родитељ
комит
3a46b0cd78

+ 0 - 33
.github/workflows/documentation.yaml

@@ -1,33 +0,0 @@
-name: Documentation
-
-on:
-  workflow_dispatch: {}
-  push:
-    branches:
-      - master
-    paths:
-      - .github/workflows/documentation.yaml
-      - Sources/**.swift
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v3
-      - name: Generate Documentation
-        uses: SwiftDocOrg/swift-doc@master
-        with:
-          inputs: "Sources"
-          output: "Documentation"
-          format: "html"
-          module-name: "Kingfisher"
-          base-url: "/"
-      - name: Upload Documentation Netlify
-        uses: netlify/actions/cli@master
-        with:
-          args: deploy --dir=Documentation --prod
-        env:
-          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
-          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}

+ 2 - 2
.spi.yml

@@ -1,5 +1,5 @@
 version: 1
 builder:
   configs:
-    - platform: ios
-      documentation_targets: [Kingfisher]
+    - documentation_targets: [Kingfisher]
+      custom_documentation_parameters: [--include-extended-types]

+ 14 - 0
CHANGELOG.md

@@ -2,6 +2,20 @@
 
 -----
 
+## [7.10.0 - Privacy Manifest](https://github.com/onevcat/Kingfisher/releases/tag/7.10.0) (2023-10-29)
+
+#### Add
+* Actually add the privacy manifest files to the xcframework, Swift Package Manager and CocoaPods. [#2122](https://github.com/onevcat/Kingfisher/issues/2122)[#2156](https://github.com/onevcat/Kingfisher/pull/2156) @CloudosaurusRex @NikcN22
+* Enable the modulemap generation and `-Swift.h` header again for ObjC compatibility. [#2138](https://github.com/onevcat/Kingfisher/pull/2138) @yev-kanivets
+
+#### Fix
+* Use the trait collection to determine animated image scale, instead of the deprecated `UIScreen` API. [#2157](https://github.com/onevcat/Kingfisher/pull/2157) @hyun99999
+* An issue that a local AV asset creates multiple disk caches when connected to Xcode during Debug phase. [#2158](https://github.com/onevcat/Kingfisher/pull/2157) @onevcat @elijahdou
+* The disk cache now is still availiable when the whole cache folder is removed by external operations instead of the methods in Kingfisher. [#2162](https://github.com/onevcat/Kingfisher/pull/2162) @onevcat @uclort
+* Some documentation and CI impro/vements.
+
+---
+
 ## [7.9.1 - Lastest Xcode 15 beta](https://github.com/onevcat/Kingfisher/releases/tag/7.9.1) (2023-08-26)
 
 #### Fix

+ 39 - 29
Gemfile.lock

@@ -3,10 +3,15 @@ GEM
   specs:
     CFPropertyList (3.0.6)
       rexml
-    activesupport (7.0.7.2)
+    activesupport (7.1.1)
+      base64
+      bigdecimal
       concurrent-ruby (~> 1.0, >= 1.0.2)
+      connection_pool (>= 2.2.5)
+      drb
       i18n (>= 1.6, < 2)
       minitest (>= 5.1)
+      mutex_m
       tzinfo (~> 2.0)
     addressable (2.8.5)
       public_suffix (>= 2.0.2, < 6.0)
@@ -16,29 +21,31 @@ GEM
     artifactory (3.0.15)
     atomos (0.1.3)
     aws-eventstream (1.2.0)
-    aws-partitions (1.812.0)
-    aws-sdk-core (3.181.0)
+    aws-partitions (1.843.0)
+    aws-sdk-core (3.185.1)
       aws-eventstream (~> 1, >= 1.0.2)
       aws-partitions (~> 1, >= 1.651.0)
       aws-sigv4 (~> 1.5)
       jmespath (~> 1, >= 1.6.1)
-    aws-sdk-kms (1.71.0)
-      aws-sdk-core (~> 3, >= 3.177.0)
+    aws-sdk-kms (1.72.0)
+      aws-sdk-core (~> 3, >= 3.184.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.134.0)
+    aws-sdk-s3 (1.136.0)
       aws-sdk-core (~> 3, >= 3.181.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.6)
-    aws-sigv4 (1.6.0)
+    aws-sigv4 (1.6.1)
       aws-eventstream (~> 1, >= 1.0.2)
     babosa (1.0.4)
+    base64 (0.1.1)
+    bigdecimal (3.1.4)
     claide (1.1.0)
-    cocoapods (1.12.1)
+    cocoapods (1.14.2)
       addressable (~> 2.8)
       claide (>= 1.0.2, < 2.0)
-      cocoapods-core (= 1.12.1)
+      cocoapods-core (= 1.14.2)
       cocoapods-deintegrate (>= 1.0.3, < 2.0)
-      cocoapods-downloader (>= 1.6.0, < 2.0)
+      cocoapods-downloader (>= 2.0)
       cocoapods-plugins (>= 1.0.0, < 2.0)
       cocoapods-search (>= 1.0.0, < 2.0)
       cocoapods-trunk (>= 1.6.0, < 2.0)
@@ -50,8 +57,8 @@ GEM
       molinillo (~> 0.8.0)
       nap (~> 1.0)
       ruby-macho (>= 2.3.0, < 3.0)
-      xcodeproj (>= 1.21.0, < 2.0)
-    cocoapods-core (1.12.1)
+      xcodeproj (>= 1.23.0, < 2.0)
+    cocoapods-core (1.14.2)
       activesupport (>= 5.0, < 8)
       addressable (~> 2.8)
       algoliasearch (~> 1.0)
@@ -62,7 +69,7 @@ GEM
       public_suffix (~> 4.0)
       typhoeus (~> 1.0)
     cocoapods-deintegrate (1.0.5)
-    cocoapods-downloader (1.6.3)
+    cocoapods-downloader (2.0)
     cocoapods-plugins (1.0.0)
       nap
     cocoapods-search (1.0.1)
@@ -75,17 +82,20 @@ GEM
     commander (4.6.0)
       highline (~> 2.0.0)
     concurrent-ruby (1.2.2)
+    connection_pool (2.4.1)
     declarative (0.0.20)
     digest-crc (0.6.5)
       rake (>= 12.0.0, < 14.0.0)
     domain_name (0.5.20190701)
       unf (>= 0.0.5, < 1.0.0)
     dotenv (2.8.1)
+    drb (2.1.1)
+      ruby2_keywords
     emoji_regex (3.2.3)
     escape (0.0.4)
     ethon (0.16.0)
       ffi (>= 1.15.0)
-    excon (0.102.0)
+    excon (0.104.0)
     faraday (1.10.3)
       faraday-em_http (~> 1.0)
       faraday-em_synchrony (~> 1.0)
@@ -115,7 +125,7 @@ GEM
     faraday_middleware (1.2.0)
       faraday (~> 1.0)
     fastimage (2.2.7)
-    fastlane (2.214.0)
+    fastlane (2.216.0)
       CFPropertyList (>= 2.3, < 4.0.0)
       addressable (>= 2.8, < 3.0.0)
       artifactory (~> 3.0)
@@ -136,6 +146,7 @@ GEM
       google-apis-playcustomapp_v1 (~> 0.1)
       google-cloud-storage (~> 1.31)
       highline (~> 2.0)
+      http-cookie (~> 1.0.5)
       json (< 3.0.0)
       jwt (>= 2.1.0, < 3)
       mini_magick (>= 4.9.4, < 5.0.0)
@@ -147,20 +158,20 @@ GEM
       security (= 0.1.3)
       simctl (~> 1.6.3)
       terminal-notifier (>= 2.0.0, < 3.0.0)
-      terminal-table (>= 1.4.5, < 2.0.0)
+      terminal-table (~> 3)
       tty-screen (>= 0.6.3, < 1.0.0)
       tty-spinner (>= 0.8.0, < 1.0.0)
       word_wrap (~> 1.0.0)
       xcodeproj (>= 1.13.0, < 2.0.0)
       xcpretty (~> 0.3.0)
       xcpretty-travis-formatter (>= 0.0.3)
-    ffi (1.15.5)
+    ffi (1.16.3)
     fourflusher (2.3.1)
     fuzzy_match (2.0.4)
     gh_inspector (1.1.3)
-    google-apis-androidpublisher_v3 (0.48.0)
+    google-apis-androidpublisher_v3 (0.51.0)
       google-apis-core (>= 0.11.0, < 2.a)
-    google-apis-core (0.11.1)
+    google-apis-core (0.11.2)
       addressable (~> 2.5, >= 2.5.1)
       googleauth (>= 0.16.2, < 2.a)
       httpclient (>= 2.8.1, < 3.a)
@@ -189,10 +200,9 @@ GEM
       google-cloud-core (~> 1.6)
       googleauth (>= 0.16.2, < 2.a)
       mini_mime (~> 1.0)
-    googleauth (1.7.0)
+    googleauth (1.8.1)
       faraday (>= 0.17.3, < 3.a)
       jwt (>= 1.4, < 3.0)
-      memoist (~> 0.16)
       multi_json (~> 1.11)
       os (>= 0.9, < 2.0)
       signet (>= 0.16, < 2.a)
@@ -205,13 +215,13 @@ GEM
     jmespath (1.6.2)
     json (2.6.3)
     jwt (2.7.1)
-    memoist (0.16.2)
     mini_magick (4.12.0)
     mini_mime (1.1.5)
-    minitest (5.19.0)
+    minitest (5.20.0)
     molinillo (0.8.0)
     multi_json (1.15.0)
     multipart-post (2.3.0)
+    mutex_m (0.1.2)
     nanaimo (0.3.0)
     nap (1.1.0)
     naturally (2.2.1)
@@ -220,7 +230,7 @@ GEM
     os (1.1.4)
     plist (3.7.0)
     public_suffix (4.0.7)
-    rake (13.0.6)
+    rake (13.1.0)
     representable (3.2.0)
       declarative (< 0.1.0)
       trailblazer-option (>= 0.1.1, < 0.2.0)
@@ -232,7 +242,7 @@ GEM
     ruby2_keywords (0.0.5)
     rubyzip (2.3.2)
     security (0.1.3)
-    signet (0.17.0)
+    signet (0.18.0)
       addressable (~> 2.8)
       faraday (>= 0.17.5, < 3.a)
       jwt (>= 1.5, < 3.0)
@@ -241,8 +251,8 @@ GEM
       CFPropertyList
       naturally
     terminal-notifier (2.0.0)
-    terminal-table (1.8.0)
-      unicode-display_width (~> 1.1, >= 1.1.1)
+    terminal-table (3.0.2)
+      unicode-display_width (>= 1.1.1, < 3)
     trailblazer-option (0.1.2)
     tty-cursor (0.7.1)
     tty-screen (0.8.1)
@@ -256,13 +266,13 @@ GEM
     unf (0.1.4)
       unf_ext
     unf_ext (0.0.8.2)
-    unicode-display_width (1.8.0)
+    unicode-display_width (2.5.0)
     webrick (1.8.1)
     word_wrap (1.0.0)
     xcode-install (2.8.1)
       claide (>= 0.9.1)
       fastlane (>= 2.1.0, < 3.0.0)
-    xcodeproj (1.22.0)
+    xcodeproj (1.23.0)
       CFPropertyList (>= 2.3.3, < 4.0)
       atomos (~> 0.1.3)
       claide (>= 1.0.2, < 2.0)

+ 2 - 1
Kingfisher.podspec

@@ -1,7 +1,7 @@
 Pod::Spec.new do |s|
 
   s.name         = "Kingfisher"
-  s.version      = "7.9.1"
+  s.version      = "7.10.0"
   s.summary      = "A lightweight and pure Swift implemented library for downloading and cacheing image from the web."
 
   s.description  = <<-DESC
@@ -36,6 +36,7 @@ Pod::Spec.new do |s|
 
   s.source       = { :git => "https://github.com/onevcat/Kingfisher.git", :tag => s.version }
   s.source_files  = ["Sources/**/*.swift"]
+  s.resource_bundles = {"Kingfisher" => ["Sources/PrivacyInfo.xcprivacy"]}
 
   s.requires_arc = true
   s.frameworks = "CFNetwork", "Accelerate"

+ 24 - 6
Kingfisher.xcodeproj/project.pbxproj

@@ -110,6 +110,7 @@
 		D1BA781D2174D07800C69D7B /* CallbackQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1BA781C2174D07800C69D7B /* CallbackQueue.swift */; };
 		D1BFED95222ACC6B009330C8 /* ImageProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1BFED94222ACC6B009330C8 /* ImageProcessorTests.swift */; };
 		D1D2C32A1C70A3230018F2F9 /* single-frame.gif in Resources */ = {isa = PBXBuildFile; fileRef = D1D2C3291C70A3230018F2F9 /* single-frame.gif */; };
+		D1D550D52AEB9E8700AAD79D /* PrivacyInfo.xcprivacy in CopyFiles */ = {isa = PBXBuildFile; fileRef = D1C04A3E2A45D20500B3775F /* PrivacyInfo.xcprivacy */; };
 		D1DC4B411D60996D00DFDFAA /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1DC4B401D60996D00DFDFAA /* StringExtensionTests.swift */; };
 		D1E564412199C21E0057AAE3 /* StorageExpirationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1E564402199C21E0057AAE3 /* StorageExpirationTests.swift */; };
 		D1E56445219B16330057AAE3 /* ImageDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1E56444219B16330057AAE3 /* ImageDataProvider.swift */; };
@@ -131,6 +132,19 @@
 		};
 /* End PBXContainerItemProxy section */
 
+/* Begin PBXCopyFilesBuildPhase section */
+		D1D550D42AEB9E7300AAD79D /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 7;
+			files = (
+				D1D550D52AEB9E8700AAD79D /* PrivacyInfo.xcprivacy in CopyFiles */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
 /* Begin PBXFileReference section */
 		07292244263B02F00089E810 /* KFAnimatedImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KFAnimatedImage.swift; sourceTree = "<group>"; };
 		185218B51CC07F8300BD58DE /* NSButtonExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSButtonExtensionTests.swift; sourceTree = "<group>"; };
@@ -703,6 +717,7 @@
 			buildConfigurationList = D1ED2D4E1AD2D09F00CFC3EB /* Build configuration list for PBXNativeTarget "Kingfisher" */;
 			buildPhases = (
 				D1ED2D301AD2D09F00CFC3EB /* Sources */,
+				D1D550D42AEB9E7300AAD79D /* CopyFiles */,
 				D1ED2D311AD2D09F00CFC3EB /* Frameworks */,
 				D1ED2D321AD2D09F00CFC3EB /* Headers */,
 			);
@@ -1065,10 +1080,11 @@
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
 				CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
 				CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
-				CURRENT_PROJECT_VERSION = 2624;
+				CURRENT_PROJECT_VERSION = 2664;
+				DEFINES_MODULE = YES;
 				DEAD_CODE_STRIPPING = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 2639;
+				DYLIB_CURRENT_VERSION = 2664;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
 				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
@@ -1101,6 +1117,7 @@
 				SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
 				SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_INSTALL_OBJC_HEADER = YES;
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 				TARGETED_DEVICE_FAMILY = "1,2,3,4,7";
 				VERSIONING_SYSTEM = "apple-generic";
@@ -1124,10 +1141,11 @@
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
 				CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
 				CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
-				CURRENT_PROJECT_VERSION = 2624;
+				CURRENT_PROJECT_VERSION = 2664;
+				DEFINES_MODULE = YES;
 				DEAD_CODE_STRIPPING = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
-				DYLIB_CURRENT_VERSION = 2639;
+				DYLIB_CURRENT_VERSION = 2664;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
 				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
@@ -1159,8 +1177,8 @@
 				SUPPORTS_MACCATALYST = NO;
 				SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
 				SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
-				SWIFT_COMPILATION_MODE = wholemodule;
-				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_INSTALL_OBJC_HEADER = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 				TARGETED_DEVICE_FAMILY = "1,2,3,4,7";
 				VERSIONING_SYSTEM = "apple-generic";
 			};

+ 2 - 1
Package@swift-5.9.swift

@@ -16,7 +16,8 @@ let package = Package(
     targets: [
         .target(
             name: "Kingfisher",
-            path: "Sources"
+            path: "Sources",
+            resources: [.copy("PrivacyInfo.xcprivacy")]
         )
     ]
 )

+ 31 - 3
Sources/Cache/DiskStorage.swift

@@ -161,9 +161,21 @@ public enum DiskStorage {
             do {
                 try data.write(to: fileURL, options: writeOptions)
             } catch {
-                throw KingfisherError.cacheError(
-                    reason: .cannotCreateCacheFile(fileURL: fileURL, key: key, data: data, error: error)
-                )
+                if error.isFolderMissing {
+                    // The whole cache folder is deleted. Try to recreate it and write file again.
+                    do {
+                        try prepareDirectory()
+                        try data.write(to: fileURL, options: writeOptions)
+                    } catch {
+                        throw KingfisherError.cacheError(
+                            reason: .cannotCreateCacheFile(fileURL: fileURL, key: key, data: data, error: error)
+                        )
+                    }
+                } else {
+                    throw KingfisherError.cacheError(
+                        reason: .cannotCreateCacheFile(fileURL: fileURL, key: key, data: data, error: error)
+                    )
+                }
             }
 
             let now = Date()
@@ -613,3 +625,19 @@ extension DiskStorage {
         }
     }
 }
+
+fileprivate extension Error {
+    var isFolderMissing: Bool {
+        let nsError = self as NSError
+        guard nsError.domain == NSCocoaErrorDomain, nsError.code == 4 else {
+            return false
+        }
+        guard let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? NSError else {
+            return false
+        }
+        guard underlyingError.domain == NSPOSIXErrorDomain, underlyingError.code == 2 else {
+            return false
+        }
+        return true
+    }
+}

+ 4 - 1
Sources/General/ImageSource/AVAssetImageDataProvider.swift

@@ -54,7 +54,10 @@ public struct AVAssetImageDataProvider: ImageDataProvider {
     public let time: CMTime
 
     private var internalKey: String {
-        return (assetImageGenerator.asset as? AVURLAsset)?.url.absoluteString ?? UUID().uuidString
+        guard let url = (assetImageGenerator.asset as? AVURLAsset)?.url else {
+            return UUID().uuidString
+        }
+        return url.cacheKey
     }
 
     /// The cache key used by `self`.

+ 2 - 2
Sources/Info.plist

@@ -15,11 +15,11 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>7.9.1</string>
+	<string>7.10.0</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>2639</string>
+	<string>2664</string>
 	<key>NSPrincipalClass</key>
 	<string></string>
 </dict>

+ 8 - 1
Sources/Views/AnimatedImageView.swift

@@ -283,7 +283,14 @@ open class AnimatedImageView: UIImageView {
             #if os(visionOS)
             let targetSize = bounds.scaled(UITraitCollection.current.displayScale).size
             #else
-            let targetSize = bounds.scaled(UIScreen.main.scale).size
+            var scale: CGFloat = 0
+            
+            if #available(iOS 13.0, tvOS 13.0, *) {
+                scale = UITraitCollection.current.displayScale
+            } else {
+                scale = UIScreen.main.scale
+            }
+            let targetSize = bounds.scaled(scale).size
             #endif
             let animator = Animator(
                 frameSource: frameSource,

+ 62 - 0
Tests/KingfisherTests/ImageCacheTests.swift

@@ -672,6 +672,68 @@ class ImageCacheTests: XCTestCase {
         }
         waitForExpectations(timeout: 3, handler: nil)
     }
+    
+    func testDiskCacheStillWorkWhenFolderDeletedExternally() {
+        let exp = expectation(description: #function)
+        let key = testKeys[0]
+        let url = URL(string: key)!
+        
+        let exists = cache.imageCachedType(forKey: url.cacheKey)
+        XCTAssertEqual(exists, .none)
+        
+        cache.store(testImage, forKey: key, toDisk: true) { _ in
+            self.cache.retrieveImage(forKey: key) { result in
+
+                XCTAssertNotNil(result.value?.image)
+                XCTAssertEqual(result.value?.cacheType, .memory)
+
+                self.cache.clearMemoryCache()
+                self.cache.retrieveImage(forKey: key) { result in
+                    XCTAssertNotNil(result.value?.image)
+                    XCTAssertEqual(result.value?.cacheType, .disk)
+                    self.cache.clearMemoryCache()
+                    
+                    try! FileManager.default.removeItem(at: self.cache.diskStorage.directoryURL)
+                    
+                    let exists = self.cache.imageCachedType(forKey: url.cacheKey)
+                    XCTAssertEqual(exists, .none)
+                    
+                    self.cache.store(testImage, forKey: key, toDisk: true) { _ in
+                        self.cache.clearMemoryCache()
+                        let cacheType = self.cache.imageCachedType(forKey: url.cacheKey)
+                        XCTAssertEqual(cacheType, .disk)
+                        exp.fulfill()
+                    }
+                }
+            }
+        }
+        
+        waitForExpectations(timeout: 3, handler: nil)
+    }
+    
+    func testDiskCacheCalculateSizeWhenFolderDeletedExternally() {
+        let exp = expectation(description: #function)
+        
+        let key = testKeys[0]
+        
+        cache.calculateDiskStorageSize { result in
+            XCTAssertEqual(result.value, 0)
+            
+            self.cache.store(testImage, forKey: key, toDisk: true) { _ in
+                self.cache.calculateDiskStorageSize { result in
+                    XCTAssertEqual(result.value, UInt(testImagePNGData.count))
+                    
+                    try! FileManager.default.removeItem(at: self.cache.diskStorage.directoryURL)
+                    self.cache.calculateDiskStorageSize { result in
+                        XCTAssertEqual(result.value, 0)
+                        exp.fulfill()
+                    }
+                    
+                }
+            }
+        }
+        waitForExpectations(timeout: 3, handler: nil)
+    }
 
     func testCalculateDiskStorageSizeAsync() async throws {
         let size = try await cache.diskStorageSize

+ 24 - 0
Tests/KingfisherTests/ImageDataProviderTests.swift

@@ -87,6 +87,30 @@ class ImageDataProviderTests: XCTestCase {
 
         XCTAssertTrue(called)
     }
+    
+    func testAVAssetImageDataProviderCacheKeyVariesForRemote() {
+        let remoteURL1 = URL(string: "https://example.com/1/hello.mp4")!
+        let remoteURL2 = URL(string: "https://example.com/2/hello.mp4")!
+        
+        let provider1 = AVAssetImageDataProvider(assetURL: remoteURL1, seconds: 10)
+        XCTAssertEqual(provider1.cacheKey, "https://example.com/1/hello.mp4_10.0")
+        
+        let provider2 = AVAssetImageDataProvider(assetURL: remoteURL2, seconds: 10)
+        XCTAssertNotEqual(provider1.cacheKey, provider2.cacheKey)
+    }
+    
+    // AVAssetImageDataProvider fix for appending to #1825
+    func testAVAssetImageDataProviderCacheKeyConsistForDifferentAppSandbox() {
+        let localURL1 = URL(string: "file:///Users/onevcat/Library/Developer/CoreSimulator/Devices/ABC/data/Containers/Bundle/Application/DEF/Kingfisher-Demo.app/video/hello.mp4")!
+        let localURL2 = URL(string: "file:///Users/onevcat/Library/Developer/CoreSimulator/Devices/ABC/data/Containers/Bundle/Application/XYZ/Kingfisher-Demo.app/video/hello.mp4")!
+        
+        let provider1 = AVAssetImageDataProvider(assetURL: localURL1, seconds: 10)
+        XCTAssertEqual(provider1.cacheKey, "\(URL.localFileCacheKeyPrefix)/Kingfisher-Demo.app/video/hello.mp4_10.0")
+    
+        let provider2 = AVAssetImageDataProvider(assetURL: localURL2, seconds: 10)
+        XCTAssertEqual(provider1.cacheKey, provider2.cacheKey)
+    }
+    
 
     func testLocalFileImageDataProviderMainQueueAsync() async {
         let fm = FileManager.default

+ 2 - 2
Tests/KingfisherTests/Info.plist

@@ -15,10 +15,10 @@
 	<key>CFBundlePackageType</key>
 	<string>BNDL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>7.9.1</string>
+	<string>7.10.0</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>2639</string>
+	<string>2664</string>
 </dict>
 </plist>

+ 2 - 4
fastlane/Fastfile

@@ -41,9 +41,7 @@ platform :ios do
 
   desc "Lint"
   lane :lint do
-    # Allows warnings temporarily before CocoaPods 1.13.0 (visionOS support) and Xcode 15.0
-    # pod_lib_lint
-    pod_lib_lint(allow_warnings: true)
+    pod_lib_lint
     spm
   end
   
@@ -83,7 +81,7 @@ platform :ios do
       upload_assets: ["build/Kingfisher-#{target_version}.zip"]
     )
     
-    pod_push(allow_warnings: true)
+    pod_push
   end
 
   lane :xcframework do |options|