Download and use files stored in Firebase Storage from different projects - ios

I'm using Firebase Storage to store images in FB, I'm saving download URL in Realtime DB and to retrieve some photos from the storage, I'm using this code:
let storage = FIRStorage.storage()
imageRefInDB.observeEventType(.Value, withBlock: { (snapshot) in
// Get download URL from snapshot
let downloadURL = snapshot.value as! String
// Create a storage reference from the URL
let storageRef = storage.referenceForURL(downloadURL)
storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
print(error.debugDescription)
} else {
let downloadedImage = UIImage(data: data!)
}
}
})
My problem is I wanna use some of my photo that are inside another Firebase project. For example, the download URLs will be:
https://firebasestorage.googleapis.com/v0/b/PROJECT1.appspot.com/o/someMedia&token
When in my current project, the bucket is different like :
https://firebasestorage.googleapis.com/v0/b/PROJECT2.appspot.com/o/someMedia&Token
When I try to using the PROJECT1 files in my current PROJECT2, I'm getting the following error:
reason: 'Provided bucket: PROJECT1.appspot.com does not match bucket specified in FIRApp configuration: PROJECT2.appspot.com
Is there a way to enable downloading theses files from other projects like a setting in Firebase without retrieving them with regular URL downloads?
Thanks for your help!

I tried that once and it lead to an unhappy time. In my case I had two different buckets for my images, so I had to find an alternate solution.
If you have only a single bucket, you can try configuring that bucket in your FIRApp:
let firOptions = FIROptions(googleAppID: googleAppID, bundleID: bundleID, GCMSenderID: GCMSenderID, APIKey: nil, clientID: nil, trackingID: nil, androidClientID: nil, databaseURL: databaseURL, storageBucket: storageBucket, deepLinkURLScheme: nil)
FIRApp.configureWithName("anotherClient", options: options)
let app = FIRApp(named: "anotherClient")
let storageRef = FIRStorage.storage(app: app!).reference()
Taken from this answer, so you may need to modify it to suit your needs
With that app, you can then use the Firebase Storage API as you're already doing to download the image data.
If you have multiple buckets (as I had), you either have to configure multiple apps or (as I did) handle downloading the image from the downloadURL yourself (without using the Firebase Storage API):
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
let data = NSData(contentsOfURL: downloadURL) //make sure your image in this url does exist, otherwise unwrap in a if let check
dispatch_async(dispatch_get_main_queue(), {
let downloadedImage = UIImage(data: data!)
});
}

Related

Error 13010 "Object does not exist" while downloading jpeg image from Firebase storage using getData()

Language : Swift 5
iOS: 13.2
macOS: Catalina 10.15.4
Firebase Storage Rules:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth!=null;
}
}
}
The code to upload image and save download URL: (Which works fine, because I can see images uploaded to storage and their respective download URLs stored to real-time database.)
let storageRef = Storage.storage().reference()
//Let's upload all workout pictures
let uploadPicsRef =
storageRef.child("WORKOUTDATA/USERS/"+self.UID!).child("WHITEBOARDWORKOUTS")
let uploadNumberRef = uploadPicsRef.child("\(String(describing: workoutNum))")
let workoutPicturesRef = uploadNumberRef.child("WORKOUTPICTURES")
let workoutPicURLRef = workoutRef.child("WORKOUTPICTURESURL")
var count = 0
var picNumber = 0
//workoutPictures list/array contains images selected from iPhone Gallery, using
//UIImagePickerController
for workoutPic in self.workoutPictures
{
let workoutPicData = workoutPic.jpegData(compressionQuality: 1.0)!
count = count + 1
let pictureName = "Picture\(count).jpg"
// Upload the file to the path in pictureRef
let pictureRef = workoutPicturesRef.child("\(pictureName)")
let metaData = StorageMetadata()
metaData.contentType = "image/jpg"
pictureRef.putData(workoutPicData, metadata: metaData) { (metadata, error) in
if error != nil {
print("Error while uploading image")
}
else
{
pictureRef.downloadURL { (url, err) in
picNumber = picNumber + 1
workoutPicURLRef.child("Picture\(picNumber)").setValue(url?.absoluteString)
}
}
}
}
The code to download image:
let myGroup = DispatchGroup()
let workoutPicUrls = snapshot.childSnapshot(forPath: "WORKOUTPICTURESURL")
for url in workoutPicUrls.children
{
myGroup.enter()
let snap = url as! DataSnapshot
let link = snap.value as? String
let storageRef = Storage.storage().reference()
let pictureRef = storageRef.root().child(link!)
DispatchQueue.main.async {
pictureRef.getData(maxSize: 1*2000000*2000000) { (data, err) in
if (err != nil) {
print(err!)
print(err!.localizedDescription)
} else {
let pic = UIImage(data: data!)
workoutPicsArray.append(pic!)
myGroup.leave()
}
}
}
}
Error:
Error Domain=FIRStorageErrorDomain Code=-13010 "Object https:/firebasestorage.googleapis.com/v0/b/trainer-8cb52.appspot.com/o/WORKOUTDATA%2FUSERS%2F1K7WV1alYIeWPAsFC6YMoJKPFSj1%2FWHITEBOARDWORKOUTS%2F5%2FWORKOUTPICTURES%2FPicture1.jpg?alt=media&token=785ab8c7-1e08-4ad3-a542-c9e6313eb547 does not exist." UserInfo={object=https:/firebasestorage.googleapis.com/v0/b/trainer-8cb52.appspot.com/o/WORKOUTDATA%2FUSERS%2F1K7WV1alYIeWPAsFC6YMoJKPFSj1%2FWHITEBOARDWORKOUTS%2F5%2FWORKOUTPICTURES%2FPicture1.jpg?alt=media&token=785ab8c7-1e08-4ad3-a542-c9e6313eb547, ResponseBody={
"error": {
"code": 404,
"message": "Not Found. Could not get object",
"status": "GET_OBJECT"
}
}, bucket=trainer-8cb52.appspot.com, data={length = 115, bytes = 0x7b0a2020 22657272 6f72223a 207b0a20 ... 54220a20 207d0a7d }, data_content_type=application/json; charset=UTF-8, NSLocalizedDescription=Object https:/firebasestorage.googleapis.com/v0/b/trainer-8cb52.appspot.com/o/WORKOUTDATA%2FUSERS%2F1K7WV1alYIeWPAsFC6YMoJKPFSj1%2FWHITEBOARDWORKOUTS%2F5%2FWORKOUTPICTURES%2FPicture1.jpg?alt=media&token=785ab8c7-1e08-4ad3-a542-c9e6313eb547 does not exist., ResponseErrorDomain=com.google.HTTPStatus, ResponseErrorCode=404}
What I have tried so far:
Checked firebase storage rules.
When I paste the path https:/firebasestorage.googleapis.com/v0/b/trainer8cb52.appspot.com/o/WORKOUTDATA%2FUSERS%2F1K7WV1alYIeWPAsFC6YMoJKPFSj1%2FWHITEBOARDWORKOUTS%2F5%2FWORKOUTPICTURES%2FPicture1.jpg?alt=media&token=785ab8c7-1e08-4ad3-a542-c9e6313eb547 in chrome browser window, the expected image opens.
Set the maxSize to a ridiculously high number 1*2000000*2000000.
Thank you!
Is it possible that you are storing the full https URL in the database and are trying to create a reference by adding the full https url as a child to the storage reference?
I think you should try to either store just the path and name in your database or you change your download code to use the https URL.
// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
let httpsReference = storage.reference(forURL: "https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg")
httpsReference.getData(maxSize: ...
Also you're running your getData method inside DispatchQueue.main.async. getData has itself a completion handler and might take some time, when you run that inside of DispatchQueue.main.async it will block your code until the download is done. Only put code that update the UI inside DispatchQueue.main.async. In your case as soon as you do something with your workoutPicsArray or the UIImage to update your view.
Have a look here to see if you can figure out how you are actually trying to get the data. It might be helpful to put a print() after each line to see what you are creating and using at what point.
Download Files on iOS

Process for uploading image to s3 with AWS Appsync || iOS image uploading with Appsync

I'm working on a new project that requires uploading attachments in the form of images. I'm using DynamoDB and AppSync API's to insert and retrieve data from database. As we are new to the AppSync and all the amazon services and database we are using for the app i'm little bit confused about the authentication process. Right now we are using API key for authentication and I have tried these steps to upload image to s3.
1 Configue the AWSServiceManager with static configuration like :-
let staticCredit = AWSStaticCredentialsProvider(accessKey: kAppSyncAccessKey, secretKey: kAppSyncSecretKey)
let AppSyncRegion: AWSRegionType = .USEast2
let config = AWSServiceConfiguration(region: AppSyncRegion, credentialsProvider: staticCredit)
AWSServiceManager.default().defaultServiceConfiguration = config
2 Uploading picture with this method : -
func updatePictureToServer(url:URL, completion:#escaping (Bool)->Void){
let transferManager = AWSS3TransferManager.default()
let uploadingFileURL = url
let uploadRequest = AWSS3TransferManagerUploadRequest()
let userBucket = String(format: "BUCKET")
uploadRequest?.bucket = userBucket
let fileName = String(format: "%#%#", AppSettings.getUserId(),".jpg")
uploadRequest?.key = fileName
uploadRequest?.body = uploadingFileURL
transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if let error = task.error as NSError? {
if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
switch code {
case .cancelled, .paused:
break
default:
print("Error uploading: \(String(describing: uploadRequest!.key)) Error: \(error)")
}
} else {
print("Error uploading: \(String(describing: uploadRequest!.key)) Error: \(error)")
}
completion(false)
return nil
}
_ = task.result
completion(true)
print("Upload complete for: \(String(describing: uploadRequest!.key))")
return nil
})
}
3 And finally i'm able to see the uploaded image on the S3 bucket
But i'm concerned about how to save the url of the image and how to retrieve the image because when i have to make the buket PUBLIC to retrieve the image and i don't think that's a good approach, plus is it necessary to have a Cognito user pool because we aren't using Cognito user pool yet in our app and not have much knowledge about that too and documents are not helping in practical situations because we are implementing ti for the first time so we need some little help.
So two question : -
Proper procedure to use for uploading and retrieving images for S3 and AppSync.
Is it necessary to use Cognito user pool for image uploading and retrieving.
Thanks
Note: Any suggestion or improvement or anything related to the AppSync, S3 or DynamoDB will be truly appreciated and language is not a barrier just looking for directions so swift or objective-c no problem.
You need per-identity security on the bucket using Cognito Federated Identities which gives each user their own secure bucket. You can leverage the AWS Amplify to set this up for your project with $amplify add auth and selecting the default config, then $amplify add storage which configures that bucket and pool with appropriate permissions to use private uploads.
For more info checkout the repo: https://github.com/aws-amplify/amplify-cli

How to upload a video from iOS photo album to Azure Blob Storage

I am struggling with uploading videos from iOS photo album to Azure blob storage. I am using AZSClient.
uploading images is straight forward, ie. I get the image 'Data' from PHAsset and then upload it to azure storage using AZSCloudBlockBlob.uploadFromData method
Can anyone guide me on how to upload a video to azure blob preferably in swift
There was a similar thread for this they used the bellow code, and they used the IOS library found here:
//Upload to Azure Blob Storage with help of SAS
func uploadBlobSAS(container: String, sas: String, blockname: String, fromfile: String ){
// If using a SAS token, fill it in here. If using Shared Key access, comment out the following line.
var containerURL = "https://yourblobstorage.blob.core.windows.net/\(container)\(sas)" //here we have to append sas string: + sas
print("containerURL with SAS: \(containerURL) ")
var container : AZSCloudBlobContainer
var error: NSError?
container = AZSCloudBlobContainer(url: NSURL(string: containerURL)! as URL, error: &error)
if ((error) != nil) {
print("Error in creating blob container object. Error code = %ld, error domain = %#, error userinfo = %#", error!.code, error!.domain, error!.userInfo);
}
else {
let blob = container.blockBlobReference(fromName: blockname)
blob.uploadFromFile(withPath: fromfile, completionHandler: {(NSError) -> Void in
NSLog("Ok, uploaded !")
})
}
}
I found the answer in this thread
let manager = PHImageManager.default()
manager.requestAVAsset(forVideo: asset, options: nil, resultHandler: { (avasset, audio, info) in
if let avassetURL = avasset as? AVURLAsset {
guard let video = try? Data(contentsOf: avassetURL.url) else {
return
}
videoData = video
}
})
once you get the Data object then you can use AZSCloudBlockBlob.uploadFromData to upload it to azure storage

How to save PDF files from Firebase Storage into App Documents for future use?

I have connected my App with the Firebase Storage where my 19ea PDF files exists.
I would like to download those files and save them locally for future use.
Those PDF files will be used inside UIWebviews but they may need to be updated in time. Therefore, I have configured version control system with Firebase Database, so I will be able to push the newer versions when I update the files in the storage.
So, how I can save those files locally? (to a folder like: user/myapp/Documents/PDF etc?)
Also, how I can check if that folder contains any documents and how to delete them before downloading new files?
Here is what I have got so far.
I appreciate all the help.
// Firebase Storage Connection
static var refStorage:FIRStorageReference?
static var dataPDF = [NSData]()
func newDataDownload(){
// Compare Current Data Version with Online Data Version
if myFirebaseData.localDataVersion < myFirebaseData.onlineDataVersion {
// Set Firebase Storage Reference
myFirebaseData.refStorage = FIRStorage.storage().reference()
for i in 1...myFirebaseData.onlineTotalPDFCount {
// Create a reference to the file you want to download
let pulledPDF = FIRStorage.storage().reference().child("/PDF/\(i).pdf")
// Create local filesystem URL
let localURL = URL(string: "myApp/Documents/PDF/\(i)")!
pulledPDF.data(withMaxSize: myFirebaseData.maxPDFdownloadSize, completion: { (downPDF, err) in
if err == nil {
// Accessed the data
myFirebaseData.dataPDF.append(downPDF! as NSData)
print(myFirebaseData.dataPDF)
} else {
// If there is an error print it
print(err.debugDescription)
}
})
}
}
// If Data is successfully downloaded update Local Data Version
myFirebaseData.localDataVersion = myFirebaseData.onlineDataVersion
Use storageRef.write(toFile: completion:) (docs), like:
// Create a reference to the file you want to download
let pdfRef = storageRef.child("files/file.pdf")
// Create local filesystem URL
let localURL = URL(string: "path/to/local/file.pdf")!
// Download to the local filesystem
let downloadTask = pdfRef.write(toFile: localURL) { url, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Local file URL for "path/to/local/file.pdf" is returned
}
}
Note that you can only write to /tmp and /Documents due to app sandboxing requirements (see Downloading Firebase Storage Files Device Issue for an example of how this fails otherwise).

How do I store private app data on Google Drive with my iOS app?

I have an iOS app that has a local database. I'd like to back that up for users who choose to sign in with Google. The web (https://developers.google.com/drive/web/appdata) and android (https://developers.google.com/drive/android/appfolder) have guides on how to do this, but I can't find a similar one for iOS. Does it exist?
If you already have code to upload a file to the user's Drive account, it is very easy to switch to uploading into the private app folder instead. When making the Files.insert call, the file will be added to all of the folders listed in the parents[] array. (If this array is empty, by default the file is added to the root folder.) To upload the file into the private app data folder, simply set the parents[] array to appfolder. You have to do this at the same time as uploading the file, because once it has been uploaded the file can't be moved between the user's drive and your app's private data folder.
(Note: you may need to use the regular REST API to do this, because Google's Drive API for iOS docs do not show any methods for actually uploading a new file to Drive.)
Check this how this is working for me in swift 4.2 and above:
let googleDrive: GTLRDrive_File = GTLRDrive_File()
googleDrive.name = "name.json"
googleDrive.parents = ["appDataFolder"]
let uploadParam: GTLRUploadParameters = GTLRUploadParameters(data: data, mimeType: "application/json")
uploadParameters.shouldUploadWithSingleRequest = true;
let queryDrive: GTLRDriveQuery_FilesCreate = GTLRDriveQuery_FilesCreate.query(withObject: metadata, uploadParameters: uploadParam)
queryDrive.fields = "id"
self.service.executeQuery(queryDrive) { (result, response, error) in
if let file = response as? GTLRDrive_File {
if (error == nil) {
print(file.identifier)
/// your code here
} else {
// handle error part
}
}
else {
//handle exception part
}
}
"data" the json data you get this like below
let param = [["key": "value"], ["key": "value"], ["key": "value"]]
let data = try JSONSerialization.data(withJSONObject: param, options: .prettyPrinted)

Resources