SDWebImageSwiftUI icon indicating copy to clipboard operation
SDWebImageSwiftUI copied to clipboard

How to use Firebase Storage with SDWebImageSwiftUI

Open Xenolion opened this issue 1 year ago • 13 comments

All my efforts to use firebase storage reference with SDWebImageSwiftUI do not work. import SwiftUI import FirebaseStorage import SDWebImage import SDWebImageSwiftUI import FirebaseStorageUI

I have imported all these but it does not work.

WebImage(url: imageReference)

How do I make this work?

Xenolion avatar Jul 20 '23 10:07 Xenolion

Emmmm...

You can use the category on FirebaseStorage to create URL from FIRStorageReference ?

dreampiggy avatar Jul 20 '23 10:07 dreampiggy

I am talking about import FirebaseStorageUI. I wanted to go for the option to load an Image directly from Reference like how its done in SDWebImage(the version without swuftui). @dreampiggy

Xenolion avatar Jul 20 '23 10:07 Xenolion

You can check that FirebaseUI implementation (open-sourced), it create a special NSURL by wrapping the FIRStorageReference (which is the unit of FirebaseStorage)

So, I guess if you can create that special NSURL and feed into WebImage, it will get the same effect.

I have no demo code here, any usable demo ?

dreampiggy avatar Jul 20 '23 10:07 dreampiggy

The magic happens here: https://github.com/firebase/FirebaseUI-iOS/blob/master/FirebaseStorageUI/Sources/NSURL%2BFirebaseStorage.m

So, if in Swift you can call to create this sd_URLWithStorageReference:, then it will work

dreampiggy avatar Jul 20 '23 11:07 dreampiggy

This sd_URLWithStorageReference: is public API, so it can be called from Swift side: https://github.com/firebase/FirebaseUI-iOS/blob/master/FirebaseStorageUI/Sources/Public/FirebaseStorageUI/NSURL%2BFirebaseStorage.h

dreampiggy avatar Jul 20 '23 11:07 dreampiggy

To say, this ugly design can be changed in SDWebImage 6.0. We can load a thing which is not NSURL * but something conforms to protocol, so that it can generalize the usage like this :(

public protocol SDImageResource : NSObjectProtocol {
    public var url: URL { get }
    public var cacheKey: String { get }
}

public struct WebImage {
    public init(_ resource: SDImageResource)
}

dreampiggy avatar Jul 20 '23 11:07 dreampiggy

Do I don't understand should I create an exact copy of that? I am using SwiftUI copying the method does not work as well.

Xenolion avatar Jul 20 '23 11:07 Xenolion

I dont think I understand. Look it still gives an error

WebImage(url: sd_URLWithStorageReference(imageReference))

Xenolion avatar Jul 20 '23 11:07 Xenolion

The code above still throws Cannot find 'sd_URLWithStorageReference' in scope @dreampiggy

Xenolion avatar Jul 20 '23 11:07 Xenolion

I have got to try this if it works in this case: func toUrl(_ reference: StorageReference) -> URL? { let url = NSURL.sd_URL(withStorageReference: reference) as URL? print("URL is : \(String(describing: url))") return url }

Xenolion avatar Jul 20 '23 12:07 Xenolion

Even the method above throws an error: Task <5B5CBD27-B0DC-4D9B-A50B-1A3354CEE9DF>.<2> finished with error [-1002] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=gs://comcha-posts/uzXc4oMdKQ5pKI3MTX87/8higbpn7elJpru3KOKlB/wlB9wr4nIhPcxaqK8zWM.png, NSErrorFailingURLKey=gs://bucket-posts/uzXc4oMdKQ5pKI3MTX87/8higbpn7elJpru3KOKlB/wlB9wr4nIhPcxaqK8zWM.png, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <5B5CBD27-B0DC-4D9B-A50B-1A3354CEE9DF>.<2>" ), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <5B5CBD27-B0DC-4D9B-A50B-1A3354CEE9DF>.<2>, NSUnderlyingError=0x2835d9f80 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}

Xenolion avatar Jul 20 '23 13:07 Xenolion

Even the method above throws an error: Task <5B5CBD27-B0DC-4D9B-A50B-1A3354CEE9DF>.<2> finished with error [-1002] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSErrorFailingURLStringKey=gs://comcha-posts/uzXc4oMdKQ5pKI3MTX87/8higbpn7elJpru3KOKlB/wlB9wr4nIhPcxaqK8zWM.png, NSErrorFailingURLKey=gs://bucket-posts/uzXc4oMdKQ5pKI3MTX87/8higbpn7elJpru3KOKlB/wlB9wr4nIhPcxaqK8zWM.png, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <5B5CBD27-B0DC-4D9B-A50B-1A3354CEE9DF>.<2>" ), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <5B5CBD27-B0DC-4D9B-A50B-1A3354CEE9DF>.<2>, NSUnderlyingError=0x2835d9f80 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}

I think that you don't setup the FirebaseStorageUI correcly. Seems you use that special wrapper NSURL and use URLSession to load that, but it's not a HTTP URL so URLSession will fail.

Which actually, should use FirebaseStorage's Loader instead, which means, the custom loader feature from SDWebImage: https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#custom-loader-50

API: https://sdwebimage.github.io/documentation/sdwebimage/sdwebimagecontextoption/imageloader

dreampiggy avatar Jul 22 '23 08:07 dreampiggy

Give me an example ? So I can test it as well.

From the docs, maybe you need something like:

WebImage(url: CreateURLFromFirebaseStoragreReference(),
  options: 0,
  context: [.imageLoader: StorageImageLoader.shared])

See the readme in FirebaseStorageUI, you can also setup the global loaders manger like this, so you don't need speciay .context param each time you need. It will support both HTTP URL or FirebaseStorage URL :

let loader1 = SDWebImageDownloader.shared
let loader2 = StorageImageLoader.shared
SDImageLoadersManager.shared.loaders = [loader1, loader2]

// Assign loader to manager
let manager = SDWebImageManager(cache: SDImageCache.shared, loader: SDImageLoadersManager.shared)
// Start use

// If you want to assign loader to default manager, use `defaultImageLoader` class property before shared manager initialized
SDWebImageManager.defaultImageLoader = SDImageLoadersManager.shared

dreampiggy avatar Jul 22 '23 08:07 dreampiggy