I have two viewcontrollers: GetStartedViewController (root viewController) and TrimVideoViewController. I pick a video from the root one using PHPicker and I need to play that video in the second viewController. The problem is that when I provide the url to AVFoundation nothing happens. I am at a loss.
I've scoured the internet and cannot find an answer to this.
I saw a single solution to this saying I need to copy and save to another directory and use that directory with AVFoundation. It still didn't work.
I also searched for a framework that could maybe play videos from gallery, but most of them only played using HTTP links.
can anyone help me with this?
Here's the GetStartedViewController
Here's the TrimVideoViewController
please take note that you have fetched the URL but you didn't set self.url = url
changing your vc!.videoURL = url to the following should make a difference
vc!.videoURL = url
Okay, after consulting with a more experienced iOS developer, we found that the url that was being passed by PHPicker was not suitable for AVFoundation. Instead we wrote this function that relocates the video and makes it suitable for AVFoundation.
private func getVideo(from itemProvider: NSItemProvider, typeIdentifier: String) {
itemProvider.loadFileRepresentation(forTypeIdentifier: typeIdentifier) { url, error in
if let error = error {
print(error.localizedDescription)
}
guard let url = url else { return }
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
guard let targetURL = documentsDirectory?.appendingPathComponent(url.lastPathComponent) else { return }
do {
if FileManager.default.fileExists(atPath: targetURL.path) {
try FileManager.default.removeItem(at: targetURL)
}
try FileManager.default.copyItem(at: url, to: targetURL)
DispatchQueue.main.async {
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "TrimVideooViewController") as? TrimVideooViewController
vc!.videoURL = targetURL
self.navigationController?.pushViewController(vc!, animated: true)
}
} catch {
print(error.localizedDescription)
}
}
}
enjoy!
Related
I am working on a swift application in which users have a link of videos like facebook etc and if the user wishes to download that he can just put a link in UITextfield and download it. The code I tried is
func downloadAndSaveVideo(videoUrl:String?,videoName:String) {
DispatchQueue.global(qos: .background).async {
guard let myUrl = videoUrl else {
print("Invalid Url")
return
}
Alamofire.request(myUrl).downloadProgress(closure: { (Progress) in
print(Progress)
self.progress_view.progress = Float(Progress.fractionCompleted)
}).responseData(completionHandler: { (responce) in
if let data = responce.result.value{
print(data)
let documentUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let videoUrl = documentUrl.appendingPathComponent(videoName)
do {
try data.write(to: videoUrl)
print("done")
}catch
{
print("error")
}
}
})
}
}
This code is working fine if I use a playable link like this. but if try to put facebook link like https://www.facebook.com/pagename/videos/962353737470453/ or youtube I am unable to download that video
can someone help me to how to download such videos or convert facebook video share link to watch or downloadable link so that I can download videos directly from my app.
I'm trying to play audio files from URLs in an iOS app (Swift 4). I'd like them to buffer and play while downloading. And I quite like AudioKit, but for the life of me and I can't figure out how to make it read remote files.
Any suggestions?
You can't find it because its not there. We've never implemented any streaming functionality. It could be added though, and a number of people like yourself would be quite pleased. Consider contributing some code if you manage to work it out. We can offer you membership to AudioKit's Slack group during development if you wish.
If you only need to stream and play audio files you might just use AVFoundation.AVPlayer. If you want to integrate it into AudioKit then more is needed currently.
You can cache the URL of the remote file locally then load that cached file into AKPlayer. Obviously not streaming - but it will work:
guard let remote = URL(string: "https://www.sample-videos.com/audio/mp3/crowd-cheering.mp3"),
let data = NSData(contentsOf: remote) else {
AKLog("Remote failed to load.")
return
}
let cachedFile = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(remote.lastPathComponent)
try? data.write(to: cachedFile)
let player = AKPlayer(url: cachedFile)
Note that this is just a quick macOS sample - you will likely want to write to a temp directory or some other place.
I tried using Ryan Francesconi's solution and it works. But when I stoped the player once and trying to play again, I got the error below.
func setupPlayer() {
guard let remote = URL(string: "https://xxxxxx.mp3"),
let data = NSData(contentsOf: remote) else {
print("Remote failed to load.")
return
}
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let cachedFile = documentsDirectoryURL.appendingPathComponent(remote.lastPathComponent)
try? data.write(to: cachedFile)
try? player.load(url: cachedFile)
}
But finally I managed to fixed it doing the following:
func setupPlayer() {
guard let remote = URL(string: "https://https://xxxxxx.mp3"),
let data = NSData(contentsOf: remote) else {
print("Remote failed to load.")
return
}
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
cachedFile = documentsDirectoryURL.appendingPathComponent(remote.lastPathComponent)
try? data.write(to: cachedFile)
try? player.load(url: cachedFile)
}
func stop() {
engine.stop()
}
func pause() {
currentTime = player.getCurrentTime()
player.pause()
}
func play() {
try? player.load(url: cachedFile)
player.editStartTime = currentTime
print(currentTime)
player.play()
}
Done.
I need to share an image file to Instagram, and according to Instagram doc: https://www.instagram.com/developer/mobile-sharing/iphone-hooks/, I can use Document Interaction to implement this, but it just doesn't work. Here is my code:
let img = UIImage(named: "test.jpg")
let kInstagramURL = URL(string: "instagram://")
let kUTI = "com.instagram.exclusivegram" // testing "com.instagram.photo" too
let instagramCaption = "TESTING"
let kfileNameExtension = "instagram.igo" // testing "jpg"/"ig" too
if UIApplication.shared.canOpenURL(kInstagramURL!) {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if urls.count == 0 {
print("Not found")
return
}
let url = urls[0].appendingPathComponent(kfileNameExtension)
print("URL", url)
// OUPUT: file:///var/mobile/Containers/Data/Application/F14B18CB-5CD4-47AD-8257-E2288C23181E/Documents/instagram.igo
do {
try UIImageJPEGRepresentation(img!, 1.0)?.write(to: url, options: .atomic)
print("WRITEN", url) // Written successfully, no error
} catch {
//TODO: issue error on UI
print("WRITE ERROR: \(error)")
}
let documentInteractionController = UIDocumentInteractionController(url: url)
var rect = CGRect.zero
let view = self.view
documentInteractionController.delegate = DocInteractionResponder() // tried nil, same result
documentInteractionController.uti = kUTI
// adding caption for the image
documentInteractionController.annotation = ["InstagramCaption": instagramCaption]
documentInteractionController.presentOpenInMenu(from: rect, in: view!, animated: true)
}
else {
//TODO: warn from dialog
}
I have tried many things within this code snippet (see comments), but the result is the same: after I tap instagram in the menu, nothing happens.
I thought it may be caused by other code in my app, so I create a blank app (with one simple UIViewController) and put this code in. It doesn't work.
I have read almost all answers on SO related to UIDocumentInteractionController.
Does this happen to you? Is this the problem with iOS 11 (just upgraded my phone), or maybe Instagram stop supporting Document Interaction?
I just came across the same issue today, and I was able to solve it by declaring the UIDocumentInteractionController as a class-level property in the view controller, to prevent it from getting deallocated too soon.
I'm trying to open a .pdf file after download which is downloaded with Alamofire. But I've seen only using a "webview". Thus the application consumes lots of memory and is not viable.
What I want is to open it with the native device application. Any suggestions? Thank you.
Edit: This is my code for download file:
var localPath: NSURL?
Alamofire.download(.GET, url, destination: { (temporaryURL, response) in
let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
localPath = directoryURL.URLByAppendingPathComponent(pathComponent!)
return localPath!
})
.response { (request, response, _, error) in
if error != nil
{
// got an error in getting the data, need to handle it
print("Error: \(error!)")
}
//print(response)
print("Download file en:\(localPath!)")
self.view.hideToastActivity()
//self.actioncall()
}
}
I need open file from localpath...
You should use UIDocumentInteractionController. You can read about it on this Apple documentation page.
By doing some Googling you should see even some example implementations. For example here you can see some code about this done by "mattneub".
I let you one more code that you can use:
var documentInteractionController: UIDocumentInteractionController!
#IBAction func openDocument(sender: UIButton) {
let URL: NSURL = NSBundle.mainBundle().URLForResource("yourPDF", withExtension: "pdf")!
if (URL != "") {
// Initialize Document Interaction Controller
self.documentInteractionController = UIDocumentInteractionController(URL: URL)
// Configure Document Interaction Controller
self.documentInteractionController.delegate = self
// Present Open In Menu
self.documentInteractionController.presentOptionsMenuFromRect(sender.frame, inView: self.view, animated: true)
//presentOpenInMenuFromRect
}
}
// UIDocumentInteractionControllerDelegate
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) -> UIViewController {
return self
}
I have uploaded some songs in firebase Storage directly,I just want to stream the song in AVAudioPlayer.
Below is the code which I am trying:
var mainRef: FIRStorageReference {
return FIRStorage.storage().reference(forURL: "gs://musicapp-d840c.appspot.com")
}
var audioStorageRef: FIRStorageReference{
return mainRef.child("SongsPath")
}
audioStorageRef.downloadURL { url, error in
if let error = error {
print(error.localizedDescription)
} else {
if let url = url {
do {
self.audioPlayer = try AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: String(describing: url)) as URL)
self.audioPlayer.play()
} catch {}
let storyboard = UIStoryboard(name: "AudioPlayer", bundle: nil)
let audioVc = storyboard.instantiateViewController(withIdentifier: "AudioPlayerViewController") as! AudioPlayerViewController
audioVc.playThisSong = String(describing: url)
self.present(audioVc, animated: false, completion: nil)
}
}
}
Here the song url from the firebase is passing but it is skipping the self.audioPlayer.play. ,I just want to stream the audio. Can I get a proper solution for this?
This is not an answer for streaming.
This is an answer for downloading the file, storing it locally, and playing the audio after the file has finished downloading.
Get a Firebase storage reference using a path string with the file extension. Get a file url to store it on the device using the same path string that we use for the Firebase storage reference.
Initiate the download task using write(toFile: URL). Store the download task in a variable to add observers. When the download is successful, play the audio.
In Swift 4:
var player: AVAudioPlayer?
let pathString = "SongsPath.mp3"
let storageReference = Storage.storage().reference().child(pathString)
let fileUrls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
guard let fileUrl = fileUrls.first?.appendingPathComponent(pathString) else {
return
}
let downloadTask = storageReference.write(toFile: fileUrl)
downloadTask.observe(.success) { _ in
do {
self.player = try AVAudioPlayer(contentsOf: fileUrl)
self.player?.prepareToPlay()
self.player?.play()
} catch let error {
print(error.localizedDescription)
}
}
This is minimal code. Implement error handling as you see fit.
Firebase example of downloading locally