How to download sqlite store file of iMessage extension to MacBook
Asked Answered
S

2

3

We are developing an iMessage extension. It uses Core Data successfully. We need to evaluate the store.sqlite file, but can not find it.

We try to find it like this:

  • In Xcode: Window -> Devices
  • In Installed Apps, select our extension
  • Download Container ...

But the container is empty:


Update:

Thanks to @Mundi's answer we found out how to get the models URL:

file:///var/mobile/Containers/Data/PluginKitPlugin/9C15B67C-8917-4A24-9FB0-BD119C43B3C4/Library/Application%20Support/Model.sqlite

Now we are trying to copy the Model to the Documents folder, to be able to download it later to our MacBook via Xcode (see above).

Unfortunately the path to `Documents:

NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]

is again in /var/mobile/Containers/:

file:///var/mobile/Containers/Data/PluginKitPlugin/D0BBD375-A8B7-43DD-8486-1909965CAEB0/Documents

How can we download the Model.sqlite file from a shared container to our MacBook?

Strunk answered 7/11, 2016 at 11:20 Comment(3)
Is it feasible to do this on the simulator? You can then access the files directly in the MacOS file system.Telemann
Unfortunately we need the one from device.Strunk
Doesn't copying the file to Documents directory and sharing it to mac via airdrop programatically solve the problem here? Have you tried doing it like that?Samoyedic
C
1

Your best bet with this is to write an exporter using the mail share action. In one of my apps I allow the user to export all of the data by emailing a copy of the sqlite file.

func exportAllDataSqlite() {
    let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

    var newFilePath: URL!
    var mutablePathComponents = [String]()
    var sqliteFileCopied = false

    do {
        let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: FileManager.DirectoryEnumerationOptions())
        for f in directoryContents {
            let pathComponents = f.pathComponents
            if pathComponents.last == "XXXXWhatever your file is called when created by the persisten store.sqliteXXXXX" {
                //create a copy of the file with a dated file name
                mutablePathComponents = pathComponents

                let dateComponents = (Calendar.current as NSCalendar).components([.day, .month, .year], from: Date())
                let dateString = "\(dateComponents.day)-\(dateComponents.month)-\(dateComponents.year)"

                mutablePathComponents[mutablePathComponents.count-1] = "Events App \(dateString).sqlite"


                newFilePath = NSURL.fileURL(withPathComponents: mutablePathComponents)
                do {
                    try FileManager.default.copyItem(at: f, to: newFilePath!)
                    sqliteFileCopied = true
                    print("Copied sqlite file")
                } catch let error as NSError {
                    print(error.localizedDescription)
                }

            }
        }
    } catch let error as NSError {
        print(error.localizedDescription)
    }

    if sqliteFileCopied == true {
        //sharing
        let activityItem:URL = newFilePath!

        let objectsToShare = [activityItem]
        let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)

        activityVC.completionWithItemsHandler = { activity, success, items, error in
            do {
                try FileManager.default.removeItem(at: newFilePath!)
                print("Deleted file: \(newFilePath!)")
            } catch let error as NSError {
                print(error.localizedDescription)
            }
        }

        let excludeActivities = [UIActivityType.airDrop,
                                 UIActivityType.print,
                                 UIActivityType.assignToContact,
                                 UIActivityType.saveToCameraRoll,
                                 UIActivityType.addToReadingList,
                                 UIActivityType.postToFlickr,
                                 UIActivityType.postToVimeo]
        activityVC.excludedActivityTypes = excludeActivities

        self.present(activityVC, animated: true, completion: nil)
    } else {
        print("file not copied so can't be shared")
    }
}

It's some of my earliest Swift so not great but it works. I used it the other day in a deployed copy of my app to debug an issue, just email to yourself and open with an Sqlite viewer on your mac.

Crypto answered 3/12, 2016 at 19:14 Comment(1)
Hardcore but great :-)Strunk
T
2

The actual sqlite file is likely to be in a shared container.

What works for me is to log the store URL and use that to locate it:

print(container.persistentStoreCoordinator.persistentStores.first!.url!)

Yields something like

file:///Users/developer/Library/Developer/CoreSimulator/Devices/2EAE0CD4-7899-45A3-8E83-E7D79DEEA08F/data/Containers/Data/Application/37F48A5E-7DAB-4E30-A752-F5B62826A15A/Library/Application%20Support/Events.sqlite

Telemann answered 7/11, 2016 at 17:38 Comment(4)
How to get this from NSPersistentContainer?Strunk
I updated the answer to demonstrate how to get to the URL.Telemann
Thanks for the mention. However, to not even up-vote my correct answer and instead just to change the question is not particularly motivating.Telemann
Upvoted and mentioned in question update. The update of the question was not to change it`s semantic but to better describe my actual concern.Strunk
C
1

Your best bet with this is to write an exporter using the mail share action. In one of my apps I allow the user to export all of the data by emailing a copy of the sqlite file.

func exportAllDataSqlite() {
    let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

    var newFilePath: URL!
    var mutablePathComponents = [String]()
    var sqliteFileCopied = false

    do {
        let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: FileManager.DirectoryEnumerationOptions())
        for f in directoryContents {
            let pathComponents = f.pathComponents
            if pathComponents.last == "XXXXWhatever your file is called when created by the persisten store.sqliteXXXXX" {
                //create a copy of the file with a dated file name
                mutablePathComponents = pathComponents

                let dateComponents = (Calendar.current as NSCalendar).components([.day, .month, .year], from: Date())
                let dateString = "\(dateComponents.day)-\(dateComponents.month)-\(dateComponents.year)"

                mutablePathComponents[mutablePathComponents.count-1] = "Events App \(dateString).sqlite"


                newFilePath = NSURL.fileURL(withPathComponents: mutablePathComponents)
                do {
                    try FileManager.default.copyItem(at: f, to: newFilePath!)
                    sqliteFileCopied = true
                    print("Copied sqlite file")
                } catch let error as NSError {
                    print(error.localizedDescription)
                }

            }
        }
    } catch let error as NSError {
        print(error.localizedDescription)
    }

    if sqliteFileCopied == true {
        //sharing
        let activityItem:URL = newFilePath!

        let objectsToShare = [activityItem]
        let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)

        activityVC.completionWithItemsHandler = { activity, success, items, error in
            do {
                try FileManager.default.removeItem(at: newFilePath!)
                print("Deleted file: \(newFilePath!)")
            } catch let error as NSError {
                print(error.localizedDescription)
            }
        }

        let excludeActivities = [UIActivityType.airDrop,
                                 UIActivityType.print,
                                 UIActivityType.assignToContact,
                                 UIActivityType.saveToCameraRoll,
                                 UIActivityType.addToReadingList,
                                 UIActivityType.postToFlickr,
                                 UIActivityType.postToVimeo]
        activityVC.excludedActivityTypes = excludeActivities

        self.present(activityVC, animated: true, completion: nil)
    } else {
        print("file not copied so can't be shared")
    }
}

It's some of my earliest Swift so not great but it works. I used it the other day in a deployed copy of my app to debug an issue, just email to yourself and open with an Sqlite viewer on your mac.

Crypto answered 3/12, 2016 at 19:14 Comment(1)
Hardcore but great :-)Strunk

© 2022 - 2024 — McMap. All rights reserved.