0

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 {

    }
  • I work with Photos Extensions, and if I read you correctly, an "iMessage app" is actually more of a Messages *extension* than an actual *app*. I created one and "out of the box" I see two targets and no main view controller. Based on that (and my experience with Photo extensions) I think the issue is with `Bundle.main` - there is none. I use a Framework target, and there *is* a way to include images and scripts and find the location of the "bundle" in this. If you'd like, I can post that code as an answer. (Edit: I don't know if this will work with a db, but it should.) –  Jul 28 '17 at 23:03
  • https://stackoverflow.com/questions/23236554/sqlite3-from-bundle-resources-in-ios – john elemans Jul 28 '17 at 23:37
  • @dfd I'm willing to try anything. I appreciate the help. – itsinthekeys Jul 29 '17 at 00:42

1 Answers1

1

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.

  • Very instructional! Thank you! I'll try to give it a go later tonight. I'll update when I get something working. – itsinthekeys Jul 29 '17 at 02:07
  • I apologize, I'm still new to Swift. In the functions, are you passing a String into the function? -- Never mind, I'm just a little slow sometimes, lol – itsinthekeys Jul 29 '17 at 02:26
  • I went ahead and gave the image function a try first in my actual project and the second time in a new one. It crashes both times I tried. I could try using it as a framework instead? Pics: http://imgur.com/ub2xpMB http://imgur.com/y3E91z7 – itsinthekeys Jul 29 '17 at 02:51
  • A couple of things: (1) In your .xcodeproj General properties, is your bundle ID "zb.test"? (2) Is the image "pic" a ".png" or ".jpg" - if it's the latter, you'll need to add the extension of the file. (3) Is the image in a ".bundle"? It looks like you might need to try a framework. –  Jul 29 '17 at 10:26
  • I got it working! I had two problems: I hadn't fully checked that the bundle ID was valid (I believe it said something about it not being unique enough), so I changed it. The other was adding ".MessagesExtension" to the end of the identifier in the function. Once I changed those things, your text file function works beautifully, even to find my database file. Thank you! – itsinthekeys Jul 29 '17 at 15:53