Hi all, is there anyone using KMMBridge and SQLCi...
# touchlab-tools
s
Hi all, is there anyone using KMMBridge and SQLCipher for iOS? Asking because SQLCipher is not supporting SPM yet, so I am curious if we should switch to the KMMBridge because it suggests using SPM. Currently we are installing our KMM library using Cocoapods and it installs the SQLCipherđź”’ along the way, like this(build.gradle.kts):
Copy code
kotlin {  
  cocoapods {
    summary = "My Library"
    homepage = "github_path_to_the_library"
    ios.deploymentTarget = "14.0"
     
    tasks.withType(org.jetbrains.kotlin.gradle.tasks.CInteropProcess::class.java) {
      settings.compilerOpts("-DNS_FORMAT_ARGUMENT(A)=")
    }

    framework {
      baseName = "MyLibrary"
    }

    pod(name = "SQLCipher", version = "4.5.7") // <- HERE
    …
  }
}
k
KMMBridge doesn't support SPM importing. It's for SPM exporting. What the
pod(name = "SQLCipher", version = "4.5.7")
does is run cinterop on SQLCipher, then include the native dependency in builds and tests. Producing a version of that for SPM would be a huge effort. It is something I think JetBrains should have done years ago, and is a major issue across many KMP libraries that need native libraries included.
See https://docs.sentry.io/platforms/kotlin/guides/kotlin-multiplatform/manual-setup/#apple-installation-methods, from the Sentry KMP library. Specifically:
In order to install the Sentry Kotlin Multiplatform SDK, you need to use Cocoapods and Swift Package Manager simultaneously, which might seem unconventional at first, especially if you're accustomed to using SPM for all your dependencies
The key here is they're using CocoaPods to import the dependency in Kotlin, but then the app consuming the build can use SPM. It's an ugly and confusing situation, but that's the situation.
SQLCipher specifically is a special case. If this is your project and not a library that's being published, Kotlin doesn't need to know about SQLCIpher at all. SQLCipher is a drop-in replacement for Sqlite (not on Android). You just need to make sure the Xcode/iOS build is using SQLCipher and properly linking to it and not linking to the platform Sqlite bindings.
s
thank you @kpgalligan may I ask what would you suggest in our situation? Use KmmBridge in Cocoapods keeping the SQLCipher being installed along the way? Yes, we are using pubilc SQLCipher library made by Zetetic.
k
We had a blog post about it, but I'm reluctant to link to it only because it's several years old. But, here. Two, actually: https://touchlab.co/sqlcipher-kotlin-multiplatform-mobile and https://touchlab.co/multiplatform-encryption-with-sqldelight-and-sqlcipher. I wrote the SqlDelight driver for native, so if you're using SqlDelight, you just need to add the encryption config to the setup. If you're using room, no idea.
s
yes, we are using SQLDelight and SQLCipher
k
For SqlCipher, I would not. CocoaPods isn't embedding SqlCipher in the project. It's just adding the dependency to the podspec. cinterop doesn't embed binaries, it just generates Kotlin adapters to call native code. So, effectively, if you use SPM, you just need to make sure you have the SQLCIpher dependency when you build Xcode, and follow ALL of the instructions from SQLCipher, because it's very easy to have the wrong config and wind up with unencrypted DBs. We did a client build last year, and I wrote a check that only ran in debug mode that would crash the app if the db wasn't encrypted, because if a dev changes a setting, SQLCipher won't be used (or it won't build with encryption turned on. I forget exactly). That's not unique to SPM. You need to be very careful with CocoaPods as well.
However, if using SqlDelight, bear in mind that it silently adds the linker flag to include the system sqlite3 binary. You need to turn that off explicitly in the Gradle config. Of course, it's not so simple if you're building dynamic frameworks and/or running tests in Kotlin, because you need the sqlite link. Hmm. I guess, if you're not deeply experienced in native linking, I might keep the CocoaPods. But, again, you don't need to use CocaoPods in Xcode. You can use SPM. The
pod
block is only there to run cinterop. It's hard to explain. KMP's real learning curve is linking.
s
yeah I know that SQLCipher is very tricky, I tried to switch it from Cocoapods to manual integration, but could not resolve the
SQLITE_NOTADB
crash when updating the app(on fresh install after deleting app it worked fine). Also I could not move the SQLCipher from KMM to iOS directly since all the stuff is handled in KMM. However, if I understood you correctly, with the current implementation I pasted in the question, I can still follow KMMBridge SPM Quick Start and keep SQLCipher like it is, adding dependency to the podspec and KMM will still be available to handle it, without me having a podfile and stuff on the iOS side?
k
Also I could not move the SQLCipher from KMM to iOS directly since all the stuff is handled in KMM.
Not sure what you mean by this. SQLCipher on ios builds the same references as sqlite. The "extra" stuff it does is internal and/or in sql statements. It's been a while, though. It's maybe adding some C calls on top, but IIRC, the calls necessary to encrypt the DB are available to stock sqlite. You just won't get encryption. CocoaPods is just adding the SQLCipher dependency, which CocoaPods in Xcode is using to add SQLCiper. For SPM, you'd need to add that manually to your Xcode build.
No idea about
SQLITE_NOTADB
s
For SPM, you’d need to add that manually to your Xcode build.
you mean for installing SQLCipher using SPM or KMMBridge with SPM? I am asking because SQLCipher is not available for SPM yet.
k
SQLCipher is not available for SPM yet.
Oh, weird. I did not know that. The client project we did last year was using CocoaPods (which is rare these days)
Um, hmm. In that case, I'd stick with CocoaPods unless you can't.
👍 1
s
yes, they have been trying to make it for years but nothing: source. so, to confirm, KMMBridge CocoaPods Quick Start is the one for us? I still have a lot of learning about KMM and stuff (as an iOS dev) ahead of me, so I am asking some questions that may sound funny for someone, but thank you for your patience!
k
Ah, iOS dev! Interesting. Most KMP devs come from Android and aren't even aware of what "linking" is. If you're wondering if anybody else gets confused and frustrated with Gradle, the answer is yes, but it's more of an issue with how Android, KMP, and the ides all fit together as they kind of get breaking changes independently a few times a year and all tutorials are old. Anyway...
👍 1
Confirmed on the Quick Start. Bear in mind that we really neglected CocoaPods in KMMBridge for the last few releases, and only put extra effort in for the recent releases, so you may run into some surprises. Most people using KMMBridge (and KMP) are using SPM, so it's rare to get questions or issue reports. When we do, CocoaPods or SPM, they're usually issues with not understanding how the Xcode toolchain works, but I digress.
👍 1
thank you color 1
s
hi @kpgalligan, its me again. We have successfully published Android & iOS versions using kmmbridge. Is there any kmmbridge-solution for version autoincrement? We have found some solutions but they are kinda tricky.
k
What kind of versioning are you looking for? Automatically updating the patch versions on builds?
s
yes, instead of manually changing it each time: version = “1.0.0” we added some CI to run kmmbridge on pull request, and are now looking for the way to automatically increment version so we dont get 409 conflict error in Actions.
k
Ah. We used to have a much more complicated flow in KMMBridge doing automatic versioning on builds. Over the last few releases, we've been taking complications out of KMMBridge itself. Doing it inside KMMBridge was a huge problem because we were already in Gradle, but Gradle publishing really doesn't like when you try to change the version because it's already been evaluated. The later version of autoversion we had took a tag version prefix, then looked at git tags to calculate the next version. That is also complex because of the way CocoaPods publishes. Essentially it needs to build before it'll publish. So, you needed to push the binary, then run the build, then do all the tag stuff later. Anyway, the GitHub action code we had is still around, but we haven't used it for quite a while. You can see an example here: https://github.com/touchlab/KMMBridgeGithubWorkflow/blob/f98a8b44a278cbea152e8ef1571f7e2054863188/.github/workflows/faktorybuildautoversion.yml We kept a version base value in gradle.properties. Something like:
Copy code
LIBRARY_VERSION=0.1
In the GitHub Actions workflow, read the value:
Copy code
- uses: touchlab/read-property@0.1
        id: versionBasePropertyValue
        with:
          file: ./gradle.properties
          property: ${{ inputs.versionBaseProperty }}
Then pass that to autoversion:
Copy code
- uses: touchlab/autoversion-nextversion@main
        id: autoversion
        with:
          versionBase: ${{ steps.versionBasePropertyValue.outputs.propVal }}
Then that gets passed into the Gradle build task:
Copy code
-PAUTO_VERSION=${{ steps.autoversion.outputs.nextVersion }}
You can get a sense for how it works from this: https://github.com/touchlab/KMMBridgeSKIETemplate. That's an old template, though, which had an overly CI setup. You should just need to add the stuff mentioned above, then in the Gradle build script, test if AUTO_VERSION was passed in, and if so, use that.
Copy code
val autoVersion = project.property(
    if (project.hasProperty("AUTO_VERSION")) {
        "AUTO_VERSION"
    } else {
        "LIBRARY_VERSION"
    }
) as String

subprojects {
    val GROUP: String by project
    group = GROUP
    version = autoVersion
}
You can see it in https://github.com/touchlab/KMMBridgeSKIETemplate/blob/main/build.gradle.kts#L13