incubator-callback-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Davide Bertola (Issue Comment Edited) (JIRA)" <j...@apache.org>
Subject [jira] [Issue Comment Edited] (CB-330) localStorage / SQLDatabase no longer persistent after iOS 5.01 Update
Date Sun, 25 Mar 2012 08:14:33 GMT

    [ 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:14 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 suggestions are 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 *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

        

Mime
View raw message