iOS Application Library directory <uid> always gets changed - ios

After reading Apple documentation, I used URLsForDirectory to obtain the Library destination within my app, and my objective is to download content from a hosted service & cache it in the Library folder, so that User cannot interact with the contents through iTunes.
NSArray *docPaths= [[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask];
NSLog(#"%#",[docPaths description]);
NSString *docPath=[(NSURL *)[docPaths objectAtIndex:0] path];
docPath = [docPath stringByAppendingPathComponent:#"audios"];
Running & executing the code several times(various simulators, and iOS 8.0 device) I realized that somehow the content being fetched seems to be no longer accessible, so I logged the library destination path, and after running app every time the destination path seems to have changed:
/var/mobile/Containers/Data/Application/83725F33-C7EA-4F89-B69F-0AECF26FA77A/Library/"
/var/mobile/Containers/Data/Application/4627FC86-C3A4-4A1A-9721-AF73D808433E/Library/"
/var/mobile/Containers/Data/Application/709CCA84-936A-4596-933A-D6779758FF85/Library/
Has anybody faced a similar issue? If so how did it got corrected? And is there anything I've missed out here?

I had the same issue. I think the variable part changes only when the code is recompiled (ie not if you just rerun without making changes), so should not affect a live app. But I decided in the end not to save the path - just to use the same code (as you use above) both when saving and retrieving the data. It seems to work, in spite of the fact that the path actually changes between runs (so the simulator must copy the files across, or rename the folder).

Related

download file to update-independent directory in objective c

I'm developing an IOS app which download some video and save it, but after update app or reinstall it the directory of app change, and app can not access to previous downloaded files.
Is there any way to save downloaded file to location out of application domain directory?
the code for generating path to save file is.
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
I cannot verify the update part of your question.
I use the application's Documents all the time and after an update that is untouched, so I can still use any files added to it in a previous version.
For the reinstalling (i.e. first delete the app, then re-download it from the AppStore and run it) there is obviously no such way, unless you consider what ravi.p suggested in his comment (adding it to PhotosAlbum). That would beat the entire purpose of a reinstall. If a user deletes the app they want to delete all its data. That's why the warning dialog specifically makes that clear. If you could circumvent this would beat the intention, wouldn't it?
The previous Documents directory isn't changed in this case, it is deleted and on the reinstall a new one is created.
I didn't check it recently, but I believe even the full path of the Documents directory doesn't change after an update, including the hashed part that is created by the sandboxing mechanism. My guess is that you're either confusing something with the update process or simply get a different file name in the newer app version.
Edit:
Okay, so apparently the application's folders can change on an update, at least according to what you further explained in your comment. :)
Then I am wondering how you can find your sqlite file again, but in ay way there is an easy solution to your problem:
Do not save the full path in your database. That is bad practice anyways, since the method you already used to get it in the first place (after downloading the file) is meant to be used for accessing the folder. So you only save
[response suggestedFilename]
in your database (going from your posted code).
In places where you need to access the file you then simply rebuild your path in just the same way you do in the first line of code you posted.
You can even write a convenience method for this in some place (a model class or the class taking care about DB access).
And by the way: Again, updating and reinstalling are two different things, especially the process in which Xcode copies your development build onto your development device is a different one from how users ultimately update your app from the store.

iCloud file versions and mystery files

I have been trying to retrofit a large app to have it store its files in iCloud. The app is not really "Document-based" but the files may be thought of as configuration or preference files.
To be honest I haven't followed all the Apple iCloud guidelines. Some really don't fit in with the flow of the app. When the app starts I read the files from the ubiquity directory (using normal file reads) and when I write them I use a normal file write to the ubiquity directory. When the app start, I also call:
[fileManager startDownloadingUbiquitousItemAtURL:url error:&error];
I do have an NSFilePresenter watching for changes in the ubiquity directory. It notifies me of file changes but there are never any conflict notifications.
My problem is that often when I upload a file to iCloud, it will create a separate file with a number appended. E.g.
MyFile.skyset
MyFile 2 .skyset
These seem to show up when more than one app has been writing MyFile.skyset to the ubiquity directory.
They don't seem to be conflicted file versions. If I use NSFileVersion to look for conflicts and other versions, I only see the one version of MyFile.skyset and it is not in conflict.
I can't find any documentation that explains what this "versioned" file is and what to do about it. Any thoughts as to what is going on here?
Well, I don't fully understand the "versions" but the problem was solved by changing how I updated the files in the ubiquity directory.
I changed from:
[fileMgr removeItemAtPath:dstPath error:nil];
[fileMgr copyItemAtPath:srcPath toPath:dstPath error:&error];
To:
NSData *data = [NSData dataWithContentsOfFile:srcPath];
[data writeToFile:dstPath atomically:NO];
I looks like the operation of deleting the file before copying the updated information to the ubiquity directory was confusing the system. After switching to the second form I'm no longer seeing this problem.
Hope this answer helps someone else.

xCode: Retrieving images from apps documents directory

I've come across a problem I can't find a solution to. I've searched the forums extensively but can't find anything. Hopefully someone might be able to shed some light.
I have an app that can save images. They are saved to the apps documents directory and the path to them is saved in a sqlite database. Every time I run/build the app, it can no longer retrieve the images that are already in the documents directory. During that same build phase I can re-save the images and then I can retrieve them just fine, but as soon as I run/build the app again it can't retrieve the images. The images are not being deleted and the path is still correct.
This is how I try retrieving them in my ViewDidLoad method
//database was opened. Getting path to image
NSString *logoPath = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 21)];
//use path to load image to a UIImage view
[self.logoView setImage:[UIImage imageWithContentsOfFile:logoPath]];
I have confirmed that the image is in the documents directory still and the path is correctly assigned in my first line of code above. This code only fails when I run/build the app. Once the app is running I can save images to the directory and retrieve them with this same code just fine, but once I run/build the app again, the images I saved on the previous build can't be pulled up even though I can see them in the directory still (I use iExplorer to view my iPhones directories).
Any ideas? Im thinking that maybe I have to initiate those images in the directory somehow in order to use them right after I build.
UPDATE - Some more info in case it will help. After the app is built on my iPhone, I can close the app and reopen it and the images work just fine. I can even completely close the app (double click home button and end app process) and when I relaunch the app the images are retrieved from the directory just fine. But as soon as I build the app again through xCode, I cannot access the images. Something is changing when a new build is done.
UPDATE 2 - I think I found the issue and it is in the path.
This is my path
/var/mobile/Containers/Data/Application/8A387845-7B1F-4228-9E7E-2498EC302C5A/Documents/RYal7UXrLvcompanyLogo.png
After I build the app again, this is now the new path when I save the image again
/var/mobile/Containers/Data/Application/C0C30E2F-05D8-48F4-A0FF-603359AF5130/Documents/RYal7UXrLvcompanyLogo.png
Looks like the part in between Applications and Documents changes after every build so the path I am saving in my sqlite db is no longer valid after a new build. So now I need to figure out what that middle part is that keeps changing and how to get it after each build so I can update my paths to my images.
The issue was the path. Every time a new build was created, part of the path to the documents directory changed. See UPDATE 2 in the original question above.

Resource File Not Found after App Upgrade?

My app is bundled with two preinstalled videos, and the user can purchase more through in-app-purchase.
Each video episode is an objective-C object with an ivar called _videoFilePath (property NSString* videoFilePath)
When a video finished downloading, the file path is appropriately set. For preinstalled episodes, it is set once at startup with code like this:
NSString* fileName = [NSString stringWithFormat:#"Chapter_%03d", _episodeNumber];
self.videoFilePath = [[NSBundle mainBundle] pathForResource:fileName ofType:#"m4v"];
(Episode metadata is initialized from a bundled .plist on the first run, and a copy of that .plist is saved in /Documents and used on subsequent runs. This is because the metadata is read/write, but bundled resources are read-only)
I've noticed that some users can play the preinstalled videos after upgrading my app. I am currently investigating this, so I deleted the app from the Device, installed version 1.0 (from Xcode->Run), Archived version 1.1 as AdHoc and installed that on top.
As expected, the preinstalled episodes won't play.
So this time I built/run version 1.1 from Xcode, on top of the AdHoc install, with some breakpoints enabled.
Purchased (downloaded) episodes are saved to the cache, so the presence of a valid file path is not enough to guarantee playback (might be deleted by the system). So I use NSFileMananger to check if the file exists before attempting playback, with code like this:
if (_videoFilePath) {
// Video File Path is Set...
if ([[NSFileManager defaultManager] fileExistsAtPath:_videoFilePath]) {
// ...and file exists in system;
// Can Play:
return YES;
}
else{
// ...but file has been deleted, possibly as a result of a
// restore from iTunes backup;
// Can Not Play:
return NO;
}
}
The breakpoints revealed that the fileExistsAtPath: test fails; However the console shows the value of _videoFilePath as:
/var/mobile/Applications/CEAA80EF-A85F-4C60-929D-9BA18E8D1702/[App Name]/Chapter_001.m4v
So, what gives?
Note: Deleting the app and reinstalling version 1.1 seems to fix the problem.
The bug only manifests itself when you upgrade to 1.1 on top of 1.0.
ADDENDUM
After a second of thought (writing things down does help), I think I've figured it out. The file path for the resource is obtained on the first run of version 1.0, and saved in the /Documents folder with the rest of the metadata. On upgrade, I assume the 'Random numbers, letters and hyphens' part of the app's path changes to something else, and thus the 'hard-coded' path from version 1.0 becomes a broken URL. Must NSLog the full path on both v1.0 and v1.1 to confirm this, but I think I got it.
Answers and comments are still welcome.
So, as I realized after some thought, the full path for bundled resources seems to change slightly on each upgrade of the app; Specifically, the "Long, autogenerated random string of numbers and letter" intermediate directory. My mistake was in saving (i.e., hard-coding) the path on the first install, and using that value even after app upgrades.
I solved it by not caching the path and instead using
-pathForResource:ofType:
each time.

Does updating iOS apps delete library directory files?

I keep save files in a private directory in my iPad app, namely the one returned when I use:
paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
documentsDirectory = [documentsDirectory stringByAppendingPathComponent:#"Private Documents"];
Notice that I also append a subdirectory to it. When I update the app, users are telling me that their progress in the app is getting destroyed. Are files in this NSLibraryDirectory destroyed every time I update the app? If so, should I be using NSDocumentDirectory instead?
Additionally, is there no way to make a further update to my app to remedy this without destroying all my my current users' save files? It doesn't seem like there is.
When a user downloads an app update, iTunes installs the update in a new app directory. It then moves the user’s data files from the old installation over to the new app directory before deleting the old installation. Files in the following directories are guaranteed to be preserved during the update process:
Application_Home/Documents
Application_Home/Library
Although files in other user directories may also be moved over, you should not rely on them being present after an update.
This is provided by apple officially. See this link :
iOS Developer Library - File Saved During App Updates
I would also like to add this info as a personal experience with a big online game. You can't rely at 100% that your "Document" and "Library" folder will always be there. In fact, you can't rely that your app folder will still be at the same place on your device after an update.
Let me explain it a little bit more. When you install an app on your device, the real path will be /var/mobile/Applications/[some class id]/[your app].app/...
We're not sure who defines the class id of your app (either the iOS or app store), but this Id can change when updating the game resulting in having your app in a totaly different folder so your old files aren't there anymore. Our QA experienced it and our users too.
I won't go through the details on how we found that out and how we managed to get around this (private company stuff, usual shit...), but you need to consider it if you're doing an app that affects tons of users and might be updated a couple of times. It might have been fixed since, but it's always good to have a backup plan.
You should save them in the Documents folder, it is persistent across updates.
Monotouch: documentsDirectory = environment.specialfolder.personal;
Objective-C: NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)

Resources