I've updated firebase pods today and I've encountered some issues.
First of all I was getting this error:
No such module 'FirebaseStorageUI'
Now I've changed it into:
import FirebaseStorage
import FirebaseUI
This seems to work as all functions are still available like storage and sd_webimage.
Now I'm getting this error:
Cannot convert value of type 'StorageReference' to expected argument type 'URL?'
Below code worked before the update
let storageRef = Storage.storage().reference().child("user/thomas_1")
self.profileImageView.sd_setImage(with: storageRef, placeholderImage: UIImage(named: "placeholder"), completed: { (image, error, cacheType, storageRef) in
if image != nil && error != nil {
UIView.animate(withDuration: 0.3) {
self.profileImageView.alpha = 1
}
}
})
Now it didn't and it gave me that error, I changed it into a url but it still doesn't work or is giving me errors. Following the examples in the documentation and sample apps above method should work. I also found out that the url is a direct gs:// path and that is not reachable.
If anyone can point out (maybe the obvious) mistake that would be very helpful and thanks in advance.
You will need to get the download URL of the image, which can be obtained through the downloadURL method, like this:
let storageRef = Storage.storage().reference().child("user/thomas_1")
storageRef.downloadURL { url, error in
guard let url = url else { return }
self.profileImageView.sd_setImage(with: storageRef, placeholderImage: UIImage(named: "placeholder"), completed: { (image, error, cacheType, storageRef) in
if image != nil && error != nil {
UIView.animate(withDuration: 0.3) {
self.profileImageView.alpha = 1
}
}
})
}
This will work, but instead of generating the download URL every time like the above example, I'd recommend generating it right after initially uploading the image, and then storing this download URL in whatever database you use.
Related
I have an array of image data(in bytes), and I want to upload them to storage and get the download URL for all of them. But after uploading lots of pictures, there is only one file appears in the storage under the reference. I do get the download URLs, but only the last one works, the rest all say access denied.
I suspect it is because I am putting all the pictures under the same storage reference and the picture substitutes every time. But what can I do to upload multiple images?
My upload code:
var picturesURL: [String] = [] // I want to put the download URL in this array
if self.imageButton.isSelected{
picturesURL = []
for photoData in self.pictures{ // pictures is the array that stores all the photo data
self.storage.child("images/file.png").putData(photoData, metadata: nil) { _, error in
guard error == nil else{
print("Failed to upload")
return
}
self.storage.child("images/file.png").downloadURL (completion: { url, error in
guard let url = url, error == nil else{
print("problems getting url")
return
}
let urlString = url.absoluteString
picturesURL.append(urlString)
print(urlString)
//UserDefaults.standard.set(urlString, forKey: "url")
})
}
}
In short, I am writing an App with the following order.
Upload an image to Firebase Storage.
Download the image URL.
Upload the URL (and some other staff) to Firestore documents.
Parts 1 and 3 are working well. Beside the fact that I receive the URL too late. Yes too late.
To understand what's happening I added print statements in the expected order 0-13. See my code below. Print statements 9-13 are outside the function uploadImage.
When executing the app the processed order is the following:
0 - before calling function uploadImage
1 - Right before putData
8 - Before leaving function uploadImage
12 - Upload document with URL: Optional("")
13 - At FirestoreDB.collection.addDocument ->Document added with ID: 3uDhNM3o…
2 - Processing the completion of putData
4 - Right before downloadURL
5 - Processing the completion of downloadURL
7 - Within completion url https://firebasestorage.googleapis.com/…
10 - Within clompetion url of uploadImage function
11a - URL available https://firebasestorage.googleapis.com/…
Any advice?
Thanks, Michael
guard let imageData = image.jpegData(compressionQuality: 0.2) else {
completion(nil)
return
}
let uploadStorageReference = storageReference.child(directory)
let imgID = NSUUID().uuidString
let idStorageReference = uploadStorageReference.child(imgID)
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
print("1 - Right before putData")
_ = idStorageReference.putData(imageData, metadata: metaData, completion: { (metadata, error) in
print("2 - Processing the completion of putData")
if let error = error {
print("3 - Within error handling of putData \(error.localizedDescription)")
completion(nil)
return
} else {
print("4 - Right before downloadURL")
idStorageReference.downloadURL(completion: { (url, error) in
print("5 - Processing the completion of downloadURL")
if let error = error {
print("6 - Within error handling of downloadURL \(error.localizedDescription)")
completion(nil)
return
} else {
if let downloadedURL = url {
print("7 - Within completion url \(downloadedURL)")
completion(downloadedURL)
}
}
})
}
})
print("8 - Before leaving function uploadImage")
}
As Larme mentions in a comment:
The order doesn't seem strange to me. You are seeing the concept of asynchronism. Look how to manage it. It's normal that 8 is printed just after 1.
I fixed it by using DispatchSemaphore.
The below swift code is written to upload an image to firebase storage. Earlier it was working fine. But now onwards it works randomly. I waited 30mins to upload an image but didn't reach to success nor even in error.
I have tried different code to upload an image. Also, search a lot to analyze the problem. But sometimes it works randomly. I am not able to identify why this is happening.
To check if the image is uploading or not, I just put an observer to check the progress of an upload task, uploading works perfectly, but it didn't reach to completion block. I tried to generate download URL too after upload task done but it also didn't reach to completion block.
let storageRef = Storage.storage().reference().child("abc").child("myImage1234")
storageRef.putData(imageData, metadata: nil, completion: { (storageMetaData, error) in
if let error = error {
print(error.localizedDescription)
} else {
storageRef.downloadURL(completion: { (url, error) in
if error != nil {
print(error?.localizedDescription as Any)
return
}
if let photoUrl = url?.absoluteString {
self.imageUpload()
}
})
}
})
I am really stuck at this point. Any help would be appreciated.
For the past 2 weeks I've been banging my head against a wall trying to create and validate CMS signatures in Swift 4 using OpenSSL. My code is ultimately destined to be run on Linux, so I can't use the macOS Security framework. I believe I have finally gotten CMS signature creation working properly. My code for that looks like this:
let testBundle = Bundle(for: type(of: self))
guard let textUrl = testBundle.url(forResource: "test_message", withExtension: "txt"),
let signingKeyUrl = testBundle.url(forResource: "signing_key", withExtension: "pem"),
let signingCertUrl = testBundle.url(forResource: "signing_cert", withExtension: "pem") else {
exit(1)
}
let certFileObject = signingCertUrl.path.withCString { filePtr in
return fopen(filePtr, "rb")
}
defer {
fclose(certFileObject)
}
let keyFileObject = signingKeyUrl.path.withCString { filePtr in
return fopen(filePtr, "rb")
}
defer {
fclose(keyFileObject)
}
guard let key = PEM_read_PrivateKey(keyFileObject, nil, nil, nil),
let cert = PEM_read_X509(certFileObject, nil, nil, nil) else {
exit(1)
}
OpenSSL_add_all_ciphers()
OpenSSL_add_all_digests()
OPENSSL_add_all_algorithms_conf()
guard let textData = FileManager.default.contents(atPath: textUrl.path) else {
exit(1)
}
guard let textBIO = BIO_new(BIO_s_mem()) else {
print("Unable to create textBIO")
exit(1)
}
_ = textData.withUnsafeBytes({dataBytes in
BIO_write(textBIO, dataBytes, Int32(textData.count))
})
guard let cms = CMS_sign(cert, key, nil, textBIO, UInt32(CMS_BINARY)) else {
exit(1)
}
When I debug this code, I see that the cms object is being set after the CMS_sign call, so I believe that the signature was generated properly. Right after this, I'm trying to validate the signature I just created. That code looks like this:
let store = X509_STORE_new()
X509_STORE_add_cert(store, cert)
let outBIO = BIO_new(BIO_s_mem())
let result = CMS_verify(cms, nil, store, nil, outBIO, 0)
print("result : \(result)")
if result != 1 {
let errorCode: UInt = ERR_get_error()
print("ERROR : \(String(format: "%2X", errorCode))")
}
When I run this code, however, result == 0, indicating an error. The error code that OpenSSL is returning is 0x2E099064. I ran this command:
openssl errstr 0x2E099064
Which gave me this info about the error:
error:2E099064:CMS routines:func(153):reason(100)
After a bit more digging, I think that the error corresponds to PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH. I got that from the pkcs7.h file here. I'm not 100% that this is the correct error message, however.
My question is, why is my signature validation failing? I'm using the exact same certificate to validate the signature. All of this code is inline, so nothing is getting lost anywhere. Can any of you give me an idea where things are going wrong?
I have little problem. I got caching to work with the following URL:
let URL = NSURL(string: "https://raw.githubusercontent.com/onevcat/Kingfisher/master/images/kingfisher-\(indexPath.row + 1).jpg")!
But can't get it to work like this with this URL:
FIRStorage.storage().reference().child("\(productImageref!).png").downloadURLWithCompletion({(url, error)in
if error != nil{
print(error)
return
}else{
cell.snusProductImageView.kf_setImageWithURL(url , placeholderImage: nil,
optionsInfo: [.Transition(ImageTransition.Fade(1))],
progressBlock: { receivedSize, totalSize in
print("\(indexPath.row + 1): \(receivedSize)/\(totalSize)")
},
completionHandler: { image, error, cacheType, imageURL in
print("\(indexPath.row + 1): Finished")
})
}
})
What I am doing wrong here? Can you point me to the right direction? For caching I use the 3rd party library "KingFisher"
Edit: Firebase guy Mike McDonald's quote
"The Github one has Cache-Control: max-age=300 while Firebase Storage
doesn't have cache control set by default (you can set it when you
upload the file, or change it by updating metadata), so I assume
that's why KingFisher isn't caching it."
KingFisher owner quotes.
Like Firebase guy Mike McDonald said I directly set the cache-control when uploading the image to the Firebase storage. Then it will be cached correctly when loading it later.
(Configuration: Swift3, Firebase Storage 3.11.0)
let storage = FIRStorage.storage()
let storageRef = storage.reference(forURL: yourFirebaseStorageReferenceURL)
let imageRef = storageRef.child("profileImages/\(imageUUID).jpg")
let metadata = FIRStorageMetadata()
metadata.contentType = "image/jpeg"
// THIS is the important part
metadata.cacheControl = "public,max-age=2592000"
let uploadTask = imageRef.put(imageData, metadata: metadata) { (metadata, error) in
if let error = error
{
completion(.failure(error as NSError))
}
guard let metadata = metadata, let downloadURL = metadata.downloadURL()?.absoluteString else {
// Handle upload error
return
}
// Handle successful upload
}
When I download the image, the cache-control is set
The way I got them caching was that I had to write all image url-s into JSON like this:
.setValue(url!.absoluteString)
And then read those as url-s