Skip to content

Commit 7cbb052

Browse files
authored
Merge pull request #654 from dreampiggy/refactory_storage_sdwebimage_binding_5_api
Refactory the FirebaseUI-Storage binding of SDWebImage using the 5.0 modern Custom Image Loader API.
2 parents e153e27 + 68842f1 commit 7cbb052

16 files changed

+676
-226
lines changed

FirebaseUI.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Pod::Spec.new do |s|
3636
storage.public_header_files = 'Storage/FirebaseStorageUI/*.h'
3737
storage.source_files = 'Storage/FirebaseStorageUI/*.{h,m}'
3838
storage.dependency 'Firebase/Storage', '~> 6.0'
39-
storage.dependency 'SDWebImage', '~> 4.0'
39+
storage.dependency 'SDWebImage', '~> 5.0'
4040
storage.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(PODS_ROOT)/FirebaseUI/FirebaseStorageUI' }
4141
end
4242

Storage/FirebaseStorageUI.xcodeproj/project.pbxproj

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
32450161224B963B00AF2E90 /* FUIStorageImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 3245015F224B963B00AF2E90 /* FUIStorageImageLoader.h */; settings = {ATTRIBUTES = (Public, ); }; };
11+
32450162224B963B00AF2E90 /* FUIStorageImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 32450160224B963B00AF2E90 /* FUIStorageImageLoader.m */; };
12+
32450165224B96B400AF2E90 /* NSURL+FirebaseStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 32450163224B96B400AF2E90 /* NSURL+FirebaseStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
13+
32450166224B96B400AF2E90 /* NSURL+FirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 32450164224B96B400AF2E90 /* NSURL+FirebaseStorage.m */; };
14+
3245016D224B987400AF2E90 /* FUIStorageDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 3245016B224B987400AF2E90 /* FUIStorageDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
15+
3245016E224B987400AF2E90 /* FUIStorageDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 3245016C224B987400AF2E90 /* FUIStorageDefine.m */; };
16+
32A5DB2722755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 32A5DB2522755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
17+
32A5DB2822755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A5DB2622755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.m */; };
1018
8D69E60621DE968300CFA49B /* FirebaseStorageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D69E5FC21DE968300CFA49B /* FirebaseStorageUI.framework */; };
1119
8D69E60D21DE968300CFA49B /* FirebaseStorageUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D69E5FF21DE968300CFA49B /* FirebaseStorageUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
1220
8D69E61821DE96CF00CFA49B /* UIImageView+FirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D69E61621DE96CF00CFA49B /* UIImageView+FirebaseStorage.m */; };
@@ -25,6 +33,14 @@
2533
/* End PBXContainerItemProxy section */
2634

2735
/* Begin PBXFileReference section */
36+
3245015F224B963B00AF2E90 /* FUIStorageImageLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUIStorageImageLoader.h; sourceTree = "<group>"; };
37+
32450160224B963B00AF2E90 /* FUIStorageImageLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUIStorageImageLoader.m; sourceTree = "<group>"; };
38+
32450163224B96B400AF2E90 /* NSURL+FirebaseStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSURL+FirebaseStorage.h"; sourceTree = "<group>"; };
39+
32450164224B96B400AF2E90 /* NSURL+FirebaseStorage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSURL+FirebaseStorage.m"; sourceTree = "<group>"; };
40+
3245016B224B987400AF2E90 /* FUIStorageDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FUIStorageDefine.h; sourceTree = "<group>"; };
41+
3245016C224B987400AF2E90 /* FUIStorageDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FUIStorageDefine.m; sourceTree = "<group>"; };
42+
32A5DB2522755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FIRStorageDownloadTask+SDWebImage.h"; sourceTree = "<group>"; };
43+
32A5DB2622755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "FIRStorageDownloadTask+SDWebImage.m"; sourceTree = "<group>"; };
2844
8D69E5FC21DE968300CFA49B /* FirebaseStorageUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FirebaseStorageUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2945
8D69E5FF21DE968300CFA49B /* FirebaseStorageUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FirebaseStorageUI.h; sourceTree = "<group>"; };
3046
8D69E60021DE968300CFA49B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -78,6 +94,14 @@
7894
8D69E5FF21DE968300CFA49B /* FirebaseStorageUI.h */,
7995
8D69E61721DE96CF00CFA49B /* UIImageView+FirebaseStorage.h */,
8096
8D69E61621DE96CF00CFA49B /* UIImageView+FirebaseStorage.m */,
97+
3245015F224B963B00AF2E90 /* FUIStorageImageLoader.h */,
98+
32450160224B963B00AF2E90 /* FUIStorageImageLoader.m */,
99+
3245016B224B987400AF2E90 /* FUIStorageDefine.h */,
100+
3245016C224B987400AF2E90 /* FUIStorageDefine.m */,
101+
32450163224B96B400AF2E90 /* NSURL+FirebaseStorage.h */,
102+
32450164224B96B400AF2E90 /* NSURL+FirebaseStorage.m */,
103+
32A5DB2522755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.h */,
104+
32A5DB2622755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.m */,
81105
8D69E60021DE968300CFA49B /* Info.plist */,
82106
);
83107
path = FirebaseStorageUI;
@@ -100,6 +124,10 @@
100124
buildActionMask = 2147483647;
101125
files = (
102126
8D69E61921DE96CF00CFA49B /* UIImageView+FirebaseStorage.h in Headers */,
127+
32A5DB2722755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.h in Headers */,
128+
32450161224B963B00AF2E90 /* FUIStorageImageLoader.h in Headers */,
129+
3245016D224B987400AF2E90 /* FUIStorageDefine.h in Headers */,
130+
32450165224B96B400AF2E90 /* NSURL+FirebaseStorage.h in Headers */,
103131
8D69E60D21DE968300CFA49B /* FirebaseStorageUI.h in Headers */,
104132
);
105133
runOnlyForDeploymentPostprocessing = 0;
@@ -201,6 +229,10 @@
201229
buildActionMask = 2147483647;
202230
files = (
203231
8D69E61821DE96CF00CFA49B /* UIImageView+FirebaseStorage.m in Sources */,
232+
3245016E224B987400AF2E90 /* FUIStorageDefine.m in Sources */,
233+
32450166224B96B400AF2E90 /* NSURL+FirebaseStorage.m in Sources */,
234+
32450162224B963B00AF2E90 /* FUIStorageImageLoader.m in Sources */,
235+
32A5DB2822755E480029B3D5 /* FIRStorageDownloadTask+SDWebImage.m in Sources */,
204236
);
205237
runOnlyForDeploymentPostprocessing = 0;
206238
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// Copyright (c) 2019 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#import <FirebaseStorage/FirebaseStorage.h>
18+
#import <SDWebImage/SDWebImage.h>
19+
20+
NS_ASSUME_NONNULL_BEGIN
21+
22+
// `FIRStorageDownloadTask` conforms to `SDWebImageOperation` protocol
23+
@interface FIRStorageDownloadTask (SDWebImage) <SDWebImageOperation>
24+
25+
@end
26+
27+
NS_ASSUME_NONNULL_END
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// Copyright (c) 2019 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#import "FIRStorageDownloadTask+SDWebImage.h"
18+
19+
@implementation FIRStorageDownloadTask (SDWebImage)
20+
21+
@end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// Copyright (c) 2019 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#import <FirebaseStorage/FirebaseStorage.h>
18+
#import <SDWebImage/SDWebImage.h>
19+
20+
/**
21+
* A UInt64 raw value specify the maximum size of the downloaded image. If the downloaded image
22+
* exceeds this size, an error will be raised in the completion block. (NSNumber *)
23+
*/
24+
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextFUIStorageMaxImageSize;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// Copyright (c) 2019 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#import "FUIStorageDefine.h"
18+
19+
SDWebImageContextOption _Nonnull const SDWebImageContextFUIStorageMaxImageSize = @"FUIStorageMaxImageSize";
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// Copyright (c) 2019 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#import <SDWebImage/SDWebImage.h>
18+
#import "FUIStorageDefine.h"
19+
#import "NSURL+FirebaseStorage.h"
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
/*
24+
* This Firebase Storage loader is used to load a `Firebase Storage reference` of image record.
25+
* To use the Firebase Storage loader, you can use the API in `UIImageView+FirebaseStorage.h` for simple usage.
26+
* You can also use the native SDWebImage's View Category API, with the URL constructed with `FIRStorageReference`. See `NSURL+FirebaseStorage.h`
27+
* @code
28+
// Supports HTTP URL as well as Firebase Storage URL globally. Put this in the early setup step like AppDelegate.m
29+
SDImageLoadersManager.loaders = @[SDWebImageDownloader.sharedDownloader, FUIStorageImageLoader.sharedLoader];
30+
// Replace default manager's loader implementation
31+
SDWebImageManager.defaultImageLoader = SDImageLoadersManager.sharedManager;
32+
33+
// Then you can simply call SDWebImage's APIs the same as normal HTTP URL
34+
FIRStorageReference *storageRef;
35+
NSURL *url = [NSURL sd_URLWithStorageReference:storageRef];
36+
[imageView sd_setImageWithURL:url];
37+
* @endcode
38+
*/
39+
NS_SWIFT_NAME(StorageImageLoader)
40+
@interface FUIStorageImageLoader : NSObject<SDImageLoader>
41+
42+
/**
43+
* The maximum image download size, in bytes. Defaults to 10e6.
44+
*/
45+
@property (nonatomic, assign) UInt64 defaultMaxImageSize;
46+
47+
/**
48+
The global shared instance for Firebase Storage loader.
49+
*/
50+
@property (nonatomic, class, readonly, nonnull) FUIStorageImageLoader *sharedLoader;
51+
52+
@end
53+
54+
NS_ASSUME_NONNULL_END
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//
2+
// Copyright (c) 2019 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
#import "FUIStorageImageLoader.h"
18+
#import "FIRStorageDownloadTask+SDWebImage.h"
19+
#import <FirebaseCore/FirebaseCore.h>
20+
21+
@implementation FUIStorageImageLoader
22+
23+
+ (FUIStorageImageLoader *)sharedLoader {
24+
static dispatch_once_t onceToken;
25+
static FUIStorageImageLoader *loader;
26+
dispatch_once(&onceToken, ^{
27+
loader = [[FUIStorageImageLoader alloc] init];
28+
});
29+
return loader;
30+
}
31+
32+
- (instancetype)init {
33+
self = [super init];
34+
if (self) {
35+
self.defaultMaxImageSize = 10e6;
36+
}
37+
return self;
38+
}
39+
40+
#pragma mark - SDImageLoader Protocol
41+
42+
- (BOOL)canRequestImageForURL:(NSURL *)url {
43+
return url.sd_storageReference;
44+
}
45+
46+
- (id<SDWebImageOperation>)requestImageWithURL:(NSURL *)url options:(SDWebImageOptions)options context:(SDWebImageContext *)context progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDImageLoaderCompletedBlock)completedBlock {
47+
FIRStorageReference *storageRef = url.sd_storageReference;
48+
if (!storageRef) {
49+
if (completedBlock) {
50+
NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"The provided image url must have an associated FIRStorageReference."}];
51+
completedBlock(nil, nil, error, YES);
52+
}
53+
}
54+
55+
UInt64 size;
56+
if (context[SDWebImageContextFUIStorageMaxImageSize]) {
57+
size = [context[SDWebImageContextFUIStorageMaxImageSize] unsignedLongLongValue];
58+
} else {
59+
size = self.defaultMaxImageSize;
60+
}
61+
// Download the image from Firebase Storage
62+
63+
// TODO: Support progressive image loading using the `GTMSessionFetcher.downloadedData` with `SDImageLoaderDecodeProgressiveImageData`
64+
FIRStorageDownloadTask * download = [storageRef dataWithMaxSize:size
65+
completion:^(NSData * _Nullable data, NSError * _Nullable error) {
66+
if (error) {
67+
dispatch_main_async_safe(^{
68+
if (completedBlock) {
69+
completedBlock(nil, nil, error, YES);
70+
}
71+
});
72+
return;
73+
}
74+
// Decode the image with data
75+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
76+
UIImage *image = SDImageLoaderDecodeImageData(data, url, options, context);
77+
dispatch_main_async_safe(^{
78+
if (completedBlock) {
79+
completedBlock(image, data, nil, YES);
80+
}
81+
});
82+
});
83+
}];
84+
// Observe the progress changes
85+
[download observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot * _Nonnull snapshot) {
86+
NSProgress *progress = snapshot.progress;
87+
if (progressBlock) {
88+
progressBlock(progress.completedUnitCount, progress.totalUnitCount, url);
89+
}
90+
}];
91+
92+
return download;
93+
}
94+
95+
- (BOOL)shouldBlockFailedURLWithURL:(NSURL *)url error:(NSError *)error {
96+
if ([error.domain isEqualToString:FIRStorageErrorDomain]) {
97+
if (error.code == FIRStorageErrorCodeBucketNotFound
98+
|| error.code == FIRStorageErrorCodeProjectNotFound
99+
|| error.code == FIRStorageErrorCodeObjectNotFound) {
100+
return YES;
101+
}
102+
}
103+
return NO;
104+
}
105+
106+
@end

Storage/FirebaseStorageUI/FirebaseStorageUI.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2016 Google Inc.
2+
// Copyright (c) 2019 Google Inc.
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -24,3 +24,7 @@ FOUNDATION_EXPORT double FirebaseStorageUIVersionNumber;
2424
FOUNDATION_EXPORT const unsigned char FirebaseStorageUIVersionString[];
2525

2626
#import "UIImageView+FirebaseStorage.h"
27+
#import "FUIStorageImageLoader.h"
28+
#import "FUIStorageDefine.h"
29+
#import "NSURL+FirebaseStorage.h"
30+
#import "FIRStorageDownloadTask+SDWebImage.h"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// Copyright (c) 2019 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
#import <Foundation/Foundation.h>
17+
#import <FirebaseStorage/FirebaseStorage.h>
18+
19+
NS_ASSUME_NONNULL_BEGIN
20+
21+
@interface NSURL (FirebaseStorage)
22+
23+
/**
24+
The `FIRStorageReference` value for Firebase Storage reference, or nil for other URL.
25+
*/
26+
@property (nonatomic, strong, readonly, nullable) FIRStorageReference *sd_storageReference;
27+
28+
/**
29+
Create a Firebase Storage reference URL with `FIRStorageReference`
30+
31+
@param storageRef `FIRStorageReference` object
32+
@return A Firebase Storage reference URL
33+
*/
34+
+ (nullable instancetype)sd_URLWithStorageReference:(nonnull FIRStorageReference *)storageRef;
35+
36+
@end
37+
38+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)