Issues with read file permission Swift & Firebase - mobile not simulator - swift

I am attempting to upload a video from a custom UICollection that accesses the users videos. When I attempt to upload the URL to firebase, I get the following error:
Body file is unreachable: /var/mobile/Media/DCIM/103APPLE/IMG_3002.MOV
Error Domain=NSCocoaErrorDomain Code=257 "The file “IMG_3002.MOV” couldn’t be opened because you don’t have permission to view it." UserInfo={NSURL=file:///var/mobile/Media/DCIM/103APPLE/IMG_3002.MOV, NSFilePath=/var/mobile/Media/DCIM/103APPLE/IMG_3002.MOV, NSUnderlyingError=0x17024b790 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
I am a little confused as to why this is occuring, b/c when I print out the url of the video I get:
file:///var/mobile/Media/DCIM/103APPLE/IMG_3002.MOV
&& my info.plist looks like this
Here is the upload code:
videosFolder.child("\(nsuid).mov").putFile(self.videoURLToUpload, metadata: nil, completion: { (metadata, error) in
if error != nil {
print("we Had an Error!: \(String(describing: error))")
} else {
print("we uploaded the video correctly!!!")
}
})
&& just in-case here is the where I am fetching the videos
struct Media {
var image:UIImage?
var videoURL:NSURL?
}
var mediaArray = [Media]()
func grabPhotos(){
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count{
var mediaItem = Media()
//Used for fetch Image//
imgManager.requestImage(for: fetchResult.object(at: i) as PHAsset , targetSize: CGSize(width: 400, height: 400), contentMode: .aspectFit, options: requestOptions, resultHandler: {
image, error in
let imageOfVideo = image! as UIImage
mediaItem.image = imageOfVideo;
//Used for fetch Video//
imgManager.requestAVAsset(forVideo: fetchResult.object(at: i) as PHAsset, options: PHVideoRequestOptions(), resultHandler: {(avAsset, audioMix, info) -> Void in
if let asset = avAsset as? AVURLAsset {
let videoData = NSURL(string: "\(asset.url)")
let duration : CMTime = asset.duration
let durationInSecond = CMTimeGetSeconds(duration)
print(durationInSecond)
mediaItem.videoURL = videoData!
self.mediaArray.append(mediaItem)
print(self.mediaArray.count)
}
})
})
}
}
else{
//showAllertToImportImage()//A function to show alert
}
}
}
This issue is on the mobile not the simulator

Related

Save Image to Photo Library and retrieve the URL

I can save an image to my photo library using the following code:
PHPhotoLibrary.shared().performChanges({
PHAssetCreationRequest
.creationRequestForAssetFromImage(atFileURL: outfileURL)
}) { (saved, err) in
print("Saved?", saved)
if (saved) {
DispatchQueue.main.async {
onComplete(outfileURL.absoluteString)
}
}
}
But I am trying to load the image I just saved in an Image (SwiftUI) and I want to get the new images fileURL. The outfileURL is a temp file and is not retained. Please note this is a gif - if that has any bearing.
I am trying to use the PHObjectPlaceholder thing but I still don't know how to get the location out:
var placeHolder: PHObjectPlaceholder? = nil
PHPhotoLibrary.shared().performChanges({
let changeRequest = PHAssetCreationRequest.creationRequestForAssetFromImage(atFileURL: outfileURL)
placeHolder = changeRequest?.placeholderForCreatedAsset
}) { (saved, err) in
print("Saved? \(saved) to location \(placeHolder?)") //<--- AAAARGH!!!!
if (saved) {
DispatchQueue.main.async {
onComplete(/*????*/)
}
}
}
From PHObjectPlaceholder you can use localIdentifier
let fetchOptions = PHFetchOptions()
let fetchResult: PHFetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [placeholder.localIdentifier], options: fetchOptions)
if let asset = fetchResult.firstObject {
// Here you can get UIImage from PHAsset
}
So this is possible solution:
var placeHolder: PHObjectPlaceholder? = nil
PHPhotoLibrary.shared().performChanges({
let changeRequest = PHAssetCreationRequest.creationRequestForAssetFromImage(atFileURL: outfileURL)
placeHolder = changeRequest?.placeholderForCreatedAsset
}) { (saved, err) in
if let localIdentifier = placeHolder?.localIdentifier, saved {
let fetchOptions = PHFetchOptions()
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: fetchOptions)
if let phAsset = fetchResult.firstObject {
let targetSize = CGSize(width: CGFloat(phAsset.pixelWidth), height: CGFloat(phAsset.pixelHeight))
let options = PHImageRequestOptions()
PHCachingImageManager.default().requestImage(for: phAsset, targetSize: targetSize, contentMode: .aspectFill, options: options) { (uiImage, info) in
DispatchQueue.main.async {
onComplete(uiImage)
}
}
}
}
}

Swift4.2 grab screenshot from Video

in Swift 4.2 I am trying to grab screenshot from video
func thumbnailImageFor(fileUrl:URL) -> UIImage? {
let asset = AVAsset(url: fileUrl)
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
assetImgGenerate.appliesPreferredTrackTransform = true
let time = CMTimeMakeWithSeconds(1.0, preferredTimescale: 600)
do {
let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
let thumbnail = UIImage(cgImage: img)
return thumbnail
} catch {
print(error)
return nil
}
}
But getting error:
Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could
not be completed" UserInfo={NSLocalizedFailureReason=An unknown error
occurred (-12792), NSLocalizedDescription=The operation could not be
completed, NSUnderlyingError=0x600000f46580 {Error
Domain=NSOSStatusErrorDomain Code=-12792 "(null)"}}
video's url:
https://firebasestorage.googleapis.com/v0/b/lailaichatapp.appspot.com/o/message_movies%2F8A61AC4E-4A08-4EC7-BC78-A5D861BE48C5.mov?alt=media&token=8906971d-59d7-4880-988e-135615c10f22
am I missing something?
I think it may be an issue with the filetype of the movie, as this works:
import UIKit
import AVFoundation
func thumbnailImageFor(fileUrl:URL) -> UIImage? {
let video = AVURLAsset(url: fileUrl, options: [:])
let assetImgGenerate = AVAssetImageGenerator(asset: video)
assetImgGenerate.appliesPreferredTrackTransform = true
let videoDuration:CMTime = video.duration
let durationInSeconds:Float64 = CMTimeGetSeconds(videoDuration)
let numerator = Int64(1)
let denominator = videoDuration.timescale
let time = CMTimeMake(value: numerator, timescale: denominator)
do {
let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
let thumbnail = UIImage(cgImage: img)
return thumbnail
} catch {
print(error)
return nil
}
}
let url: URL = URL(string: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4")!
let image: UIImage? = thumbnailImageFor(fileUrl: url)
print("Image: \(image)")

SWIFT: Crash when trying to fetch all Images From Library

The app keeps crashing when I attempt to fetch all images from library, the message from debugger is: Terminated due to memory issue
Any idea how can fix it? Here is my code:
func fetchImagesFromLibrary() {
let fetchOptions: PHFetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
fetchResult.enumerateObjects { (object, index, stop) -> Void in
let options = PHImageRequestOptions()
options.isSynchronous = false
options.deliveryMode = .fastFormat
PHImageManager.default().requestImage(for: fetchResult.object(at: index) as PHAsset, targetSize: self.view.frame.size, contentMode: PHImageContentMode.aspectFill, options: .none, resultHandler: { (image, _) in
if let image = image {
print(image)
//self.imageview1.image = image
}
}
)
}
}

Error Domain=NSCocoaErrorDomain Code=257 The fil "" could not be opened - Firebase

So I am accessing the user's videos & photos through a custom UICollectionView, my issue is that when I attempt to upload to firebase the video through the mobile phone, i am getting this error:
2017-09-03 13:09:20.884509-0400 Project[5797:2021536] Cannot get file size: Error Domain=NSCocoaErrorDomain Code=257 "The file “IMG_3476.MP4” couldn’t be opened because you don’t have permission to view it." UserInfo={NSURL=file:///var/mobile/Media/DCIM/103APPLE/IMG_3476.MP4, NSFilePath=/var/mobile/Media/DCIM/103APPLE/IMG_3476.MP4, NSUnderlyingError=0x17064f450 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
/var/mobile/Media/DCIM/103APPLE/IMG_3476.MP4
2017-09-03 13:09:21.261767-0400 Project[5797:2021536] Body file is unreachable: /var/mobile/Media/DCIM/103APPLE/IMG_3476.MP4
Error Domain=NSCocoaErrorDomain Code=257 "The file “IMG_3476.MP4” couldn’t be opened because you don’t have permission to view it." UserInfo={NSURL=file:///var/mobile/Media/DCIM/103APPLE/IMG_3476.MP4, NSFilePath=/var/mobile/Media/DCIM/103APPLE/IMG_3476.MP4, NSUnderlyingError=0x170651b20 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
Here is where I am loading the files
struct Media {
var image:UIImage?
var videoURL:NSURL?
}
var mediaArray = [Media]()
func grabPhotos(){
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count{
var mediaItem = Media()
//Used for fetch Image//
imgManager.requestImage(for: fetchResult.object(at: i) as PHAsset , targetSize: CGSize(width: 400, height: 400), contentMode: .aspectFit, options: requestOptions, resultHandler: {
image, error in
let imageOfVideo = image! as UIImage
mediaItem.image = imageOfVideo;
//Used for fetch Video//
imgManager.requestAVAsset(forVideo: fetchResult.object(at: i) as PHAsset, options: PHVideoRequestOptions(), resultHandler: {(avAsset, audioMix, info) -> Void in
if let asset = avAsset as? AVURLAsset {
let videoData = NSURL(string: "\(asset.url)")
let duration : CMTime = asset.duration
let durationInSecond = CMTimeGetSeconds(duration)
print(durationInSecond)
mediaItem.videoURL = videoData!
self.mediaArray.append(mediaItem)
print(self.mediaArray.count)
}
})
})
}
}
else{
//showAllertToImportImage()//A function to show alert
}
}
}
I dont think it has to do with when I am uploading the video because i can record a video an upload it from the phone, just not upload from the phone itself; I am just transferring over the url to the nextVC like so:
let videoVC = PrepareVideoVC()
videoVC.url = outputFileURL as URL!
self.navigationController?.pushViewController(videoVC, animated: false)
I looked into this The file “ ” couldn’t be opened because you don’t have permission to view it but couldnt really figure out how to implement it
I also came across https://stackoverflow.com/a/41517165/7823620 but once again I tried implementing it but couldnt get it to not give me errors
Also I can upload from the simulator but not the mobile phone
It is trying to get a file from this directory:
NSFilePath=/var/mobile/Media/DCIM/
You can try
url.startAccessingSecurityScopedResource()
<...>
url.stopAccessingSecurityScopedResource()
use this options:
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionCurrent;
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
options.networkAccessAllowed = true;
if you request the middle-quality video, then u will get an error " Error Domain=NSCocoaErrorDomain Code=257, no permission..."
So if the AppDelegate gets passed in a document on launch via this method:
func application(_: UIApplication, open url: URL, options _: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
I found that I had to do this to FIX it so that FileManager documents loaded successfully using Ivan's solution above but you CAN NOT make that call if say the document is an e-mail attachment.
This fixed it for me and huge thanks again to Ivan Vavilov for his post.
func application(_: UIApplication, open url: URL, options _: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
print("Doc attachment passed")
let docAttachment = url
// files written to 'tmp' are NOT backed up to iCloud or iTunes
let tempDir = getTempDirectory()
// add file name to tmp path
tempFileToLoad = tempDir.appendingPathComponent(docAttachment.lastPathComponent)
let fm = FileManager()
// passed a file from the FileManger app?
let isAttachmentScopedResource = docAttachment.startAccessingSecurityScopedResource()
do {
// put in tmp so we can read/write
try fm.copyItem(at: docAttachment, to: tempFileToLoad!)
if(isAttachmentScopedResource) {
// have MUST release the security access after calling it
docAttachment.stopAccessingSecurityScopedResource()
}
} catch {
print("Error getting file. \(error)")
return false
}

Saving Video to Parse & Playback

So i'm using this custom class to record my video -- https://github.com/piemonte/PBJVision. I am attempting to record video in my iOS app and I can't seem to get the code correct to upload the file to my parse server. A few things:
In the PBJVision class it allows you to use NSURL(fileWithPath:videoPath) to access the asset after the video has been recorded.
To access the Data in the asset and save to Parse, I use the following function:
func vision(vision: PBJVision, capturedVideo videoDict: [NSObject : AnyObject]?, error: NSError?) {
if error != nil {
print("Encountered error with video")
isVideo = false
} else {
let currentVideo = videoDict
let videoPath = currentVideo![PBJVisionVideoPathKey] as! String
print("The video path is: \(videoPath)")
self.player = Player()
self.player.delegate = self
self.player.view.frame = CGRect(x: cameraView.frame.origin.x, y: cameraView.frame.origin.y, width: cameraView.frame.width, height: cameraView.frame.height)
self.player.playbackLoops = true
videoUrl = NSURL(fileURLWithPath: videoPath)
self.player.setUrl(videoUrl)
self.cameraView.addSubview(self.player.view)
self.player.playFromBeginning()
nextButton.hidden = false
isVideo = true
let contents: NSData?
do {
contents = try NSData(contentsOfFile: videoPath, options: NSDataReadingOptions.DataReadingMappedAlways)
} catch _ {
contents = nil
}
print(contents)
let videoObject = PFObject(className: "EventChatroomMessages")
videoObject.setValue(user, forKey: "user")
videoObject.setValue("uG7v2KWBQm", forKey: "eventId")
videoObject.setValue(NSDate(), forKey: "timestamp")
let videoFile: PFFile?
do {
videoFile = try PFFile(name: randomAlphaNumericString(26) + ".mp4", data: contents!, contentType: "video/mp4")
print("VideoFile: \(videoFile)")
} catch _ {
print("error")
}
print(videoFile)
videoObject.setValue(videoFile, forKey: "image")
videoObject.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if success == true {
ProgressHUD.showSuccess("Video Saved.", interaction: false)
dispatch_async(dispatch_get_main_queue()) {
ProgressHUD.dismiss()
}
} else {
ProgressHUD.showError("Error Saving Video.", interaction: false)
dispatch_async(dispatch_get_main_queue()) {
ProgressHUD.dismiss()
}
}
}
}
}
I am then using a UITableView to display my data from Parse. Here is how I retrieve my asset back from Parse and into my AVPlayer():
// Create Player for Reaction
let player = Player()
player.delegate = self
player.view.frame = CGRectMake(0.0, nameLabel.frame.origin.y + nameLabel.frame.size.height + 0.0, self.view.frame.width, 150)
player.view.backgroundColor = UIColor.whiteColor()
let video = message.objectForKey("image") as! PFFile
let urlFromParse = video.url!
print(urlFromParse)
let url = NSURL(fileURLWithPath: video.url!)
print(url)
let playerNew = AVPlayer(URL: url!)
let playerLayer = AVPlayerLayer(player: playerNew)
playerLayer.frame = CGRectMake(0.0, nameLabel.frame.origin.y + nameLabel.frame.size.height + 0.0, self.view.frame.width, 150)
cell.layer.addSublayer(playerLayer)
playerLayer.backgroundColor = UIColor.whiteColor().CGColor
playerNew.play()
I copy the value that is returned from urlFromParse which is (http://parlayapp.herokuapp.com/parse/files/smTrXDGZhlYQGh4BZcVvmZ2rYB9kA5EhPkGbj2R2/58c0648ae4ca9900f2d835feb77f165e_file.mp4) and paste it into my browser and the video plays in browser. Am I correct to assume the file has been saved correctly?
When I go to run my app, the video does not play.Any suggestion on what i'm doing wrong?
I have found that playing video using the pfFile.url does not work. You have to write the NSData from the PFFIle to a local file using the right extension (mov) and then play the video using the local file as the source.