Access couchbase lite database directly from bundle? - ios

I'm using Couchbase lite for my iOS app. I include the database in my app bundle and I don't have any replication. (I know it's a bit strange to use Couchbase without replication but that's the case)
The problem is that I can't find a way to access the database directly from the bundle since replaceDatabaseNamed will copy it to the document directory. As the database is huge I don't want to duplicate it on the users iPhone with one version in the bundle and one in the document directory.
Do you know a way not to copy the database and to access it directly from the app bundle ?

This works for me and successfully opens the database readonly from the bundle...
CBLManagerOptions options;
options.readOnly = YES;
_manager = [[CBLManager alloc] initWithDirectory:[[NSBundle mainBundle] resourcePath] options:&options error:&error];
if (error == nil) {
// load an existing database
_database = [_manager existingDatabaseNamed:named error:&error];
}
One thing to add here is that if you have any CBLView objects you need to make sure they get run before you save the database. They will fail to update when you are using this as a readonly database.

Related

Replace Data Container of an iOS .ipa File

I have an app that downloads a whole bunch of data from over 100+ APIs upon successful login. I successfully download the data, and then use iExplorer to extract the data container folders (Documents, Library and Tmp) from the fully loaded application.
I would like to take a blank version of the original app, in .ipa format, and insert those data container folders into that fully loaded .ipa file. Then I will be able to take this new fully loaded .ipa, and use a deployment software to deploy it to a bunch of local user's devices. So everyone will have this fully loaded app.
Please, has anyone done this? Please provide some feedback, and don't argue with my methodology, because this has be done this way due to requirements. Maybe there is a step I'm missing? I'm not sure.
With the source code in hand, you can run the app in the simulator (no need for iExplorer), wait for it to download all the files and browse to the folder on your computer where the app was installed.
From there you can put aside any files you want along with their respective folders. If you're using Coredata there should be a SQLITE database file there somewhere (typically in your Application Support folder) and this might be all you need but it is hard to tell without looking at your implementation details.
Once you have the files you need set aside, add them to the app bundle via Xcode and create code to check whether files already exist (in which case you don't want to replace them), and if not copy all files needed from the bundle into their respective folders.
Here's some semi pseudo-code for you:
NSDictionary *userPrefs = [[NSUserDefaults standardUserDefaults] objectForKey:self.email];
if (![userPrefs[kInitialSetupCompleted] boolValue])
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *destinationFilePath = ...
NSURL *seedFilePath = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:kCoreDataStoreName ofType:nil]];
NSError* err = nil;
if (![fileManager copyItemAtURL:seedPath toURL:destinationFilePath error:&err]) {
NSLog(#"Could not copy seed data. error: %#", err);
// Deal with error
} else {
// Set user defaults kInitialSetupCompleted to YES
}
}

Read through my app's Core Data files (.sqlite, .sqlite-wal)

I am trying to browse through the data written by Core Data in an iOS app I am developing.
After the app ran for a while, and I assume collected some data, I now wish to look through the data and see what was written.
I have tried getting and browsing the .sqlite file through getting the app container from the device (Xcode > Devices > myApp > Download Container...).
I got the db files, myAppDB.sqlite, myAppDB.sqlite-shm and myAppDB.sqlite-wal.
When trying to look through them, it seems like the .sqlite is an empty table (except maybe some generic CoreData/sqlite stuff), and the -wal file has all the info.
The thing is I was only able to know that the wal has useful data when opening it with TextEdit, which din't show it in a very readable way, and when I tried to use an SQLite Manager app I an alert saying the wal is encrypted and I am asked to put a password...
For what it matters, I am writing a framework which handles the db (the model file and the code for writing data is inside the framework), then I have this framework running in an app I am developing. This is the code I use to create the store from within the framework (using MagicalRecord):
NSBundle *frameworkBundle = [NSBundle bundleForClass:[self class]];
[MagicalRecord setDefaultModelNamed:#"myAppStore.momd" inBundle:frameworkBundle];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"myAppStoreDB.sqlite"];
[MagicalRecord setupCoreDataStackWithStoreAtURL:storeURL];
UPDATE: I managed to open the sqlite file with both Core-Data-Editor and CoreDataUtility but they both override and delete the contents of the .wal file, and show an empty table... It does have the model (entity names/properties etc.) but no data.
My wal file is 873KB but when I open the sqlite with one of these 2 tools it becomes 0Bytes...
tl;dr
How can I browse through the info written by Core Data of the app I am developing?
Well, for some reason I had to force not using WAL in my store (using #"journal_mode":#"DELETE" as explained here).
I then got only .sqlite file without the smh and wal files, and was able to open it and view the data using the 2 mentioned tools (Core-Data-Editor and CoreDataUtility).
My guess is that this is something to do with either the fact that I am dealing with CoreData from a framework (creating a moc, creating entities, saving etc.) and not from the application. Another guess is that it has something to do with the fact that I am using MagicalRecord.
Any insights regarding the cause would be appreciated...

Can you release an iOS app with a pre-populated sql db

I'm trying to load an sql database full of assets for my app to use upon release.
As I understand it, you can save the database to the applicationDocumentsDirectory:
NSURL *storeURL = [[self applicationDocumentsDirectory]
URLByAppendingPathComponent:DATABASEFILENAME];
But that gets saved locally on the simulator or the test device so I'd need to keep the source assets and release them with my app to generate that sql database.
I could release the app with the assets, populate the db on first run and delete the assets. Is there anyway to just include my pre-populated DB?
Yes. Simply copy the generated DB from your simulator Documents/ folder (file will have .sqlite extension) and put it in your project - making sure to add it to the package...
Yes , certainly there's a good way. Please see my answer in the link below. I have written with explanation and sample code. Hope that will help you.
Reading an already made sqlite file on ios

Dropbox Sync API iOS copy files to app documents

Does the Dropbox Sync API allow for copying directories or files from Dropbox into the app sandbox directories?
I was excited to use the Dropbox Sync API and use Dropbox to manage media assets between my OS X machine and an iPad running my app.
I integrated the Sync API pretty quickly and am able to open files and save them in to Dropbox again.
Because my app is already set up with many many calls to dynamically load media assets, it would add unnecessary complexity to try to open all those assets from the Dropbox filesystem. My intention was to use the Sync API to determine if there are updated assets and then copy them in to one of my application directories.
But it seems that nearly all the objects returned using the Sync API are DBObjects, and I can't perform normal NSFilesystem file operations such as copy. Also the DBObjects seem to have no copy functions themselves.
Is there any way to do this without resorting to the CorecAPI?
Example, for an arbitrary file type called story
//get a list of stories and put them in an array
DBPath *storyPathDB = [[DBPath root] childPath:#"/storyBundlesDB"];
NSArray *listOfStoriesDB = [[DBFilesystem sharedFilesystem] listFolder:storyPathDB error:nil];
for (DBFileInfo *story in listOfStoriesDB)
{
//now I can list out the path of my stories, but that's about it...
DBPath *storyPath = story.path;
NSLog(#"%#",storyPath.stringValue);
//How can I treat these stories whether they are directories or .mov, .png, and copy them to my app directory?
}
I saw this question here Data syncing with DropBox API and iOS where people suggested using the SyncAPI for exactly this purpose, but it seems as if noone on that thread had actually tried it.
You could use readData to read the contents of the file and then write it to another location, if you can't directly use the DBFile objects.
Note that if you want to get notifications when a file (in Dropbox) changes, you'll need to hold that file open. Essentially, files are only updated when you hold the file open, get a notification that there's newer content available, and then call update.

coredata - deliver / setup default data

I use coreData in my iOS App. It's possible, that the user Add, Delete Data into the Database.
I have to deliver default data ( some different data-sets ).
At the moment, I'm creating the database by first Application launch. I read data from a csv file an create the database with it.
The csv is in the Application sandbox; the coreData (managedDocument) is in ApplicationDocument (creation on runtime...).
It works perfect for me - but I ask me, will Apple allow that, if I push the App to the AppStore?
There is nothing wrong with this approach and it can't be a reason for rejection. There is also another way to do it. You can create the database the way you do it now, copy the .sqlite file and provide it as your default database. Then copy it on app first run. The following code will do it:
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent: #"YourDBName.sqlite"];
if (![fileManager fileExistsAtPath:storeURL.path]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"YourDBName" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storeURL.path error:NULL];
}
}
With this approach you will not need to include your csv file in your bundle.
Yes, apple does allow shipping a database populated by default.
the standard way to do it is to ship a default database in your bundle, then at launch time check if there is a database in your application documents directory, and if it does not exist, then copy the database from your bundle to the documents directory.

Resources