Search code examples
iosxcodecore-dataxcode8imessage-extension

How to download sqlite store file of iMessage extension to MacBook


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?


Solution

  • 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.