ios sqlite error : attempt to write a read-only database - ios

I made the iOS app unity.
It also successfully selected data from sqlite.
But when I insert, the error below appears.
mono.data.sqlite.sqliteexception (0x80004005): attempt to write a read-only database
The path to the DB file is here.
string filepath = Application.dataPath + "/Raw/Data.db";
if (!File.Exists(filepath))
{
File.Copy(Application.streamingAssetsPath + "/Raw/Data.db", filepath);
}
I wonder if I should set write permissions or change the path of the file.
What should I do if I have to grant write permission?
If I have to change the route, where should I go?

In the official documentation you have this:
On many platforms, the streaming assets folder location is read-only; you can not modify or write new files there at runtime. Use Application.persistentDataPath for a folder location that is writable.
Solution: Use Application.persistentDataPath instead of streaming asset folder.

Related

Play downloaded Widevine Classic files from app document folder in iOS?

I am trying to play wvm files from the app documents folder since 3 days but without success...
I removed "file://" from my path but I still get 1013 error (as discussed here), does someone have some sample code or at least the procedure to follow to make it works properly?
WV_RegisterAsset(myFilePath) always return WViOsApiStatus(rawValue: 1013)
The file should exists because when I try this:
let fileManager = NSFileManager()
print(fileManager.fileExistsAtPath(myFilePath))
It returns true
Thanks in advance for your help!
Widevine Classic on iOS uses an "asset root" directory. When you initialize the library, you pass it in the settings dictionary using the key WVAssetRootKey.
After that, all local asset pathnames you pass to the library are relative to the AssetRoot.
One simple option is to use NSHomeDirectory() as the AssetRoot, and then trim it from the beginning of absolute pathnames.

Unable to open a realm at path

I am trying to use a bundled realm file without success. I know that my realm file was copied successfully to my application’s Directory but I ca not read it.
fatal error: 'try!' expression unexpectedly raised an error: "Unable
to open a realm at path
'/Users/…/Library/Developer/CoreSimulator/Devices/…/data/Containers/Data/Application/…/Documents/default-v1.realm'.
Please use a path where your app has read-write permissions."
func fullPathToFileInAppDocumentsDir(fileName: String) -> String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,NSSearchPathDomainMask.UserDomainMask,true)
let documentsDirectory = paths[0] as NSString
let fullPathToTheFile = documentsDirectory.stringByAppendingPathComponent(fileName)
return fullPathToTheFile
}
In didFinishLaunchingWithOptions:
let fileInDocuments = fullPathToFileInAppDocumentsDir("default-v1.realm")
if !NSFileManager.defaultManager().fileExistsAtPath(fileInDocuments) {
let bundle = NSBundle.mainBundle()
let fileInBundle = bundle.pathForResource("default-v1", ofType: "realm")
let fileManager = NSFileManager.defaultManager()
do {
try fileManager.copyItemAtPath(fileInBundle!, toPath: fileInDocuments)
} catch { print(error) }
}
And setting the configuration used for the default Realm:
var config = Realm.Configuration()
config.path = fileInDocuments
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm(configuration: config) // It fails here!!! :-)
As the documentation suggests, I have tried as well to open it directly from the bundle path by setting readOnly to true on the Realm.Configuration object. I am not sure if this is something related to Realm or if I am overlooking something with the file system…. I have also tried to store the file in the Library folder.
Realm 0.97.0
Xcode Version 7.1.1
I tried to open the realm file using Realm's browser app and the file does not open anymore. It has now new permissions: Write only (Dropbox). So, I decided to change the file permission back to read/write using file manager’s setAttributes method. Here is how I did it:
// rw rw r : Attention for octal-literal in Swift "0o".
let permission = NSNumber(short: 0o664)
do {
try fileManager.setAttributes([NSFilePosixPermissions:permission], ofItemAtPath: fileInDocuments)
} catch { print(error) }
The realm file can now be open at this path.
That exception gets thrown whenever a low level I/O operation is denied permission to the file you've specified (You can check it out on Realm's GitHub account).
Even though everything seems correct in your sample code there, something must be set incorrectly with the file location (Whether it be the file path to your bundle's Realm file, or the destination path) to be causing that error.
A couple of things I can recommend trying out.
Through breakpoints/logging, manually double-check that both fileInDocuments and fileInBundle are being correctly created and are pointing at the locations you were expecting.
When running the app in the Simulator, use a tool like SimPholders to track down the Documents directory of your app on your computer, and visually ensure that the Realm file is being properly copied to where you're expecting.
If the Realm file is in the right place, you can also Realm's Browser app to try opening the Realm file to ensure that the file was copied correctly and still opens properly.
Try testing the code on a proper iOS device to see if the same error is occurring on the native system.
If all else fails, try doing some Realm operations with the default Realm (Which will simply deposit a default.realm file in your Documents directory), just to completely discount there isn't something wrong with your file system
Let me know how you go with that, and if you still can't work out the problem, we can keep looking. :)
This will occur if you have your realm file open in Realm Studio at same time you relaunch your app. Basically in this case Realm can't get write permissions if Studio already has them.
To add to the solution based on what I've discovered, make note of what error Realm reports when it throws the exception, as well as the type of Error that is passed.
As of writing, Realm documents their errors here:
https://realm.io/docs/objc/latest/api/Enums/RLMError.html
What this means is that you can find out if your Realm file has permissions problems and react to those based on Realm passing you a RLMErrorFilePermissionDenied. Or if the file doesn't exist with RLMErrorFileNotFound.
The tricky thing I'm finding is when you get a more generic RLMErrorFileAccess, but that's for another question on Stack Overflow...
I had the same issue and tried too many ways to fix it. The easiest way to fix this problem is manually creation of the folder XCode cannot reach '/Users/…/Library/Developer/CoreSimulator/Devices/…/data/Containers/Data/Application/…/Documents/...' as explained at https://docs.realm.io/sync/using-synced-realms/errors#unable-to-open-realm-at-path-less-than-path-greater-than-make_dir-failed-no-such-file-or-directory
Once you created this folder and run the project, XCode creates the Realm files inside this folder automatically.

Permanent file directory in Xcode

In the documents directory for my app, I have a file Q1.dat which I use in my program. I access it through the path:
func createArrayPath () -> String? {
if let docsPath: String = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last {
return ((docsPath as NSString).stringByAppendingPathComponent("Q1") as NSString).stringByAppendingPathExtension("dat")
}
return nil
}
When I run the program on a different device however, a different documents directory is created, and the file is no longer present. Is there a place I can put the file so that I can always access it no matter what device I am running on?
The Documents directory is meant for data created by the user.
It sounds like you want to bundle a resource with your application. You can do this by simply dragging the file into Xcode, which will automatically set it up to be copied into your app bundle, and you can find it using URLForResource(_:withExtension:).
If the file is very large, you might want it to be downloaded separately from the main app. For this you can use the new On-Demand Resources feature.

Xamarin iOS swap image in bundle at runtime

I want to allow my app to download images from the web to be placed in /images and then displayed in the UI - this is to allow branding specific images to be downloaded for a multitenant app.
The app downloads the image fine and places the image into the /Images folder
However when trying to load the image using UIImage.FromFile it always returns null - even though I know full well the image is there!
I know UIImage.FromBundle caches stuff so I chose to use FromFile but this doesn't seem to work?!
Is there something I need to do to make this work? Or am I pushing my luck a little?
I am using the following to create the file path:
public static UIImage SafeClaim_Logo = UIImage.FromFile(NSBundle.MainBundle.BundlePath +"/Images/Logo.png");
The following is the code I use to download and save the file - the file path from the above is the same below when I inspect it
HttpClient client = new HttpClient ();
var clientResponse = await client.GetByteArrayAsync(url);
using (FileStream fs = new FileStream(NSBundle.MainBundle.BundlePath + path, FileMode.OpenOrCreate))
{
var bytes = clientResponse;
fs.Write(bytes, 0, bytes.Length);
}
The app bundle is read-only so you can't change or add something in there at runtime.
All content created at runtime should be stored in your documents or cache folders.
You can get the documents folder by calling:
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
One good place to store this kind of files is the Library/ folder. On iOS 7 you can access it using:
var libraryFolderPath = Path.GetFullPath(
Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments), "..", "Library"));
On iOS 8:
var url = NSFileManager.DefaultManager.GetUrls (
NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomain.User) [0];
var libraryFolderPath = url.Path;
The reason is explained by Xamarin documentation:
The Library directory is a good place to store files that are not
created directly by the user, such as databases or other
application-generated files. The contents of this directory are never
exposed to the user via iTunes.
You can create your own subdirectories in Library; however, there are
already some system-created directories here that you should be aware
of, including Preferences and Caches.
The contents of this directory (except for the Caches subdirectory)
are backed up by iTunes. Custom directories that you create in Library
will be backed up.
If you need to enable iTunes file sharing and expose the content of the Documents/ folder, your files are not visible to the user.

iOS Adding Initial Core Data file using UIManagedDocument, NOT appdelegate

I am trying to load an initial database into my app so my core data db is not empty upon install. I'm now using this code:
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%#_InitialData", SQL_DATABASE_NAME] ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
(from http://code.google.com/p/coredatalibrary/wiki/LoadingInitialData)
to try and load an initial sqlite file for my core data to use. It isn't working and my program differs from the type used in that link in a few ways.
It appears the tutorial uses a file created to "use core data", which I am not. I just didn't happen to learn it that way (watched the stanford cs193p videos) and instead I'm using UIManagedDocument and performing this code in my top view controller. Because of this, I've run into a few problems.
I loaded up my app to create the initial data base so I could save the file to use for initial values. Upon doing so, I found that the way things are saved are different from in the tutorial. For example, if my url for my UIManagedDocument is .../Documents/Test , then my database file is .../Documents/Test/Store Content/persistentStore, where "persistentStore" is the database file. For one thing, a "Store Content" directory has been added. In addition, the sqlite file is named persistentStore and has no file extension. When I open the file it says
SQLite format 3���# �����������������������������������������������������������������-‚%
on the top though (I'm not familiar with SQLite or any db format for that matter but I assume this means it is an sqlite file).
I save this "persistentStore" file to use to load into my app using the code above. Upon doing so, I found that copyItemAtPath:toPath:error: will not copy as I expect. For example, if the storePath is .../Documents/Test , then my sqlite file that I'm copying over becomes renamed to Test.sqlite and is located at .../Documents/ instead of copying my file to a location of .../Documents/Test/.
Because of this, when I try to open the UIManagedDocument at that url (.../Documents/Test) I get this error
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason:
'UIManagedDocument can only read documents that are file packages'
I've tried creating a directory to mimic the one created by core data before copying over my intial data (that is, I create the directories to have a path of .../Documents/Test/Store Content/ and then copy my initial data to be in the "Store Content" folder with a name of persistentStore) but that also doesn't work. UIManagedDocument can't open the document.
So how can I load in initial values to my core data db without having a project that is set to "use core data"? I have the (presumably) sqlite file with the initial data (when I open it and skim it it appears to have my initial values), so I just need to know how to copy it over properly so that I can still used UIManagedDocument to open the document and save via the UIManagedObjectContext.
It turns out my way of recreating the path created by core data worked. That is, creating the directories of .../Test/Store Content/ and copying the file as "persistentStore". My error was a small one. It was suppose to be StoreContent instead of "Store Content"; I added a space...

Resources