I am using ARKit for my application and I try to dynamically load .scn files from my web-server(URL)
Here is a part of my code
let urlString = "https://da5645f1.ngrok.io/mug.scn"
let url = URL.init(string: urlString)
let request = URLRequest(url: url!)
let session = URLSession.shared
let downloadTask = session.downloadTask(with: request,
completionHandler: { (location:URL?, response:URLResponse?, error:Error?)
-> Void in
print("location:\(String(describing: location))")
let locationPath = location!.path
let documents:String = NSHomeDirectory() + "/Documents/mug.scn"
ls = NSHomeDirectory() + "/Documents"
let fileManager = FileManager.default
if (fileManager.fileExists(atPath: documents)){
try! fileManager.removeItem(atPath: documents)
}
try! fileManager.moveItem(atPath: locationPath, toPath: documents)
print("new location:\(documents)")
let node = SCNNode()
let scene = SCNScene(named:"mug.scn", inDirectory: ls)
let nodess = scene?.rootNode.childNode(withName: "Mug", recursively: true)
node.addChildNode(nodess!)
let nodeArray = scene!.rootNode.childNodes
for childNode in nodeArray {
node.addChildNode(childNode as SCNNode)
}
self.addChildNode(node)
self.modelLoaded = true
})
downloadTask.resume()
Nslog:
location:Optional(file:///private/var/mobile/Containers/Data/Application/A1B996D7-ABE9-4000-91DB-2370076198D5/tmp/CFNetworkDownload_duDlwf.tmp)
new location:/var/mobile/Containers/Data/Application/A1B996D7-ABE9-4000-91DB-2370076198D5/Documents/mug.scn
.scn file downloading with the above mentioned(new location) file path.. but when i try to use this downloaded file in SCNScene
let scene = SCNScene(named:"mug.scn", inDirectory: ls)
always scene value is nil.
error
Thread 4: Fatal error: Unexpectedly found nil while unwrapping an Optional value
how to resolve this issues. Thank you
About init?(named: String), the documentation says:
Loads a scene from a file with the specified name in the app’s main bundle
since you don't have such file inside the main bundle (is coming from a download), you may try with the following constructor:
init(url: URL, options: [SCNSceneSource.LoadingOption : Any]? = nil)
so your code might be:
do {
let documents = "yourValidPath"
let scene = try SCNScene(url: URL(fileURLWithPath: documents), options: nil)
} catch {}
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let pathToObject = documentDirectory + "ship.scn"
let fileUrl = URL(fileURLWithPath: pathToObject)
guard let cshipScene = try? SCNScene(url: fileUrl, options: nil) else { return }
let shipNode = SCNNode()
let shipSceneChildNodes = shipScene.rootNode.childNodes
for childNode in shipSceneChildNodes {
shipNode.addChildNode(childNode)
}
node.addChildNode(shipNode)
Related
this is my swift class
import Foundation
import AVFoundation
class MusicPlayer{
static let shared = MusicPlayer()
var audioPlayer: AVAudioPlayer?
func startBackgroundMusic(backgroundMusicFileName: String) {
if let bundle = Bundle.main.path(forResource: backgroundMusicFileName, ofType: "mp3") {
let backgroundMusic = NSURL(fileURLWithPath: bundle)
do {
audioPlayer = try AVAudioPlayer(contentsOf:backgroundMusic as URL)
guard let audioPlayer = audioPlayer else { return }
audioPlayer.numberOfLoops = -1
audioPlayer.volume = 1.0
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print(error)
}
}
}
func stopBackgroundMusic() {
guard let audioPlayer = audioPlayer else { return }
audioPlayer.stop()
}
}
And, here is my code for the Controller class
func downloadUsingAlamofire() {
let audioUrl = URL(string:"https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3")
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
Alamofire.download(
audioUrl!,
method: .get,
parameters: nil,
encoding: URLEncoding.default,
headers: nil,
to: destination).downloadProgress(closure: { (progress) in
}).response(completionHandler: { (DefaultDownloadResponse) in
let imageURL = fetchPathinDirectory(filepath:audioUrl!.lastPathComponent)
MusicPlayer.shared.startBackgroundMusic(backgroundMusicFileName: imageURL.path)
})
}
As explain in comment ;
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
That means the file is downloaded in documents directory of your app. But when you read the file :
if let bundle = Bundle.main.path(forResource: backgroundMusicFileName, ofType: "mp3") {
let backgroundMusic = NSURL(fileURLWithPath: bundle)
You read for file in application bundle which is where your application and its ressources (storyboard, xib, …) are installed.
You must read the file from documents directory. Something like :
var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let downloadedFileUrl = documentsURL.appendingPathComponent(backgroundMusicFileName)
I try to save given video locally after then I need those saved videos for playing video in my app. I can't handle the saving video. Here is my saving try :
func saveVideoDocumentDirectory(url : URL){
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(".MOV")
do{
let videoData = try Data(contentsOf: url)
fileManager.createFile(atPath: paths as String, contents: videoData, attributes: nil)
}catch{
//
}
}
here is the get file try
func getVideo(){
let fileManager = FileManager.default
let videoPAth = (self.getDirectoryPath() as NSString).appendingPathComponent(".MOV")
if fileManager.fileExists(atPath: videoPAth){
print(videoPAth)
play(url: URL(string: videoPAth)!)
}else{
print("No Video")
}
}
here is my play video func :
func play(url : URL)
{
let player = AVPlayer(url: url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true)
{
playerViewController.player!.play()
}
}
Instead of Filemanager.createFile(), try using write instead.
let videoData = try Data(contentsOf: url)
try videoData.write(to: paths, options: .atomic)
Also, I recommend creating a folder first (from this answer).
extension URL {
static func createFolder(folderName: String) -> URL? {
let fileManager = FileManager.default
// Get document directory for device, this should succeed
if let documentDirectory = fileManager.urls(for: .documentDirectory,
in: .userDomainMask).first {
// Construct a URL with desired folder name
let folderURL = documentDirectory.appendingPathComponent(folderName)
// If folder URL does not exist, create it
if !fileManager.fileExists(atPath: folderURL.path) {
do {
// Attempt to create folder
try fileManager.createDirectory(atPath: folderURL.path,
withIntermediateDirectories: true,
attributes: nil)
} catch {
// Creation failed. Print error & return nil
print(error.localizedDescription)
return nil
}
}
// Folder either exists, or was created. Return URL
return folderURL
}
// Will only be called if document directory not found
return nil
}
}
Then, you can save like this:
guard let folderURL = URL.createFolder(folderName: "StoredVideos") else {
print("Can't create url")
return
}
let permanentFileURL = folderURL.appendingPathComponent(nameOfYourFile).appendingPathExtension("MOV")
let videoData = try Data(contentsOf: url)
try videoData.write(to: permanentFileURL, options: .atomic)
This will save you the hassle of NSSearchPathForDirectoriesInDomains.
I am generating a PDF of a UIView and storing with a name in myforms the PFD is being generated and console prints PDF is Available but it shows nothing but a white screen in VC
here is what I am doing :
I have this code to generate a PDF
#IBAction func createAct(_ sender: Any) {
print("Creat PDF")
self.createPdfFromView(mainView: mainView, saveToDocumentsWithFileName: "myforms")
}
func createPdfFromView(mainView: UIView, saveToDocumentsWithFileName fileName: String)
{
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, mainView.bounds, nil)
UIGraphicsBeginPDFPage()
guard let pdfContext = UIGraphicsGetCurrentContext() else { return }
mainView.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
if let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
let documentsFileName = documentDirectories + "/" + fileName
debugPrint(documentsFileName)
pdfData.write(toFile: documentsFileName, atomically: true)
}
}
then I have this in console :
Creat PDF
"/Users/jawaidahmed/Library/Developer/CoreSimulator/Devices/3F95BE09-0F25-427C-9ED9-4BDB16DC3600/data/Containers/Data/Application/1EC22FBC-79E7-4AC5-BB7D-13783CC34516/Documents/myforms"
and I am using this PDFViewController to retrieve the file in a webview
override func viewDidLoad() {
super.viewDidLoad()
let check = "myforms"
var pdfURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
print("check final = \(pdfURL)")
pdfURL = pdfURL.appendingPathComponent(check) as URL
if let pdfBundleURL = Bundle.main.url(forResource: "myforms", withExtension: nil, subdirectory: nil) {
do {
let data = try Data(contentsOf: pdfBundleURL)
//Lastly, write your file to the disk.
try data.write(to: pdfURL, options: .atomicWrite)
}
catch {
// catch errors here
}
}
do{
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = URL(fileURLWithPath: path)
var filePath = url.appendingPathComponent(check).path
let fileManager1 = FileManager.default
if fileManager1.fileExists(atPath: filePath) {
print("FILE AVAILABLE in VC")
filePath = "file://\(filePath)"
let fileUrlkk = Foundation.URL(string: filePath)
let data = try Data(contentsOf: fileUrlkk!)
self.webView.load(data, mimeType: filePath, textEncodingName:"utf-8", baseURL: pdfURL.deletingLastPathComponent())
} else {
print("FILE NOT AVAILABLE in VC")
}
}
catch let error as NSError {
print("An error took place: \(error)")
}
}
And I am receiving this in console :
FILE AVAILABLE in VC
It means file is generated and available but it shows only empty VC white background only
self.webView.load(data, mimeType: "application/pdf", textEncodingName:"utf-8", baseURL: pdfURL.deletingLastPathComponent())
replace textEncodingName:""
with
textEncodingName:"utf-8"
check it
Try this for loading in Webview.I tried with your sample..It works
let FileName = "myforms"
let Filemanager = NSFileManager.defaultManager()
let docURL = Filemanager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
print(docURL)
let pdfPATH = docURL.URLByAppendingPathComponent(FileName)
print(pdfPATH)
let data = NSData(contentsOfURL: pdfPATH)
WBview.loadData(data!, MIMEType: "application/pdf", textEncodingName: "utf-8", baseURL: pdfPATH.URLByDeletingLastPathComponent!)
I am downloading file from firebase. let say the request url is following
social-cam-storage/albm-72/owner-2/1484043313786.jpeg
i can download the file using the following code
func downloadFile(url : String) {
let storageR = FIRStorage.storage().reference(withPath: url)
let maxSize : Int64 = 3 * 1024 * 1024 // 3MB
storageR.data(withMaxSize: maxSize) { (data, error) in
if error != nil {
print(error.debugDescription)
return
}
print(data!)
}
}
Now i need to store this data maintaining the directory structure of the url
I have tried
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
print(FileManager.default.createFile(atPath: "\(documentsURL.absoluteString)/\(url)", contents: data!, attributes: nil))
but i am getting false
so how to fix this or is there any other way to save??
Have you tried something like this? :
If you have the exact path already as a string:
try? data.write(to: URL(fileURLWithPath: path), options: [.atomic])
If you need the path there are a few methods:
func saveFile() {
let filePath = getDocumentsURL().absoluteString.appending(path)
try? data.write(to: URL(fileURLWithPath: filePath), options: [.atomic])
}
func getDocumentsURL() -> URL {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsURL
}
You could also just try saving the filename, and then loading later when you need it:
func fileInDocumentsDirectory(_ filename: String) -> String {
let fileURL = getDocumentsURL().appendingPathComponent(filename)
return fileURL.path
}
// To save file
func saveFile(data: Data) {
let fileName:String = "createUniqueFileName"
let filePath = fileInDocumentsDirectory(fileName)
saveData(data, filePath)
}
// To load file with saved file name
func loadFile(fileName: String) {
if let loadedData = loadData(fileName) {
// Handle data however you wish
}
}
func saveData(_ data: Data, path: String ) {
try? data.write(to: URL(fileURLWithPath: path), options: [.atomic])
}
func loadData(_ path: String) -> Data? {
let data:Data? = try? Data(contentsOf: URL(fileURLWithPath: path))
return data
}
Have you tried using the built in "download to file" API in Firebase Storage?
// Create a reference to the file you want to download
let fileURL = storage.reference(withPath: url)
// Create local filesystem URL
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = ...
// Download to the local filesystem
let downloadTask = islandRef.write(toFile: fileURL) { url, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Local file URL is returned
}
}
i am storing my data in file manager in my app. now i want to delete specific data by code so how can i do this?
here is my code which i used for store data
var localURL : String
init()
{
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
localURL = urls.first!.URLByAppendingPathComponent("podcasts").path!
createDirectory(localURL)
}
func downloadShow(slug: String, show: NSDictionary) {
SVProgressHUD.showWithStatus("Downloading...")
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
let url = NSURL(string: show["file"] as! String)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET"
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if (error == nil) {
let showFileName = url?.lastPathComponent
let programMP3Path = self.localURL + "/" + slug + "/" + showFileName!
let programDataPath = programMP3Path + ".dat"
data?.writeToFile(programMP3Path, atomically: true)
show.writeToFile(programDataPath, atomically: true)
print("Success")
print(showFileName)
SVProgressHUD.dismiss()
}
else {
// Failure
print("Faulure: \(error)");
}
})
task.resume()
}}
Not sure about session methods. Here's how to delete file in user temp directory, if that helps
let myFileName = "myFile.txt"
var fileManager = NSFileManager()
var tempDirectory = NSTemporaryDirectory()
let filePath = tempDirectory.stringByAppendingPathComponent(myFileName)
var error: NSError?
// also good idea to check before if the file is in the directory
let path = tmpDir.stringByAppendingPathComponent(isFileInDir)
fileManager.removeItemAtPath(path, error: &error)