user does not have permission to access gs:// xxx.appspot.com - swift

In this application I created authencation, database with firebase. but in my post, which consists of title, content, and image, I only see my default image. I'm having a bit of a problem with storage in the database, first uploading the image to firebase storage and then taking its url.
import Foundation
import SwiftUI
import Firebase
import FirebaseStorage
class StorageStore: ObservableObject {
let storageRef = Storage.storage().reference()
func uploadImage(_ image: UIImage, completion: #escaping (URL?) -> Void) {
let imageRef = storageRef.child("images/"+timeString()+".jpg")
guard let imageData = image.jpegData(compressionQuality: 0.1) else {
return completion(nil)
}
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
imageRef.putData(imageData, metadata: metadata, completion: { [self] (metadata, error) in
if let error = error {
assertionFailure(error.localizedDescription) // 🛑
//Thread 1: Fatal error: User does not have permission to access gs://ios-post-193ec.appspot.com/images/2022-03-29T10:03:18Z.jpg.
return completion(nil)
}
imageRef.downloadURL(completion: { (url, error) in
if let error = error {
assertionFailure(error.localizedDescription)
return completion(nil)
}
completion(url)
})
})
}
func timeString() -> String {
let now = Date()
let formatter = ISO8601DateFormatter()
let datetime = formatter.string(from: now)
print(datetime)
return datetime
}
}
as a result, I can't upload the image to storage
In this case, I have an error (🛑) as shown above. instead of the default image, one of the 6 permanent images that would be in the simulator had to come out.

The error message shows that the user does not have permission to access the file. So it looks like you have security rules controlling who can access the files in your Cloud Storage through Firebase, and those rules reject this read operation. I recommend checking the documentation I linked (there's also an old, but still great, video in there) to learn how to allow the operation, while still keeping the files secure.

Related

how to parse copy link of twitter

I am using this code -:
private static func getJson(_ link: String, completion: #escaping (Json?) -> ()) {
let url = URL(string: "https://twitter.com/BCCI/status/1476041561288822788?s=20")!
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {
return completion(nil)
}
if let json = (try? JSONSerialization.jsonObject(with: data)) as? Json {
completion(json)
} else {
completion(nil)
}
}.resume()
}
I want to get json data and download the link
If we take a look at the Twitter docs here you'll see that it requires authentication hence the error when making the call.
Auth: Twitter Oauth 1.0, app-only or app-user
This Twitter getting started link may be useful to get setup to do so, it's fairly self explanatory and goes step by step.

error - metadata?.downloadURL()?.absoluteString [duplicate]

I just updated Firebase Storage to 5.0.0 and it looks like metadata.downloadURL() is not recognized anymore. (Value of type 'StorageMetadata' has no member 'downloadURL')
Though after looking in the documentation it should still be available :
https://firebase.google.com/docs/reference/swift/firebasestorage/api/reference/Classes/StorageMetadata#/c:objc(cs)FIRStorageMetadata(im)downloadURL
The project was cleaned & rebuilt already.
Am I missing something ?
Can you try Google Firebase docs
// Create a reference to the file you want to download
let starsRef = storageRef.child("images/stars.jpg")
// Fetch the download URL
starsRef.downloadURL { url, error in
if let error = error {
// Handle any errors
} else {
// Get the download URL for 'images/stars.jpg'
}
}
This is my version for Swift 3 / Swift 4.
Explanation of what happens in the code.
This is essentially the same answer as Sh_Khan's. But in his example the User already knows the bucket path. In my example, we get the path from an upload task. This was what has lead me to this question as well as what I think op was looking for as he was looking for metadata.downloadURL() replacement.
class StorageManagager {
private let storageReference: StorageReference
init() {
// first we create a reference to our storage
// replace the URL with your firebase URL
self.storageReference = Storage.storage().reference(forURL: "gs://MYAPP.appspot.com")
}
// MARK: - UPLOAD DATA
open func uploadData(_ data: Data, named filename: String, completion: #escaping (URL? , Error?) -> Void) {
let reference = self.storageReference.child(filename)
let metadata = StorageMetadata()
metadata.contentType = "ourType" // in my example this was "PDF"
// we create an upload task using our reference and upload the
// data using the metadata object
let uploadTask = reference.putData(data, metadata: metadata) { metadata, error in
// first we check if the error is nil
if let error = error {
completion(nil, error)
return
}
// then we check if the metadata and path exists
// if the error was nil, we expect the metadata and path to exist
// therefore if not, we return an error
guard let metadata = metadata, let path = metadata.path else {
completion(nil, NSError(domain: "core", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unexpected error. Path is nil."]))
return
}
// now we get the download url using the path
// and the basic reference object (without child paths)
self.getDownloadURL(from: path, completion: completion)
}
// further we are able to use the uploadTask for example to
// to get the progress
}
// MARK: - GET DOWNLOAD URL
private func getDownloadURL(from path: String, completion: #escaping (URL?, Error?) -> Void) {
self.storageReference.child(path).downloadURL(completion: completion)
}
}
Let's try this code in Swift 4.2:
let imgData = UIImage.jpegData(self.imageView.image!)
let imageName = UUID().uuidString
let ref = Storage.storage().reference().child("pictures/\(imageName).jpg")
let meta = StorageMetadata()
meta.contentType = "image/jpeg"
self.uploadToCloud(data: imgData(0.5)!, ref: ref, meta: meta)
UploadToCloud Method:
` Method UploadToCloud
func uploadToCloud(data:Data, ref:StorageReference, meta:StorageMetadata) {
ref.putData(data, metadata: meta) { (metaData, error) in
if let e = error {
print("==> error: \(e.localizedDescription)")
}
else
{
ref.downloadURL(completion: { (url, error) in
print("Image URL: \((url?.absoluteString)!)")
})
}
}
}
This question pops up for all language searches. Hence for Kotlin, the solution is something of the kind below:
val photoRef = FirebaseStorage.getInstance()
.reference.child("images/stars.jpg")
// Code ommited - Do some saving - putFile
photoRef.downloadUrl.addOnSuccessListener({ uri ->
product.imageUrl = uri.toString()
})
However, this is not a good solution. You are better off saving the path and then re-constructing the full Url on demand. For example:
photoRef.downloadUrl.addOnSuccessListener({ uri ->
val imagePath = uri.toString()
// Save to database
})
Now, you can use it later, and only on demand:
FirebaseStorage.getInstance().reference.child(product.imageUrl).downloadUrl
.addOnSuccessListener { uri ->
String imageUrl = uri.toString()
// Load in images
}
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
print(error as Any)
return
}
guard let uid = user?.user.uid else {
return
}
self.dismiss(animated: true, completion: nil)
//Добавляем картинку в firebase. Надо добавить в Pods file pod 'Firebase/Storage' и запустить терминал
let imageName = NSUUID().uuidString
let storageRef = Storage.storage().reference()
// Create a reference to the file you want to download
let starsRef = storageRef.child("profile_images").child("\(imageName).png")
let uploadData = self.profileImageView.image?.pngData()
starsRef.putData(uploadData!, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error as Any)
}
if let profileImageUrl = metadata?.path {
let values = ["name": name, "email": email, "profileImage": profileImageUrl]
self.registerUserIntoDatabaseWithUID(uid: uid, values: values)
}
})
}
If you are stuck in converting URL to string... you can try this
url.absoluteString

What is the downloadURL equivalent in FirebaseStorage 3? [duplicate]

I just updated Firebase Storage to 5.0.0 and it looks like metadata.downloadURL() is not recognized anymore. (Value of type 'StorageMetadata' has no member 'downloadURL')
Though after looking in the documentation it should still be available :
https://firebase.google.com/docs/reference/swift/firebasestorage/api/reference/Classes/StorageMetadata#/c:objc(cs)FIRStorageMetadata(im)downloadURL
The project was cleaned & rebuilt already.
Am I missing something ?
Can you try Google Firebase docs
// Create a reference to the file you want to download
let starsRef = storageRef.child("images/stars.jpg")
// Fetch the download URL
starsRef.downloadURL { url, error in
if let error = error {
// Handle any errors
} else {
// Get the download URL for 'images/stars.jpg'
}
}
This is my version for Swift 3 / Swift 4.
Explanation of what happens in the code.
This is essentially the same answer as Sh_Khan's. But in his example the User already knows the bucket path. In my example, we get the path from an upload task. This was what has lead me to this question as well as what I think op was looking for as he was looking for metadata.downloadURL() replacement.
class StorageManagager {
private let storageReference: StorageReference
init() {
// first we create a reference to our storage
// replace the URL with your firebase URL
self.storageReference = Storage.storage().reference(forURL: "gs://MYAPP.appspot.com")
}
// MARK: - UPLOAD DATA
open func uploadData(_ data: Data, named filename: String, completion: #escaping (URL? , Error?) -> Void) {
let reference = self.storageReference.child(filename)
let metadata = StorageMetadata()
metadata.contentType = "ourType" // in my example this was "PDF"
// we create an upload task using our reference and upload the
// data using the metadata object
let uploadTask = reference.putData(data, metadata: metadata) { metadata, error in
// first we check if the error is nil
if let error = error {
completion(nil, error)
return
}
// then we check if the metadata and path exists
// if the error was nil, we expect the metadata and path to exist
// therefore if not, we return an error
guard let metadata = metadata, let path = metadata.path else {
completion(nil, NSError(domain: "core", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unexpected error. Path is nil."]))
return
}
// now we get the download url using the path
// and the basic reference object (without child paths)
self.getDownloadURL(from: path, completion: completion)
}
// further we are able to use the uploadTask for example to
// to get the progress
}
// MARK: - GET DOWNLOAD URL
private func getDownloadURL(from path: String, completion: #escaping (URL?, Error?) -> Void) {
self.storageReference.child(path).downloadURL(completion: completion)
}
}
Let's try this code in Swift 4.2:
let imgData = UIImage.jpegData(self.imageView.image!)
let imageName = UUID().uuidString
let ref = Storage.storage().reference().child("pictures/\(imageName).jpg")
let meta = StorageMetadata()
meta.contentType = "image/jpeg"
self.uploadToCloud(data: imgData(0.5)!, ref: ref, meta: meta)
UploadToCloud Method:
` Method UploadToCloud
func uploadToCloud(data:Data, ref:StorageReference, meta:StorageMetadata) {
ref.putData(data, metadata: meta) { (metaData, error) in
if let e = error {
print("==> error: \(e.localizedDescription)")
}
else
{
ref.downloadURL(completion: { (url, error) in
print("Image URL: \((url?.absoluteString)!)")
})
}
}
}
This question pops up for all language searches. Hence for Kotlin, the solution is something of the kind below:
val photoRef = FirebaseStorage.getInstance()
.reference.child("images/stars.jpg")
// Code ommited - Do some saving - putFile
photoRef.downloadUrl.addOnSuccessListener({ uri ->
product.imageUrl = uri.toString()
})
However, this is not a good solution. You are better off saving the path and then re-constructing the full Url on demand. For example:
photoRef.downloadUrl.addOnSuccessListener({ uri ->
val imagePath = uri.toString()
// Save to database
})
Now, you can use it later, and only on demand:
FirebaseStorage.getInstance().reference.child(product.imageUrl).downloadUrl
.addOnSuccessListener { uri ->
String imageUrl = uri.toString()
// Load in images
}
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
print(error as Any)
return
}
guard let uid = user?.user.uid else {
return
}
self.dismiss(animated: true, completion: nil)
//Добавляем картинку в firebase. Надо добавить в Pods file pod 'Firebase/Storage' и запустить терминал
let imageName = NSUUID().uuidString
let storageRef = Storage.storage().reference()
// Create a reference to the file you want to download
let starsRef = storageRef.child("profile_images").child("\(imageName).png")
let uploadData = self.profileImageView.image?.pngData()
starsRef.putData(uploadData!, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error as Any)
}
if let profileImageUrl = metadata?.path {
let values = ["name": name, "email": email, "profileImage": profileImageUrl]
self.registerUserIntoDatabaseWithUID(uid: uid, values: values)
}
})
}
If you are stuck in converting URL to string... you can try this
url.absoluteString

Value of type 'StorageMetadata' has no member 'downloadURL'

I just updated Firebase Storage to 5.0.0 and it looks like metadata.downloadURL() is not recognized anymore. (Value of type 'StorageMetadata' has no member 'downloadURL')
Though after looking in the documentation it should still be available :
https://firebase.google.com/docs/reference/swift/firebasestorage/api/reference/Classes/StorageMetadata#/c:objc(cs)FIRStorageMetadata(im)downloadURL
The project was cleaned & rebuilt already.
Am I missing something ?
Can you try Google Firebase docs
// Create a reference to the file you want to download
let starsRef = storageRef.child("images/stars.jpg")
// Fetch the download URL
starsRef.downloadURL { url, error in
if let error = error {
// Handle any errors
} else {
// Get the download URL for 'images/stars.jpg'
}
}
This is my version for Swift 3 / Swift 4.
Explanation of what happens in the code.
This is essentially the same answer as Sh_Khan's. But in his example the User already knows the bucket path. In my example, we get the path from an upload task. This was what has lead me to this question as well as what I think op was looking for as he was looking for metadata.downloadURL() replacement.
class StorageManagager {
private let storageReference: StorageReference
init() {
// first we create a reference to our storage
// replace the URL with your firebase URL
self.storageReference = Storage.storage().reference(forURL: "gs://MYAPP.appspot.com")
}
// MARK: - UPLOAD DATA
open func uploadData(_ data: Data, named filename: String, completion: #escaping (URL? , Error?) -> Void) {
let reference = self.storageReference.child(filename)
let metadata = StorageMetadata()
metadata.contentType = "ourType" // in my example this was "PDF"
// we create an upload task using our reference and upload the
// data using the metadata object
let uploadTask = reference.putData(data, metadata: metadata) { metadata, error in
// first we check if the error is nil
if let error = error {
completion(nil, error)
return
}
// then we check if the metadata and path exists
// if the error was nil, we expect the metadata and path to exist
// therefore if not, we return an error
guard let metadata = metadata, let path = metadata.path else {
completion(nil, NSError(domain: "core", code: 0, userInfo: [NSLocalizedDescriptionKey: "Unexpected error. Path is nil."]))
return
}
// now we get the download url using the path
// and the basic reference object (without child paths)
self.getDownloadURL(from: path, completion: completion)
}
// further we are able to use the uploadTask for example to
// to get the progress
}
// MARK: - GET DOWNLOAD URL
private func getDownloadURL(from path: String, completion: #escaping (URL?, Error?) -> Void) {
self.storageReference.child(path).downloadURL(completion: completion)
}
}
Let's try this code in Swift 4.2:
let imgData = UIImage.jpegData(self.imageView.image!)
let imageName = UUID().uuidString
let ref = Storage.storage().reference().child("pictures/\(imageName).jpg")
let meta = StorageMetadata()
meta.contentType = "image/jpeg"
self.uploadToCloud(data: imgData(0.5)!, ref: ref, meta: meta)
UploadToCloud Method:
` Method UploadToCloud
func uploadToCloud(data:Data, ref:StorageReference, meta:StorageMetadata) {
ref.putData(data, metadata: meta) { (metaData, error) in
if let e = error {
print("==> error: \(e.localizedDescription)")
}
else
{
ref.downloadURL(completion: { (url, error) in
print("Image URL: \((url?.absoluteString)!)")
})
}
}
}
This question pops up for all language searches. Hence for Kotlin, the solution is something of the kind below:
val photoRef = FirebaseStorage.getInstance()
.reference.child("images/stars.jpg")
// Code ommited - Do some saving - putFile
photoRef.downloadUrl.addOnSuccessListener({ uri ->
product.imageUrl = uri.toString()
})
However, this is not a good solution. You are better off saving the path and then re-constructing the full Url on demand. For example:
photoRef.downloadUrl.addOnSuccessListener({ uri ->
val imagePath = uri.toString()
// Save to database
})
Now, you can use it later, and only on demand:
FirebaseStorage.getInstance().reference.child(product.imageUrl).downloadUrl
.addOnSuccessListener { uri ->
String imageUrl = uri.toString()
// Load in images
}
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
print(error as Any)
return
}
guard let uid = user?.user.uid else {
return
}
self.dismiss(animated: true, completion: nil)
//Добавляем картинку в firebase. Надо добавить в Pods file pod 'Firebase/Storage' и запустить терминал
let imageName = NSUUID().uuidString
let storageRef = Storage.storage().reference()
// Create a reference to the file you want to download
let starsRef = storageRef.child("profile_images").child("\(imageName).png")
let uploadData = self.profileImageView.image?.pngData()
starsRef.putData(uploadData!, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error as Any)
}
if let profileImageUrl = metadata?.path {
let values = ["name": name, "email": email, "profileImage": profileImageUrl]
self.registerUserIntoDatabaseWithUID(uid: uid, values: values)
}
})
}
If you are stuck in converting URL to string... you can try this
url.absoluteString

Making multiple asynchronous HTTP requests in succession and writing with Realm

I'm currently using Alamofire for requesting data and writing to disk with Realm. Specifically, I am fetching 24 source URLS from a Facebook Graph GET request and then making 24 separate requests to retrieve the data for each image. Once the data is retrieved, I am writing to disk with Realm.
here is how I am fetching the 24 sources:
FBAPI
Alamofire.request(.GET, FBPath.photos, parameters: params).responseJSON { response in
guard response.result.error == nil else {
print("error calling GET on \(FBPath.photos)")
print(response.result.error!)
completion(latestDate: nil, photosCount: 0, error: response.result.error)
return
}
if let value = response.result.value {
let json = JSON(value)
if let photos = json[FBResult.data].array {
for result in photos {
let manager = PTWPhotoManager()
manager.downloadAndSaveJsonData(result)
}
As you can see, I have a for loop iterating through each JSON containing the source url for the photo's image in which I then make another network request for each url, like so:
Manager
func downloadAndSaveJsonData(photoJSON : JSON) {
let source = photoJSON[FBResult.source].string
let id = photoJSON[FBResult.id].string
let created_time = photoJSON[FBResult.date.createdTime].string
let imageURL = NSURL(string: source!)
print("image requested")
Alamofire.request(.GET, imageURL!).response() {
(request, response, data, error) in
if (error != nil) {
print(error?.localizedDescription)
}
else {
print("image response")
let photo = PTWPhoto()
photo.id = id
photo.sourceURL = source
photo.imageData = data
photo.createdTime = photo.createdTimeAsDate(created_time!)
let realm = try! Realm()
try! realm.write {
realm.add(photo)
}
print("photo saved")
}
}
}
There seems to be a very long delay between when each image's data is requested and when I receive a response, and it also does not appear to be asynchronous. Is this a threading issue or is there a more efficient way to request an array of data like this? It should also be noted that I am making this network request from the Apple Watch itself.
These requests will happen mostly asynchronous as you wish. But there is some synchronization happening, you might been not aware of:
The response closures for Alamofire are dispatched to the main thread. So your network responses competes against any UI updates you do.
Realm write transactions are synchronous and exclusive, which is enforced via locks which will block the thread where they are executed on.
In combination this both means that you will block the main thread as long as the network requests succeed and keep coming, which would also render your app unresponsive.
I'd recommend a different attempt. You can use GCD's dispatch groups to synchronize different asynchronous tasks.
In the example below, the objects are all kept in memory until they are all downloaded.
A further improvement could it be to write the downloaded data onto disk instead and store just the path to the file in the Realm object. (There are plenty of image caching libraries, which can easily assist you with that.)
If you choose a path, which depends only on the fields of PWTPhoto (or properties of the data, you can get through a quick HEAD request), then you can check first whether this path exists already locally before downloading the file again. By doing that you save traffic when updating the photos or when not all photos could been successfully downloaded on the first attempt. (e.g. app is force-closed by the user, crashed, device is shutdown)
class PTWPhotoManager {
static func downloadAllPhotos(params: [String : AnyObject], completion: (latestDate: NSDate?, photosCount: NSUInteger, error: NSError?)) {
Alamofire.request(.GET, FBPath.photos, parameters: params).responseJSON { response in
guard response.result.error == nil else {
print("error calling GET on \(FBPath.photos)")
print(response.result.error!)
completion(latestDate: nil, photosCount: 0, error: response.result.error)
return
}
if let value = response.result.value {
let json = JSON(value)
if let photos = json[FBResult.data].array {
let group = dispatch_group_create()
var persistablePhotos = [PTWPhoto](capacity: photos.count)
let manager = PTWPhotoManager()
for result in photos {
dispatch_group_enter(group)
let request = manager.downloadAndSaveJsonData(result) { photo, error in
if let photo = photo {
persistablePhotos.add(photo)
dispatch_group_leave(group)
} else {
completion(latestDate: nil, photosCount: 0, error: error!)
}
}
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
let realm = try! Realm()
try! realm.write {
realm.add(persistablePhotos)
}
let latestDate = …
completion(latestDate: latestDate, photosCount: persistablePhotos.count, error: nil)
}
}
}
}
}
func downloadAndSaveJsonData(photoJSON: JSON, completion: (PTWPhoto?, NSError?) -> ()) -> Alamofire.Request {
let source = photoJSON[FBResult.source].string
let id = photoJSON[FBResult.id].string
let created_time = photoJSON[FBResult.date.createdTime].string
let imageURL = NSURL(string: source!)
print("image requested")
Alamofire.request(.GET, imageURL!).response() { (request, response, data, error) in
if let error = error {
print(error.localizedDescription)
completion(nil, error)
} else {
print("image response")
let photo = PTWPhoto()
photo.id = id
photo.sourceURL = source
photo.imageData = data
photo.createdTime = photo.createdTimeAsDate(created_time!)
completion(photo, nil)
}
}
}
}