[ 
https://issues.apache.org/jira/browse/CB-330?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13237796#comment-13237796
 ] 

Davide Bertola edited comment on CB-330 at 3/25/12 8:08 AM:
------------------------------------------------------------

Hi, I solved this issue in my app before coming across the jira bug. My 
strategy is simple.
I move the default webkit databases (from both Caches/ for 5.0.1+ or 
Library/Webkit for older iOS)
from their location to a safe location inside Documents folder.
I do this only if the "source" database exists, and if "destination" in the 
safe location does not exists.
Then I update the app preferences to pick up the databases from my Documents 
folder.
This should be safe and simpler than backing up and restoring stuff around.

This is the code I call from my application:didFinishLaunchingWithOptions:

{code}
    /* Fix problem with ios 5.0.1+ and Webkit databases described at the 
following urls:
     *   https://issues.apache.org/jira/browse/CB-347
     *   https://issues.apache.org/jira/browse/CB-330
     * My strategy is to move any existing database from default paths
     * to Documents/ and then changing app preferences accordingly
     */
    
    NSString* library = 
[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, 
YES)objectAtIndex:0];
    NSString* documents = 
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, 
YES) objectAtIndex:0];
       
    NSString *localStorageSubdir = (IsAtLeastiOSVersion(@"5.1")) ? @"Caches" : 
@"WebKit/LocalStorage";
    NSString *localStoragePath = [library 
stringByAppendingPathComponent:localStorageSubdir];
    NSString *localStorageDb = [localStoragePath 
stringByAppendingPathComponent:@"file__0.localstorage"];
    
    NSString *WebSQLSubdir = (IsAtLeastiOSVersion(@"5.1")) ? @"Caches" : 
@"WebKit/Databases";
    NSString *WebSQLPath = [library 
stringByAppendingPathComponent:WebSQLSubdir];
    NSString *WebSQLIndex = [WebSQLPath 
stringByAppendingPathComponent:@"Databases.db"];
    NSString *WebSQLDb = [WebSQLPath stringByAppendingPathComponent:@"file__0"];
    
    NSString *ourLocalStoragePath = [documents 
stringByAppendingPathComponent:@"LocalStorage"];;
    NSString *ourLocalStorageDb = [documents 
stringByAppendingPathComponent:@"file__0.localstorage"];
    
    NSString *ourWebSQLPath = [documents 
stringByAppendingPathComponent:@"Databases"];
    NSString *ourWebSQLIndex = [ourWebSQLPath 
stringByAppendingPathComponent:@"Databases.db"];
    NSString *ourWebSQLDb = [ourWebSQLPath 
stringByAppendingPathComponent:@"file__0"];
    
    NSFileManager* fileManager = [NSFileManager defaultManager];
    
    BOOL copy;
    NSError *err = nil; 
    copy = [fileManager fileExistsAtPath:localStorageDb] && ![fileManager 
fileExistsAtPath:ourLocalStorageDb];
    if (copy) { // TODO: should check for errors
        [fileManager createDirectoryAtPath:ourLocalStoragePath 
withIntermediateDirectories:YES attributes:nil error:&err];
        [fileManager copyItemAtPath:localStorageDb toPath:ourLocalStorageDb 
error:&err];
        [fileManager removeItemAtPath:localStorageDb error:&err];
    }
    
    err = nil;
    copy = [fileManager fileExistsAtPath:WebSQLPath] && ![fileManager 
fileExistsAtPath:ourWebSQLPath];
    if (copy) { // TODO: should check for errors
        [fileManager createDirectoryAtPath:ourWebSQLPath 
withIntermediateDirectories:YES attributes:nil error:&err];
        [fileManager copyItemAtPath:WebSQLIndex toPath:ourWebSQLIndex 
error:&err];
        [fileManager copyItemAtPath:WebSQLDb toPath:ourWebSQLDb error:&err];
        [fileManager removeItemAtPath:WebSQLPath error:&err];
    }
    
    NSUserDefaults* appPreferences = [NSUserDefaults standardUserDefaults];
    NSBundle* mainBundle = [NSBundle mainBundle];
    
    NSString *bundlePath = [[mainBundle bundlePath] 
stringByDeletingLastPathComponent];
    NSString *bundleIdentifier = [[mainBundle infoDictionary] 
objectForKey:@"CFBundleIdentifier"];
    NSString* libraryPreferences = @"Library/Preferences";
    
    NSString* appPlistPath = [[bundlePath 
stringByAppendingPathComponent:libraryPreferences]    
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", 
bundleIdentifier]];
    NSMutableDictionary* appPlistDict = [NSMutableDictionary 
dictionaryWithContentsOfFile:appPlistPath];
    
    BOOL dirty = NO;
    
    NSString *value;
    NSString *key = @"WebKitLocalStorageDatabasePathPreferenceKey";
    value = [appPlistDict objectForKey: key];
    if (![value isEqual:ourLocalStoragePath]) {
        [appPlistDict setValue:ourLocalStoragePath forKey:key];
        dirty = YES;
    }
    
    key = @"WebDatabaseDirectory";
    value = [appPlistDict objectForKey: key];
    if (![value isEqual:ourWebSQLPath]) {
        [appPlistDict setValue:ourWebSQLPath forKey:key];
        dirty = YES;
    }
    
    if (dirty) 
    {
        BOOL ok = [appPlistDict writeToFile:appPlistPath atomically:YES];
        NSLog(@"Fix applied for database locations?: %@", ok? @"YES":@"NO");
        [appPreferences synchronize];
    }
{code}

What do you think ?

Also, I have a suggestion for this plugin.
It is possible to remove the data storage quota limit for WebkitSQL by running 
simple sqlite queries on the sql files. I am currently doing this with my 
plugin https://github.com/davibe/Phonegap-SQLitePlugin using it from javascript 
code to open Databases.db and run the following queries:

{code}
update origins set quota = '999999999999' where origin = 'file__0';
update databases set estimatedSize = '999999999999' where name = '" + dbName + 
"';
Where db name is the name of the db being patched.
{code}


About the mentioned Phonegap SQLitePlugin.
I tried to use my sqlite plugin instead of the database interface offered by 
webkit. I have read Edgar Canas suggesting this. I can tell from my experience 
that for some reason It's much slower. The bottleneck seems to be passing long 
queries (I store jsons that are over 1Mb) from the webview to native code. 
WebkitSQLite does not suffer from this.
By the way I have plans porting it to Cordova, any suggestion is welcome.



                
      was (Author: davibe):
    Hi, I solved this issue in my app before coming across the jira bug. My 
strategy is simple.
I move the default webkit databases (from both Caches/ for 5.0.1+ or 
Library/Webkit for older iOS)
from their location to a safe location inside Documents folder.
I do this only if the "source" database exists, and if "destination" in the 
safe location does not exists.
Then I update the app preferences to pick up the databases from my Documents 
folder.
This should be safe and simpler than backing up and restoring stuff around.

This is the code I call from my application:didFinishLaunchingWithOptions:

{code}
    /* Fix problem with ios 5.0.1+ and Webkit databases described at the 
following urls:
     *   https://issues.apache.org/jira/browse/CB-347
     *   https://issues.apache.org/jira/browse/CB-330
     * My strategy is to move any existing database from default paths
     * to Documents/ and then changing app preferences accordingly
     */
    
    NSString* library = 
[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, 
YES)objectAtIndex:0];
    NSString* documents = 
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, 
YES) objectAtIndex:0];
    
    //NSString* db = [appDocumentsFolder 
stringByAppendingPathComponent:@"Database"];
    
    //[[NSFileManager defaultManager] createDirectoryAtPath:dbFolder 
withIntermediateDirectories:YES attributes:nil error:nil];
    
    NSString *localStorageSubdir = (IsAtLeastiOSVersion(@"5.1")) ? @"Caches" : 
@"WebKit/LocalStorage";
    NSString *localStoragePath = [library 
stringByAppendingPathComponent:localStorageSubdir];
    NSString *localStorageDb = [localStoragePath 
stringByAppendingPathComponent:@"file__0.localstorage"];
    
    NSString *WebSQLSubdir = (IsAtLeastiOSVersion(@"5.1")) ? @"Caches" : 
@"WebKit/Databases";
    NSString *WebSQLPath = [library 
stringByAppendingPathComponent:WebSQLSubdir];
    NSString *WebSQLIndex = [WebSQLPath 
stringByAppendingPathComponent:@"Databases.db"];
    NSString *WebSQLDb = [WebSQLPath stringByAppendingPathComponent:@"file__0"];
    
    NSString *ourLocalStoragePath = [documents 
stringByAppendingPathComponent:@"LocalStorage"];;
    NSString *ourLocalStorageDb = [documents 
stringByAppendingPathComponent:@"file__0.localstorage"];
    
    NSString *ourWebSQLPath = [documents 
stringByAppendingPathComponent:@"Databases"];
    NSString *ourWebSQLIndex = [ourWebSQLPath 
stringByAppendingPathComponent:@"Databases.db"];
    NSString *ourWebSQLDb = [ourWebSQLPath 
stringByAppendingPathComponent:@"file__0"];
    
    NSFileManager* fileManager = [NSFileManager defaultManager];
    
    BOOL copy;
    NSError *err = nil; 
    copy = [fileManager fileExistsAtPath:localStorageDb] && ![fileManager 
fileExistsAtPath:ourLocalStorageDb];
    if (copy) { // TODO: should check for errors
        [fileManager createDirectoryAtPath:ourLocalStoragePath 
withIntermediateDirectories:YES attributes:nil error:&err];
        [fileManager copyItemAtPath:localStorageDb toPath:ourLocalStorageDb 
error:&err];
        [fileManager removeItemAtPath:localStorageDb error:&err];
    }
    
    err = nil;
    copy = [fileManager fileExistsAtPath:WebSQLPath] && ![fileManager 
fileExistsAtPath:ourWebSQLPath];
    if (copy) { // TODO: should check for errors
        [fileManager createDirectoryAtPath:ourWebSQLPath 
withIntermediateDirectories:YES attributes:nil error:&err];
        [fileManager copyItemAtPath:WebSQLIndex toPath:ourWebSQLIndex 
error:&err];
        [fileManager copyItemAtPath:WebSQLDb toPath:ourWebSQLDb error:&err];
        [fileManager removeItemAtPath:WebSQLPath error:&err];
    }
    
    NSUserDefaults* appPreferences = [NSUserDefaults standardUserDefaults];
    NSBundle* mainBundle = [NSBundle mainBundle];
    
    NSString *bundlePath = [[mainBundle bundlePath] 
stringByDeletingLastPathComponent];
    NSString *bundleIdentifier = [[mainBundle infoDictionary] 
objectForKey:@"CFBundleIdentifier"];
    NSString* libraryPreferences = @"Library/Preferences";
    
    NSString* appPlistPath = [[bundlePath 
stringByAppendingPathComponent:libraryPreferences]    
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", 
bundleIdentifier]];
    NSMutableDictionary* appPlistDict = [NSMutableDictionary 
dictionaryWithContentsOfFile:appPlistPath];
    
    BOOL dirty = NO;
    
    NSString *value;
    NSString *key = @"WebKitLocalStorageDatabasePathPreferenceKey";
    value = [appPlistDict objectForKey: key];
    if (![value isEqual:ourLocalStoragePath]) {
        [appPlistDict setValue:ourLocalStoragePath forKey:key];
        dirty = YES;
    }
    
    key = @"WebDatabaseDirectory";
    value = [appPlistDict objectForKey: key];
    if (![value isEqual:ourWebSQLPath]) {
        [appPlistDict setValue:ourWebSQLPath forKey:key];
        dirty = YES;
    }
    
    if (dirty) 
    {
        BOOL ok = [appPlistDict writeToFile:appPlistPath atomically:YES];
        NSLog(@"Fix applied for database locations?: %@", ok? @"YES":@"NO");
        [appPreferences synchronize];
    }
{code}

What do you think ?

Also, I have a suggestion for this plugin.
It is possible to remove the data storage quota limit for WebkitSQL by running 
simple sqlite queries on the sql files. I am currently doing this with my 
plugin https://github.com/davibe/Phonegap-SQLitePlugin using it from javascript 
code to open Databases.db and run the following queries:

{code}
update origins set quota = '999999999999' where origin = 'file__0';
update databases set estimatedSize = '999999999999' where name = '" + dbName + 
"';
Where db name is the name of the db being patched.
{code}


About the mentioned Phonegap SQLitePlugin.
I tried to use my sqlite plugin instead of the database interface offered by 
webkit. I have read Edgar Canas suggesting this. I can tell from my experience 
that for some reason It's much slower. The bottleneck seems to be passing long 
queries (I store jsons that are over 1Mb) from the webview to native code. 
WebkitSQLite does not suffer from this.
By the way I have plans porting it to Cordova, any suggestion is welcome.



                  
> localStorage / SQLDatabase no longer persistent after iOS 5.01 Update
> ---------------------------------------------------------------------
>
>                 Key: CB-330
>                 URL: https://issues.apache.org/jira/browse/CB-330
>             Project: Apache Callback
>          Issue Type: Bug
>          Components: iOS
>    Affects Versions: 1.3.0, 1.4.0, 1.5.0
>         Environment: iOS 5.01
> PhoneGap (Any version)
> Xcode 4
> Build.PhoneGap
>            Reporter: Amirudin Bin Mohamed Ghani
>            Assignee: Shazron Abdullah
>            Priority: Blocker
>              Labels: ios5.01, localstorage, sqldatabase, websql
>             Fix For: 1.6.0
>
>         Attachments: CDVLocalStoragePlugin.zip, 
> Directory-Structure-CB-330.zip, LocalStorageTest.zip, README.txt, iOS WebKit 
> Database Locations.txt
>
>
> Dear Dev
> WebKit data (localstorage or local SQLite) are now stored in Library/ Caches 
> folder (instead of Library/WebKit folder). This is a big problem for all apps 
> using UIWebView and storing user data, because they will no longer be backed 
> up and may be deleted. There are a lot of apps using localstorage or SQLite 
> as a critical feature. 
> The SQLite database gets deleted because the database is saved in a location 
> on the filesystem which Apple does not consider to contain persistent data.
> *Steps to Reproduce:* 
> In a UIWebView, create a new DB or use localStorage with JavaScript. 
> You can see that the WebKit data is now stored in Library/Caches :  
> *Expected Results:*
> We should at least specify the directory of WebKit data (and to set it 
> to Documents/ for critical data) 
> *Actual Results:* 
> The WebKit data are stored in Library/Caches folder, and can be 
> deleted 
> *Regression:*
> To migrate database location from Library/Caches to some other location such 
> as Documents.
> ----
> Ref: http://developer.apple.com/icloud/documentation/data-storage/
> https://devforums.apple.com/thread/137882?start=0&tstart=0

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: 
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Reply via email to