Save Firebase Storage Video and Play with AVPlayerViewController - swift

Building an app that allows users to upload media to Firebase Storage. Upload seems to be working fine, however I can't get video downloads to play.
I saved a file to the app to test the AVPlayer and it works perfect.
func handleGesture() {
print("handle gesture")
if detailMediaType == "Video"{
performSegueWithIdentifier("toVideoView", sender: self)
print("video segue called")
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "toVideoView"){
let path = NSBundle.mainBundle().pathForResource("Apartment Ceiling Collapse- Queens, NY", ofType: "mp4")
var movieUrl = NSURL(fileURLWithPath: path!)
let filename = getDocumentsDirectory().stringByAppendingPathComponent("movie")
let videoData = NSData(contentsOfURL: movieUrl)
videoData!.writeToFile(filename, atomically: true)
self.avPlayer = AVPlayer(URL: movieUrl)
self.avPlayerViewController.player = self.avPlayer
self.presentViewController(self.avPlayerViewController, animated: false) { () -> Void in self.avPlayerViewController.player?.play()
}
}
}
Edit: I am now trying to download using downloadURLWithCompletion
FIRStorage.storage().referenceForURL(detailFullsizeUrl).downloadURLWithCompletion { (URL, error) -> Void in
if (error != nil)
{
print(error!)
}
else
{
self.firebaseUrl = URL!
print("firebaseUrl")
print(self.firebaseUrl)
self.avPlayer = AVPlayer(URL: self.firebaseUrl)
self.avPlayerViewController.player = self.avPlayer
}
}
I get an AVPlayerViewController with a black screen. When I access the "firebaseUrl" from the web, it downloads a text file that looks like gibberish.
Solution:
Changed up my approach. No longer saving to device. Instead I grabbed the "downloadUrl" metadata from the Firebase Storage object and pass it directly to the AVPlayerViewController.
let avPlayerViewController = AVPlayerViewController()
var avPlayer:AVPlayer? = nil
override func viewDidLoad() {
super.viewDidLoad()
FIRStorage.storage().referenceForURL(detailFullsizeUrl).metadataWithCompletion { (metadata, error) in
if error != nil{
print("error getting metadata")
} else {
let downloadUrl = metadata?.downloadURL()
print(downloadUrl)
if downloadUrl != nil{
self.avPlayer = AVPlayer(URL: downloadUrl!)
self.avPlayerViewController.player = self.avPlayer
print("downloadUrl obtained and set")
}
}
}
}
func handleGesture() {
print("handle gesture")
self.presentViewController(self.avPlayerViewController, animated: true) { () -> Void in
self.avPlayerViewController.player?.play()
}
}

Please check question. I updated it with the correct solution found on YouTube here: YouTube

Related

URL of screen recording from ReplayKit

I like to get the url of the ReplayKit screen recording instead of saving the video to my camera roll or forwarding it. From a WWDC 2017 video, it was mentioned that to get the url, one can use the following function:
func stopRecording(withOutput url: URL, completionHandler: ((Error?) -> Void)? = nil){}
But I am having a hard time figuring out how to call/implement this line of code. I have a start recording #IBAction button and a stop recording #IBAction button. The screen recording is working fine. However, can someone show me how or/and where to add this stopRecording function so I can get the url for the screen recording? Appreciate any help pointing me to the right direction. I am still learning Xcode. Thank-you!
#IBAction func StartScreenRec( sender: Any) {
screenrecorder.startRecording { (error) in
if let error = error {
print(error)
}
self.ScreenStartRecordBtn.isHidden = true
self.StopScreenRecBtn.isHidden = false
}
}
#IBAction func StopScreenRec( sender: Any) {
screenrecorder.stopRecording { (previewVC, error) in
if let previewVC = previewVC {
previewVC.modalPresentationStyle = .fullScreen
previewVC.previewControllerDelegate = self
self.present(previewVC, animated: true, completion: nil)
}
if let error = error {
print(error)
}
self.ScreenStartRecordBtn.isHidden = false
self.StopScreenRecBtn.isHidden = true
}
}
I hope this helps -
To get the URL of the Video that you've just recorded, you need to specify the URL first, then assign the withOutput Function:
outputURL = tempURL()
recorder.stopRecording(withOutput: outputURL) { (error) in
guard error == nil else{
print("Failed to save ")
return
}
print(self.outputURL)
}
And this is for the tempURL() Function:
func tempURL() -> URL? {
let directory = NSTemporaryDirectory() as NSString
if directory != "" {
let path = directory.appendingPathComponent(NSUUID().uuidString + ".mp4")
return URL(fileURLWithPath: path)
}
return nil
}

How To Get a URL for a Video Saved in Firebase Storage

For starters here is what I currently have:
func uploadToCloud(fileURL: URL){
let storage = Storage.storage()
let data = Data()
let storageRef = storage.reference()
let localFile = fileURL
let photoRef = storageRef.child("\(email)\(counter)")
let uploadTask = photoRef.putFile(from: localFile, metadata: nil) { (metadata, err) in
guard let metadata = metadata else {
print(err?.localizedDescription)
return
}
To upload the video to storage ^
func playVideo(url: URL) {
let player = AVPlayer(url: url)
let vc = AVPlayerViewController()
vc.player = player
self.present(vc, animated: true) { vc.player?.play() }
}
This is what I have to play the video ^
Originally I tried also saving the link to Firestore, but all it saved was the files location, I believe on the phone which is not what I am trying to do. Is there a way to I can get a the url for the video saved in storage to run it as a url in the playVideo function?
Thank you!
Try this to get
// ....
photoRef.downloadURL { (url, error) in
if let error = error {
print("DEBUG: Upload: \(error.localizedDescription)")
return
}
guard let videoUrl = url?.absoluteString else {
print("DEBUG: Upload failed get URL")
return
}
completion(videoUrl)
}

Share pdf on web view to another devices using swift code

I have a WKWebView which displayed pdf. I want to share the file to another devices such as iPad, iPhone.... using the share button. I tried to display the pdf in preview so it will have the iOS share button the code below.
import UIKit
import WebKit
class ShowPDFView: UIViewController, UIDocumentInteractionControllerDelegate {
#IBAction func SharePDFFile(_ sender: Any) {
let fileName = "testPDF"
guard let urlPath = Bundle.main.url(forResource: fileName, withExtension: "pdf") else {return}
let controller = UIDocumentInteractionController(url: urlPath)
controller.delegate = self
controller.presentPreview(animated: true)
}
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController!) -> UIViewController! {
return self
}
func documentInteractionControllerViewForPreview(controller: UIDocumentInteractionController!) -> UIView! {
return self.view
}
func documentInteractionControllerRectForPreview(controller: UIDocumentInteractionController!) -> CGRect{
return self.view.frame
}
I got runtime error.
[MC] Reading from private effective user settings.
The preview does not loaded. Does anyone know why?
This function works for me. In Swift 4
#IBAction func SharePDFFile(_ sender: Any) {
let fm = FileManager.default
var pdfURL = (fm.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
pdfURL = pdfURL.appendingPathComponent("johnMilky.pdf") as URL
//Rename document name to "myFile.pdf"
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("johnMilkyFile.pdf") as NSURL
do {
let data = try Data(contentsOf: pdfURL)
try data.write(to: url as URL)
let activitycontroller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
if activitycontroller.responds(to: #selector(getter: activitycontroller.completionWithItemsHandler))
{
activitycontroller.completionWithItemsHandler = {(type, isCompleted, items, error) in
if isCompleted
{
print("completed")
}
}
}
//activitycontroller.excludedActivityTypes = [UIActivity.ActivityType.airDrop]
activitycontroller.popoverPresentationController?.sourceView = self.view
self.present(activitycontroller, animated: true, completion: nil)
}
catch {
print(error)
}
}

AVPlayer with downloaded content doesn't work but streaming content does

I am trying to (1) download a piece of audio from a link, (2) add that newly-downloaded audio to an AVPlayer and (3) play it. Something is going wrong at step (3) and I'm looking for any guidance. Here's the code, including my alamofire and download functions, as I fear something may be going wrong at that stage.
import AVFoundation
class SettingAlarmViewController: UIViewController {
var player:AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
}
catch {
// report for an error
}
}
func getLatestPodcastURL(completion: #escaping (URL) -> ()) {
let RSSUrl: String = "https://www.npr.org/rss/podcast.php?id=510318"
Alamofire.request(RSSUrl).responseRSS() {response in
if let podcastURL: String = response.result.value?.items[0].enclosure!
{
let audioURL = URL(string: podcastURL)
completion(audioURL!)
}
else {
//error handling
}
}
}
func downloadSongAsynch(audioUrl: URL, completion: #escaping (URL) -> ()) {
let fileManager = FileManager.default
let documentsDirectoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("podcasts/")
do {
try fileManager.createDirectory(atPath: documentsDirectoryURL.path,
withIntermediateDirectories: true, attributes: nil)
} catch {
//error handling
}
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) -> Void in
guard let location = location, error == nil else { return }
do {
try FileManager.default.moveItem(at: location, to: destinationUrl)
} catch {
//error handling
}
}).resume()
completion(destinationUrl)
}
#IBAction func SetUpBotton(_ sender: Any) {
getLatestPodcastURL() {response in
//Uses an asynchronous call to Alamofire to get the podcast URL
self.downloadPodcastAsynch(audioUrl: response){response2 in
self.player = AVPlayer(url: response2)
print(self.player.currentItem)
}
#IBAction func PlayButton(_ sender: Any) {
player.play()
print(player.currentItem)
}
The log consistently shows my current item: >
But nothing plays. I have checked that the audio is working by trying to use the URL to stream this content. That works fine. I am getting the following:
BoringSSL errors "[BoringSSL] Function boringssl_session_errorlog: line 2871 [boringssl_session_read] SSL_ERROR_ZERO_RETURN(6): operation failed because the connection was cleanly shut down with a close_notify alert
but from what I've read, this is just a bug in the latest update and shouldn't be impacting the download. Any thoughts on this?

How to Play And Stop an AVAudioPlayer in swift3?

I am developing an audio Player in swift and I need 2 buttons ( Play and Stop ) to control it. I have used the following code:
override func viewDidLoad() {
super.viewDidLoad()
let urlstring = "http://radio.spainmedia.es/wp-content/uploads/2015/12/tailtoddle_lo4.mp3"
let url = NSURL(string: urlstring)
print("the url = \(url!)")
downloadFileFromURL(url: url!)
}
func downloadFileFromURL(url:NSURL) {
var downloadTask:URLSessionDownloadTask
downloadTask = URLSession.shared.downloadTask(with: url as URL, completionHandler: { (URL, response, error) -> Void in
self.play(url: URL! as NSURL)
})
downloadTask.resume()
}
func play(url:NSURL) {
print("playing \(url)")
do {
self.SoundPlayer = try AVAudioPlayer(contentsOf: url as URL)
SoundPlayer.prepareToPlay()
SoundPlayer.volume = 1.0
SoundPlayer.play()
} catch let error as NSError {
//self.player = nil
print(error.localizedDescription)
} catch {
print("AVAudioPlayer init failed")
}
}
#IBAction func Play(_ sender: Any) {
SoundPlayer.play()
}
#IBAction func Stop(_ sender: Any) {
SoundPlayer.stop()
}
Basically, when the user opens the app, the mp3 audio file starts automatically. Therefore I have created 2 additional buttons, Start and Stop and I want to control this Audio Player with them. Would you please advice me how to do it, because now they are not connected with the Audio Player and no action is performed when I click on them.
If your objective is to just play the file while streaming it, get the Data from the URL from and then pass it to the AVAudioPlayer.
if let theURL = URL(string: "http://radio.spainmedia.es/wp-content/uploads/2015/12/tailtoddle_lo4.mp3") {
if let data = try? Data(contentsOf: theURL){
if let audioPlayer = try? AVAudioPlayer(data: data) {
print("Done")
audioPlayer.play()
} else {
print("Noo")
}
}
}
AVAudioPlayer(contentsOf: url as URL) often fails to fetch data from remote location.
You can also check other options such as AVPlayer to play your file
how can i play remote .mp3 file in my ios application?