I'm saving a video on my iPad with this code on swift:
let paths = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0] as String
var filePath:String? = nil
var fileNamePostfix = 0
do {
filePath =
"\(documentsDirectory)/\(dateTimePrefix)-\(fileNamePostfix++).mp4"
} while (NSFileManager.defaultManager().fileExistsAtPath(filePath))
let fileUrl = NSURL(fileURLWithPath: filePath)
self.fileOutput.startRecordingToOutputFileURL( fileUrl , recordingDelegate: delegate)
But I can't see if my video is saving because I can't open path var/mobile/media...
There are any form to save pictures on photos folder?
Thanks!!
You can't save assets to the Media Library — the stuff that appears in the Music, Videos, and Podcasts apps. The only way to get things into there is by syncing from iTunes on the desktop or downloading from the iTunes Store.
If you want to save a video so that it appears in the Photos app, use the Photos framework in iOS 8:
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
let request = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(url)
}, completionHandler: { success, error in
if !success { NSLog("Failed to create video: %#", error) }
})
(In iOS 7 and earlier, use the AssetsLibrary framework instead.)
If you just want to see if the files are getting into the documents folder on your device then you can see the container in the Devices window of Xcode 6.
Just Window > Devices then select your device. Then select your app, click the gear button and tell it if you want to view, download, or replace the container for the app.
Note that you can also save the videos into the Saved Photos album, assuming they are in the right format. Check out this method in the ALAssetsLibrary Class:
writeVideoAtPathToSavedPhotosAlbum:completionBlock:
You can't access the photo system folder directly. However if you just want to see the files you've saved, you don't have to. Just enable document sharing by adding UIFileSharingEnabled to your Info.plist.
When you plug your device in and open iTunes, it will show your documents folder like so:
More info on filesharing here.
Related
My app uses remote notifications with a NotificationService Extension in which I edit the notification before displaying it.
I would like to let the user upload a custom sound file which should be played instead of the default sound. For this I use an shared AppGroup, which the app and the extension have access to.
The uploaded sound files are stored in the "Library/Sounds" directory as follows (my code for testing, without much error handling):
.....
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.xxx.xxx")
let soundsURL = containerURL!.appendingPathComponent("Library/Sounds/", isDirectory: true)
if !FileManager.default.fileExists(atPath: soundsURL.path) {
try! FileManager.default.createDirectory(atPath: soundsURL.path, withIntermediateDirectories: true)
}
if FileManager.default.fileExists(atPath: soundsURL.path) {
do {
try FileManager.default.copyItem(at: sourceURL, to: soundsURL.appendingPathComponent(sourceURL.lastPathComponent))
} catch {
// Exception
}
}
In the Notification Extension I change the sound of the notification to the name of the uploaded file:
bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "test.wav"))
This is working fine as long as the iPhone is not locked. But if the iPhone is locked, there is no vibration and no sound is played (also no default sound). But I don't know why - according to apples documentation UNNotificationSound looks in "Library/Sounds" of the app shared group container directories. If I store the file directly in the main bundle, it works.
Does anyone have any idea what could be causing this?
Ok, now i figured out what the problem is.
My files were created with "NSFileProtectionComplete" data protection by default.
"NSFileProtectionComplete — The file is only accessible while the device is unlocked."
After changing the data protection of my sound files to "NSFileProtectionNone", it finally works!
My app has just been rejected by Apple because it was storing temporary or cache files in the documents directory. Right. Their rejection message states:
Temporary files used by your app should only be stored in the /tmp directory
I suppose it is that besides the Documents and Library in the Application's folder.
I am now trying to debug this issue in the iPhone Simulator, and when I use NSTemporaryDirectory(), the value I get in the Xcode debugger is /var/folders/yj/gnz1c7156c7d6d4fj429yms40000gn/T/tempzip.zip, and not /Users/me/Library/Application Support/iPhone Simulator/5.1/Applications/8F71AB72-598C-427A-A116-36833D3209F7/tmp/tempzip.zip.
So: is NSTemporaryDirectory() having a different behaviour using the iPhone Simulator, and, is it possible to track the application's temporary directory at debug time ?
iOS 9 or later • Swift 3 or later
let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory())
iOS 10.0+Beta, macOS 10.12+, tvOS 10.0+Beta & watchOS 3.0+ • Xcode 8 • Swift 3 or later
let tmpDirURL = FileManager.default.temporaryDirectory
UPDATED 2016 ANSWER :
Data which is explicitly accepted by the user as personal, and potentially backuped in his/her iCloud space, should be written in user's "Documents" directory
Data that belongs and extends your application (an extension user can download for instance,...), but which is NOT in the bundle, should be written in a subfolder of "Application Support/" directory, having the title of your appID. It can also be the "Cache" directory.
Data with short-life time can be stored in the tmp directory of your application. In this case, use of NSTemporaryDirectory() is possible to get the "tmp" directory. Check this link for additional help.
Check this official iOS developement Apple page in section "Determining Where to Store Your App-Specific Files" for explanations.
Below are 3 functions in Swift designed to return NSURLs to these directories and make your like simpler.
Swift:
func GetDocumentsDirectory()->NSURL{
//returns User's "Documents" directory
//something like this on a real device : file:///private/var/mobile/Containers/Data/Application/APPID/Documents/
//something like this on the simulator : file:///Users/MACUSERID/Library/Developer/CoreSimulator/Devices/SIMDEVICEID/data/Containers/Data/Application/APPUUID/Documents/
let filemgr = NSFileManager.defaultManager()
let docsDirURL = try! filemgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
return docsDirURL
}
func GetApplicationSupportDirectory()->NSURL{
//returns Application's support directory
//something like this on a real device : file:///private/var/mobile/Containers/Data/Application/APPID/Library/Application%20Support/YOURAPPBUNDLEID/
//something like this on the simulator : file:///Users/MACUSERID/Library/Developer/CoreSimulator/Devices/SIMDEVICEID/data/Containers/Data/Application/APPUUID/Library/Application%20Support/YOURAPPBUNDLEID/
let AllDirectories : [NSURL]
var ApplicationSupportDirectory : NSURL=NSURL.init()
var ApplicationDirectory : NSURL=NSURL.init()
AllDirectories=NSFileManager.defaultManager().URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask)
if AllDirectories.count>=1{
ApplicationSupportDirectory=AllDirectories[0]
}
if !ApplicationSupportDirectory.isEqual(nil) {
ApplicationDirectory=ApplicationSupportDirectory.URLByAppendingPathComponent(NSBundle.mainBundle().bundleIdentifier!)
}
return ApplicationDirectory
}
func GetTemporaryDirectory()->NSURL{
//returns Application's temporary directory
//something like this on a real device : file:///private/var/mobile/Containers/Data/Application/APPID/tmp/
//something like this on the simulator : file:///Users/MACUSERID/Library/Developer/CoreSimulator/Devices/SIMDEVICEID/data/Containers/Data/Application/APPUUID/tmp/
return NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
}
I have tested this on a real device, and it returned : "/private/var/mobile/Applications/C82383-EBD6-4F72-BC16-A865478D27/tmp/tempzip.zip"
So overall, using NSTemporaryDirectory() is the correct way of finding the path to the temporary directory, and that if you want to debug and view what is done within, you need to find it manually in the Finder if you are using the iPhone Simulator.
Check newer answer below (this one is deprecated)
According to the docs, you should avoid NSTemporaryDirectory() in favour of this approach
- (NSURL)URLForTemporaryFolder
{
// Get a parent folder, trying user folder (fails iOS) and falling back to AppSupport and Docs
NSURL *parentFolderURL = [NSURL URLForDirectory:NSUserDirectory domainMask:NSUserDomainMask];
if (!parentFolderURL) parentFolderURL = [NSURL URLForDirectory:NSApplicationSupportDirectory domainMask:NSUserDomainMask];
if (!parentFolderURL) parentFolderURL = [NSURL URLForDirectory:NSDocumentDirectory domainMask:NSUserDomainMask];
// Get the temp folder URL using approach outlined in the docs
NSURL *tmpURL = [[NSFileManager defaultManager]
URLForDirectory:NSItemReplacementDirectory
inDomain:NSUserDomainMask
appropriateForURL:parentFolderURL
create:YES
error:NULL];
return tmpURL;
}
Be aware that this creates a new unique temp folder each time you call it and it's up to you to clean it up.
I'm an undergraduate student and I'm witring an iPhone HumanSeg app. But now I have a problem, that I have a native video in album, and I need to load that video into my code and do some processing. My codes are below:
let filePath = Bundle.main.path(forResource: "1", ofType: "mp4")
let videoURL = NSURL(fileURLWithPath: filePath!)
let avAsset = AVAsset(url: videoURL as URL)
But when I run this code, Xcode just tells me that filePath is nil. I assert that 1.mp4 is in both Assets.xcaassets and iPhone album. Is there anyone who'd like to offer some help?
By the way, How can I get the images(in UIImage format) in the video at the fastest speed? For each image at given time, I really have to read it in no more than 5ms so I may output the preserved video at a good fps.
Check target's build phases, whether the file is being copied to the bundle.Also the check the box to include the file. This code is correct for fetching that file.
Is it possible to share a video on Instagram without saving it to the user's Camera Roll?
this is what i tried so far:
let instagramURL = URL(string: "instagram://app")!
if (UIApplication.shared.canOpenURL(instagramURL)) {
self.documentController = UIDocumentInteractionController(url: videoURL)
self.documentController.delegate = self
self.documentController.uti = "com.instagram.exlusivegram"
self.documentController.presentOpenInMenu(from: self.view.frame, in: self.view, animated: true)
} else {
print(" Instagram isn't installed ")
}
videoURL is the URL of the video i saves in the Documents folder.
if I save the URL with Instagram.igo at the end, then when i choose Instagram to share it opens like this:
if I save the video with .mov at the end, it seems that Instagram share opens with a photo (like video thumbnail) and not a video.
What exactly you did wrong is difficult to determine, but I'll try to address where you might have been wrong.
First of all make sure that the videoURL is defined locally. When I wrote an app posting to Instagram, I first defined the path with file manager, like:
let tempDirectory = FileManager().temporaryDirectory
var postingPath = tempDirectory.appendingPathComponent("postingVideo")
postingPath = postingPath.appendingPathExtension("igo")
I then wrote the movie into this directory and almost have the same code as you.
Do take into consideration that you need to create the igo folder and then save the movie into this folder. If you try to refer to the folder you have the movie in, your app will not read the movie file and nothing will be posted. When it is a movie file from the photo library, use an AVExportSession and export it to the postingPath.
self.instagramController = UIDocumentInteractionController.init(url: postingPath)
self.instagramController.uti = "com.instagram.exclusivegram"
self.instagramController.delegate = self
self.instagramController.presentOpenInMenu(from:
self.navigationItem.rightBarButtonItem!, animated: true)
However, you do need to make your class posting to instagram adhere to the UIDocumentInteractionControllerDelegate, otherwise you need cast self. You also need to include Social. I don't think you have done anything wrong in the second part of this post, because you would have gotten xcode errors and warnings.
I hope the first part can help you further, since I don't think the second part has given you problems.
We are currently developing an iOS10 app, including "Messages Extension".
To share CoreDatas persistant store.sqlite inbetween App and Extension, we are using a shared "Apple App Group" directory, which is working fine.
Now we have to get our hands on the store for debug reasons and are unable to find the directory. The Apps container directories are completely empty, which makes sense. But how to download our database? Do we have to somehow copy it programmatically to a reachable place?
To sum it up:
We already use CoreData which stores model.sqlite in our shared directory.
Everything is up and running.
What we want to archive is to download the database to our computer.
Without a shared directory we can simply download the App container from the device, using Xcode->Devices. But as we do use a shared directory, the .sqlite database is not within the container.
Question:
How can we download the .sqlite database from the device to our computer?
EDIT on 2018-10-12: Updated code for Swift 4.x (Xcode 10). (Older version retained for reference.)
In Swift 4.x:
let sharedContainerURL :URL? = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.etc.etc")
// replace "group.etc.etc" above with your App Group's identifier
NSLog("sharedContainerURL = \(String(describing: sharedContainerURL))")
if let sourceURL :URL = sharedContainerURL?.appendingPathComponent("store.sqlite") {
if let destinationURL :URL = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("copyOfStore.sqlite") {
try! FileManager().copyItem(at: sourceURL, to: destinationURL)
}
}
In older version of Swift (probably Swift 2.x):
let sharedContainerURL :NSURL? = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.etc.etc") // replace "group.etc.etc" with your App Group's identifier
NSLog("sharedContainerURL = \(sharedContainerURL)")
if let sourceURL :NSURL = sharedContainerURL?.URLByAppendingPathComponent("store.sqlite")
{
if let destinationURL :NSURL = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0].URLByAppendingPathComponent("copyOfStore.sqlite")
{
try! NSFileManager().copyItemAtURL(sourceURL, toURL: destinationURL)
}
}
Something like the above will get a file from the app group's shared container to the app's Documents directory. From there, you could use Xcode > Window > Devices to get it to your computer.
You could also use iTunes file sharing to retrieve the file from the app's Documents directory after setting UIFileSharingEnabled to YES in the Info.plist file, but bear in mind that this will expose the directory's contents to the user as well. Should be okay for development/debugging purposes, though.