I'm a web app developer trying to test my app, but Apple has changed the way they save web app data when you add it to the home screen.
How can I clear my web app's local storage so I can see updates to my code?
iOS Apps are stored in a sandbox. So every application has its own directory and working space.
In that working space all data of the application gets stored. This includes documents, library files, temporary files, the application bundle, as well as the preferences file.
When a user chooses to delete an app, the whole sandbox gets removed, including those preferences.
Here are some Solutions for Handling App sandbox data
Deleting all the files in the iPhone sandbox
NSFileManager *fileMgr = [[[NSFileManager alloc] init] autorelease];
NSError *error = nil;
NSArray *directoryContents = [fileMgr contentsOfDirectoryAtPath:documentsDirectory error:&error];
if (error == nil) {
for (NSString *path in directoryContents) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:path];
BOOL removeSuccess = [fileMgr removeItemAtPath:fullPath error:&error];
if (!removeSuccess) {
// Error handling
...
}
}
} else {
// Error handling
...
}
Clear Safari Cache
Clear UIWebView Cache
// Flush all cached data
[[NSURLCache sharedURLCache] removeAllCachedResponses];
Reference
Hope this helps!
Related
How to remote wipe out data/application from iDevice [iPod Touch, iPhone or iPad] ?
Possible solutions are as follow.
Configure "Find My iPod" on your iPod
Make server call and check is device was reported as stolen ? If yes then call exit(0) function and wipe out data and app.
I used second solution to wipe out data from app. I used following 2 methods for that.
-(NSString *)getDatabasePath {
NSArray *subDir = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self applicationAppSupportDirectory] error:nil];
NSString *path = [[[self applicationAppSupportDirectory] stringByAppendingPathComponent:[subDir lastObject]]
stringByAppendingPathComponent:#"xyz.sqlite"];
return path ;
}
-(void)deleteDatabase {
NSFileManager *manager = [NSFileManager defaultManager] ;
NSError *error = nil ;
NSString *databasePath = [self getDatabasePath];
if ([manager fileExistsAtPath:databasePath]) {
[manager removeItemAtPath:databasePath error:&error] ;
}
debug(#"%#",error);
if (error) {
[Utility showAlertViewWithTitle:#"Error" andMessage:error.localizedDescription];
}
}
-(void)deleteApplication {
exit(0);
NSString *appPath = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] ;
NSLog(#"%#",appPath);
}
I deleted application folder but still Application Logo is there on my iDevice.
Is this a right way to wipe out my app ?
Will apple reject my app for this ?
Why appLogo is still there as i entirely delete app folder ?
Apple won't allow you to use exit(0). You can probably wipe the user data though, but you will have make sure the application can still be used after that (I.e. bring the app back into the state of first launch).
For the reporting stolen part: you will have to create your own web UI or similar for this, as Apple currently doesn't allow you to access that kind of iCloud information from within a third party app.
My app is using the NSDocumentDirectory to save images in it, I just wanna ask if its the safe way to save images(100 maximum). I have read several thread & questions with answers about it, though I dont know which to follow.Some say that its okay to save there. Some say I shouldnt use NSDocumentDirectory for saving, because it will be back-up by the iCloud. So where can I save it that when the user exit the app then run the app again, then images should still be there?. I dont know much about the tmp directory or cache directory. But if its either one of the 2 that I should use, How can I use them in my code here:
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask ,YES );
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"Images%d.png", i]];
ALAssetRepresentation *rep = [[info objectAtIndex: i] defaultRepresentation];
UIImage *image = [UIImage imageWithCGImage:[rep fullResolutionImage]];
//----resize the images
image = [self imageByScalingAndCroppingForSize:image toSize:CGSizeMake(256,256*image.size.height/image.size.width)];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:YES];
Thank you so much for the help.
The tmp and cache directories are periodically cleaned up by iOS. If the images are for general use, use the camera roll as the other two answers suggest. However if these images are intended just for the scope of your app, you can still safely store them in the Documents directory, you just have to include an "exclude from iCloud backup" function call to each file after saving, in order to prevent Apple rejecting your app for using too much iCloud space. Of course there's a trade-off, disabling this means the user will lose their photos anyway should they delete the app or get another device(etc), but this caveat is preferable to not getting the App on the store at all.
To disable iCloud backup on a file, there's two methods for iOS versions > 5.0:
UPDATE! MERGED BOTH METHODS INTO A SINGLE FUNCTION THAT AUTOMATICALLY HANDLES iOS VERSION:
#include <sys/xattr.h> // Needed import for setting file attributes
+(BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)fileURL {
// First ensure the file actually exists
if (![[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
NSLog(#"File %# doesn't exist!",[fileURL path]);
return NO;
}
// Determine the iOS version to choose correct skipBackup method
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer isEqualToString:#"5.0.1"]) {
const char* filePath = [[fileURL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
NSLog(#"Excluded '%#' from backup",fileURL);
return result == 0;
}
else if (&NSURLIsExcludedFromBackupKey) {
NSError *error = nil;
BOOL result = [fileURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
if (result == NO) {
NSLog(#"Error excluding '%#' from backup. Error: %#",fileURL, error);
return NO;
}
else { // Succeeded
NSLog(#"Excluded '%#' from backup",fileURL);
return YES;
}
} else {
// iOS version is below 5.0, no need to do anything
return YES;
}
}
If your app must support 5.0, then unfortunately your only option is to save those photos in the Caches directory, which means they won't be backed up (this not causing an App Store rejection for that reason), but whenever the storage watchdog decides it's time to clean the Caches folder, you'll lose those photos. Not an ideal implementation at all, but such is the nature of the beast in 5.0, where Apple added in Backup exclusion as an afterthought.
EDIT: Forgot to answer the 'how to save to the tmp/cache directory' part of the question. If you do decide to go down that path:
Saving to tmp:
NSString *tempDir = NSTemporaryDirectory();
NSString *savedImagePath = [tempDir stringByAppendingPathComponent:[NSString stringWithFormat:#"Images%d.png", i]];
(note that this won't appear to have any effect in the simulator, but it works as expected on device)
Saving to Cache:
NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];
NSString *savedImagePath = [cacheDir stringByAppendingPathComponent:[NSString stringWithFormat:#"Images%d.png", i]];
If you want the user to be able to use the images in other apps or view them along with their photos, use the photo album as Mike D suggest. If the files are something you generate locally for use with your app only, then you should probably use the documents directory. You can expose the documents directory to iTunes with the info.plist option "Application supports iTunes file sharing" which will allow the user to add or delete files through iTunes, but the files will not be exposed to other apps
You are saving scaled images so they are really only useful for your game. They are not going to be very large and will not take up much space. You could save them in the Library directory for the app and avoid the whole iCloud thing, as it doesn't sound like there is any reason to back them up. Also, saving the the Library avoid the possibility of the user deleting them, if for some other reason you have iTunes sharing turned on.
Update: code for saving to the app Library directory
- (void)saveSequences:(NSMutableDictionary*)sequences
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libDirectory = [path objectAtIndex:0];
NSString *settingsPath = [libDirectory stringByAppendingPathComponent:#"userSequences.plist"];
NSLog(#"settingsPath %#", settingsPath);
[sequences writeToFile:settingsPath atomically:YES];
}
// The code below gets the path to a named directory in the 'Documents' folder - and if it doesn't exist, creates it. Adjust it to use the Library path, if you decide to go that route.
- (NSString *)getDirectoryBySequenceName:(NSString *)sequenceName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDirectory = [paths objectAtIndex:0];
NSString * sequenceDirectory = [documentDirectory stringByAppendingPathComponent:sequenceName];
NSError *error;
BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:sequenceDirectory
withIntermediateDirectories:YES
attributes:nil error:&error];
if (!success) {
NSLog(#"Error creating data path: %#", [error localizedDescription]);
}
return sequenceDirectory;
}
Depending on the purpose of your app, you could save it to the photos app (UIImageWriteToSavedPhotosAlbum(image, self, nil, nil) I think, Apple reference). Saving here, or in the documents directory (or any sub folder), will allow the user backup those images to iCloud or iTunes, if the user chooses too and/or if they have set up iCloud.
Since you state the images need to persist between launches, the temp or cache directory get emptied when the application is removed from memory, maybe sooner (the O/S decides).
More about the iOS file system.
I want to load a webpage when user connected to network and store it offline(including with images/resources). If the user not connected to any network then i should load the previously stored webpage. I have tried NSData dataWithContentsOfURL:(NSURL *)url and NSString stringWithContentsOfURL but these stores only html content not the resources.
Thanks in advance.
You can do that with ASIHttpRequest. If you do not want to to use that project (it is no longer active) you can look into the code and what it does. Look at "how to cache a whole web page with images in iOS" for more info as well.
I think the simple solution is this - "Safari Client-Side Storage and Offline Applications Programming Guide", https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Introduction/Introduction.html
Only if you are making an app with HTML5 and webview, didn't test this method yet so far, so it might work.
Write this data into file using:
-(void)writeDataToFile:(NSString*)filename
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if(filename==nil)
{
DLog(#"FILE NAME IS NIL");
return;
}
// the path to write file
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat: #"%#",filename]];
/*NSData *writeData;
writeData=[NSKeyedArchiver archivedDataWithRootObject:pArray]; */
NSFileManager *fm=[NSFileManager defaultManager];
if(!filePath)
{
//DLog(#"File %# doesn't exist, so we create it", filePath);
[fm createFileAtPath:filePath contents:self.mRespData attributes:nil];
}
else
{
//DLog(#"file exists");
[self.mRespData writeToFile:filePath atomically:YES];
}
NSMutableData *resData = [[NSMutableData alloc] init];
self.mRespData=resData;
[resData release];
}
and load it next time.
I don't know if there is one-line-solution like myWebView.cache4Offline = YES; , but I fear as long as you don't have access to the website's code (i.e. if you want to make any website available offline inside your app), you have to program this on your own. Thinking about it, it doesn't seem so difficult:
Scan the html string for image urls (and everything else you need)
Download those resources from the internet using NSData dataWithContentsOfURL (maybe a little annoying, because of relative/absolute URLs)
Save data to file with NSData writeToFile:options:error:
Replace URL in HTML with filePath from 3. (OR, better use a convention for converting their URLs in your file-URLs)
Hope it helps
I am saving Images in NSCachesDirectory in a App. At the end of app execution i would like to clear all temporary cache. Is there a way to force clear all cache on application exit. I do realise the local folder keeps cache for 3 days..but my requirement is to force clear the Cache. Thx
This code should do the trick, just substitute the name of your cache directory...
NSString *cacheDirectoryName = [self getCacheDirectoryName];
NSArray *items = [fileManager directoryContentsAtPath:cacheDirectoryName];
for (NSString *item in items)
{
NSString *path = [cacheDirectoryName stringByAppendingPathComponent:item];
NSError *error = nil;
[fileManager removeItemAtPath:path error:&error];
[error release];
}
Then call the code in your AppDelegate applicationWillTerminate method.
Whenever I build & run my program I notice that a new directory gets created in:
/Users/Username/Library/Application Support/iPhone Simulator/User/Applications
Therefore, there's no way for me to persist core data between application builds. The way I thought to get around this issue (from a testing point of view) was to just use the iphone simulator to exit the application by pressing the circular menu button and re-run my app. I.e., not build it but just rerun it via the simulator to see if the data is persisted in core data.
Now I wanted to check if the data is persisting each time the application is run. The event that I'm using is:
(void)applicationDidFinishLaunching:(UIApplication *)application
But it only fires after I build & run the application but doesn't get fired each time i restart the application - via iphone simulator (i.e., pressing menu button then rerunning my program).
Is there another event I should be using?? If I had an event that gets fired every time the application loaded I think I could just check to see if core data has data in it, if it doesn't i just populate it with an xml file to initialize it, if it does have data I don't do anything. Sound right? If so, what is that event called?
-applicationDidFinishLaunching: will be called EVERY time your app launches, whether from the debugger, hitting the icon in the Springboard (launcher), or either of these on the device.
On the sim, a folder in the .../Applications directory is created for your app, and any data stored in there will be persisted. The actual name of the folder will change each time you build-and-run your app, but the contents will remain the same, so you can store data there.
Ben's right. The reason you aren't seeing -applicationDidFinishLaunching is because the debugger doesn't run when you launch from the simulator, the method is still firing.
It sounds like you're still early in the Core Data development process. You'd probably benefit from turning on Lightweight Migration.
NSError *error;
NSURL *storeURL = <#The URL of a persistent store#>;
NSPersistentStoreCoordinator *psc = <#The coordinator#>;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![psc addPersistentStoreWithType:<#Store type#>
configuration:<#Configuration or nil#> URL:storeURL
options:options error:&error]) {
// Handle the error.
}
Instead of having to destroy your data store each time you make changes to the data model, this should allow Core Data to intelligently update the model for you.
Sorry this is a little off-topic, but I've spent a lot of time erasing and re-loading my data store because I didn't realize there was such a thing as this lightweight migration.
As vfn writes, you either need to attach the debugger or persist the log values to the disk.
I was doing OAuth and that requires the simulator to leave the app and do some authentication is Safari and then Safari will reopen the app using an URL Scheme. This meant I could not get a log of the different authentication steps logged after the app had quit.
Anyways, I wrote this class that will log messages to "log.txt" situated in ~/user*/library/application support/iPhone Simulator/user/yourapp*/documents
*user and yourapp is of course variable names.
//
// LogFile.m
//
//
// Created by RickiG on 11/30/09.
// Copyright 2009 www.rickigregersen.com.. All rights reserved.
//
#import "LogFile.h"
#implementation LogFile
+ (void) stringToLog:(NSString *) str {
NSDate *now = [NSDate date];
NSDateFormatter *logTimeFormatter = [[[NSDateFormatter alloc] init] autorelease];
[logTimeFormatter setDateFormat:#"HH:mm:ss"];
NSString *timeStr = [NSString stringWithFormat:#"%#", [logTimeFormatter stringFromDate:now]];
NSString *logMsg = [NSString stringWithFormat:#"%#\n%#\n\n", timeStr, str];
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"log.txt"];
NSData *dataToWrite = [[NSString stringWithString:logMsg] dataUsingEncoding:NSUTF8StringEncoding];
// Check if file exists
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:path]) { // Returns a BOOL
NSData *dataFromFile = [[NSData alloc] initWithContentsOfFile:path];
NSMutableData *combinedDataToWrite = [NSMutableData dataWithData:dataFromFile];
[combinedDataToWrite appendData:dataToWrite];
[combinedDataToWrite writeToFile:path atomically:YES];
[dataFromFile release];
} else {
[fileManager createFileAtPath:path contents:dataToWrite attributes:nil];
}
}
#end
Have you tried working with
-(void)applicationDidBecomeActive {
}