Search code examples
iosswiftxcodesqliteimessage

Using an existing database in an iMessage app (Swift)


Currently building an iMessage app, and would like to experiment with using a database. I have a database that I would like to use in the app, and have included it in my project, and verified the target membership is correct. Using SQLite.Swift.

Whenever I try opening the connection to the database in simulator, I always get an error (unexpected nil) for the path of the database.

I've tried an image file the same way with no avail.

 let imagePath = Bundle.main.path(forResource: "db", ofType: ".sqlite")

    do {
        let db = try Connection(imagePath!, readonly: true)

    } catch {

    }

Solution

  • I believe the issue is more related to what an iMessage "app" is - which is actually an extension, not a true app. There's no initial VC, thus no real Bundle.main to get to.

    One (maybe soon a second) app of mine has a Photo Editing Extension - basically what I always have called a "shell connection" to an Apple app. You really have either a "do nothing" app with a connection to one of their apps, or you have a stand-alone app an share the code with the extension.

    My solution for sharing code is to use a Framework target. Yes, a third project. (App, extension, shared code.) I found a technique that I think should work for you - basically, for images, scripts (my apps use .cikernel files) you add them into the framework project and return what you need in a function call.

    You may be able to streamline this with a need for a Framework target. YMMV. The basics are this:

    • Someplace in Xcode you have a "Bundle Identifier". Something like *"com.company.projectname".
    • Put your files into a folder, maybe on your desktop. Add an extension to this folder called ".bundle". macOS will give you a warning, accept it. All you are really doing is creating your bundle.
    • Drag this into your Xcode project.
    • Code to get to this bundle, and the files inside it. (I'm not sure if need a framework here - try to drag this into your "MessagesExtension" target first.

    So lets say you have images you wish to share between projects, extensions, whatever. After moving them into a folder called "images", andrenaming the folder with a ".bundle" at the end, and finally dragging it into your Xcode project, you pretty much need to add this function:

    public func returnImage(_ named:String) -> UIImage {
        let myBundle = Bundle.init(identifier: "com.company.project")
        let imagePath = (myBundle?.path(forResource: "images", ofType: "bundle"))! + "/" + named
        let theImage = UIImage(contentsOfFile: imagePath)
        return theImage!
    }
    

    For a text file you want:

    public func returnKernel(_ named:String) -> String {
        let myBundle = Bundle.init(identifier: "com.company.project")
        let kernelPath = (myBundle?.path(forResource: "cikernels", ofType: "bundle"))! + "/" + named + ".cikernel"
        do {
            return try String(contentsOfFile: kernelPath)
        }
        catch let error as NSError {
            return error.description
        }
    }
    

    Usage, for an image called "Camera.png" which is part of a bundle called "images.bundle":

    let cameraImage = returnImage("Camera")
    

    Since I don't work with SQLite files I don't have the exact code, but I think this should work. Remember to change "com.company.project" to what you have for the bundle identifier.