Skip to content

Commit 9c664a6

Browse files
authored
watchOS support (#201)
1 parent 5b2244a commit 9c664a6

File tree

12 files changed

+127
-67
lines changed

12 files changed

+127
-67
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
matrix:
1717
include:
1818
- os: macos-latest
19-
targets: iosSimulatorArm64Test macosArm64Test jvmTest
19+
targets: iosSimulatorArm64Test macosArm64Test watchosSimulatorArm64Test jvmTest
2020
- os: ubuntu-latest
2121
targets: testDebugUnitTest testReleaseUnitTest jvmTest lintKotlin
2222
- os: windows-latest

PowerSyncKotlin/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ kotlin {
1616
iosSimulatorArm64(),
1717
macosArm64(),
1818
macosX64(),
19+
watchosDeviceArm64(),
20+
watchosArm64(),
21+
watchosSimulatorArm64(),
22+
watchosX64(),
1923
).forEach {
2024
it.binaries.framework {
2125
baseName = "PowerSyncKotlin"

connectors/supabase/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ plugins {
1212
}
1313

1414
kotlin {
15-
powersyncTargets()
15+
// The Supabase KMP project does not support arm64 watchOS builds
16+
powersyncTargets(watchOS = false)
1617
targets.withType<KotlinNativeTarget> {
1718
compilations.named("main") {
1819
compileTaskProvider {

core/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinTest
99
import java.nio.file.Path
1010
import kotlin.io.path.createDirectories
1111
import kotlin.io.path.writeText
12+
import org.jetbrains.kotlin.konan.target.Family
1213

1314
plugins {
1415
alias(libs.plugins.kotlinMultiplatform)
@@ -161,6 +162,15 @@ kotlin {
161162
compileTaskProvider {
162163
compilerOptions.freeCompilerArgs.add("-Xexport-kdoc")
163164
}
165+
166+
if (target.konanTarget.family == Family.WATCHOS) {
167+
// We're linking the core extension statically, which means that we need a cinterop
168+
// to call powersync_init_static
169+
cinterops.create("powersync_static") {
170+
packageName("com.powersync.static")
171+
headers(file("src/watchosMain/powersync_static.h"))
172+
}
173+
}
164174
}
165175
}
166176

core/src/appleMain/kotlin/com/powersync/DatabaseDriverFactory.ios.kt renamed to core/src/appleMain/kotlin/com/powersync/DatabaseDriverFactory.apple.kt

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import co.touchlab.sqliter.sqlite3.sqlite3_enable_load_extension
1212
import co.touchlab.sqliter.sqlite3.sqlite3_load_extension
1313
import co.touchlab.sqliter.sqlite3.sqlite3_rollback_hook
1414
import co.touchlab.sqliter.sqlite3.sqlite3_update_hook
15+
import com.powersync.DatabaseDriverFactory.Companion.powerSyncExtensionPath
1516
import com.powersync.db.internal.InternalSchema
1617
import com.powersync.persistence.driver.NativeSqliteDriver
1718
import com.powersync.persistence.driver.wrapConnection
@@ -22,6 +23,7 @@ import kotlinx.cinterop.MemScope
2223
import kotlinx.cinterop.StableRef
2324
import kotlinx.cinterop.alloc
2425
import kotlinx.cinterop.asStableRef
26+
import kotlinx.cinterop.free
2527
import kotlinx.cinterop.nativeHeap
2628
import kotlinx.cinterop.ptr
2729
import kotlinx.cinterop.staticCFunction
@@ -132,38 +134,9 @@ public actual class DatabaseDriverFactory {
132134
connection: DatabaseConnection,
133135
driver: DeferredDriver,
134136
) {
135-
val ptr = connection.getDbPointer().getPointer(MemScope())
136-
val extensionPath = powerSyncExtensionPath
137-
138-
// Enable extension loading
139-
// We don't disable this after the fact, this should allow users to load their own extensions
140-
// in future.
141-
val enableResult = sqlite3_enable_load_extension(ptr, 1)
142-
if (enableResult != SqliteErrorType.SQLITE_OK.code) {
143-
throw PowerSyncException(
144-
"Could not dynamically load the PowerSync SQLite core extension",
145-
cause =
146-
Exception(
147-
"Call to sqlite3_enable_load_extension failed",
148-
),
149-
)
150-
}
151-
152-
// A place to store a potential error message response
153-
val errMsg = nativeHeap.alloc<CPointerVar<ByteVar>>()
154-
val result =
155-
sqlite3_load_extension(ptr, extensionPath, "sqlite3_powersync_init", errMsg.ptr)
156-
if (result != SqliteErrorType.SQLITE_OK.code) {
157-
val errorMessage = errMsg.value?.toKString() ?: "Unknown error"
158-
throw PowerSyncException(
159-
"Could not load the PowerSync SQLite core extension",
160-
cause =
161-
Exception(
162-
"Calling sqlite3_load_extension failed with error: $errorMessage",
163-
),
164-
)
165-
}
137+
connection.loadPowerSyncSqliteCoreExtension()
166138

139+
val ptr = connection.getDbPointer().getPointer(MemScope())
167140
val driverRef = StableRef.create(driver)
168141

169142
sqlite3_update_hook(
@@ -221,3 +194,41 @@ public actual class DatabaseDriverFactory {
221194
}
222195
}
223196
}
197+
198+
internal fun DatabaseConnection.loadPowerSyncSqliteCoreExtensionDynamically() {
199+
val ptr = getDbPointer().getPointer(MemScope())
200+
val extensionPath = powerSyncExtensionPath
201+
202+
// Enable extension loading
203+
// We don't disable this after the fact, this should allow users to load their own extensions
204+
// in future.
205+
val enableResult = sqlite3_enable_load_extension(ptr, 1)
206+
if (enableResult != SqliteErrorType.SQLITE_OK.code) {
207+
throw PowerSyncException(
208+
"Could not dynamically load the PowerSync SQLite core extension",
209+
cause =
210+
Exception(
211+
"Call to sqlite3_enable_load_extension failed",
212+
),
213+
)
214+
}
215+
216+
// A place to store a potential error message response
217+
val errMsg = nativeHeap.alloc<CPointerVar<ByteVar>>()
218+
val result =
219+
sqlite3_load_extension(ptr, extensionPath, "sqlite3_powersync_init", errMsg.ptr)
220+
val resultingError = errMsg.value
221+
nativeHeap.free(errMsg)
222+
if (result != SqliteErrorType.SQLITE_OK.code) {
223+
val errorMessage = resultingError?.toKString() ?: "Unknown error"
224+
throw PowerSyncException(
225+
"Could not load the PowerSync SQLite core extension",
226+
cause =
227+
Exception(
228+
"Calling sqlite3_load_extension failed with error: $errorMessage",
229+
),
230+
)
231+
}
232+
}
233+
234+
internal expect fun DatabaseConnection.loadPowerSyncSqliteCoreExtension()
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package com.powersync
22

3+
import kotlin.experimental.ExperimentalNativeApi
34
import kotlin.test.Test
45

56
class DatabaseDriverFactoryTest {
7+
@OptIn(ExperimentalNativeApi::class)
68
@Test
79
fun findsPowerSyncFramework() {
8-
DatabaseDriverFactory.powerSyncExtensionPath
10+
if (Platform.osFamily != OsFamily.WATCHOS) {
11+
// On watchOS targets, there's no special extension path because we expect to link the
12+
// PowerSync extension statically due to platform restrictions.
13+
DatabaseDriverFactory.powerSyncExtensionPath
14+
}
915
}
1016
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.powersync
2+
3+
import co.touchlab.sqliter.DatabaseConnection
4+
5+
internal actual fun DatabaseConnection.loadPowerSyncSqliteCoreExtension() {
6+
loadPowerSyncSqliteCoreExtensionDynamically()
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.powersync
2+
3+
import co.touchlab.sqliter.DatabaseConnection
4+
5+
internal actual fun DatabaseConnection.loadPowerSyncSqliteCoreExtension() {
6+
loadPowerSyncSqliteCoreExtensionDynamically()
7+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.powersync
2+
3+
import co.touchlab.sqliter.DatabaseConnection
4+
import com.powersync.static.powersync_init_static
5+
6+
internal actual fun DatabaseConnection.loadPowerSyncSqliteCoreExtension() {
7+
val rc = powersync_init_static()
8+
if (rc != 0) {
9+
throw PowerSyncException(
10+
"Could not load the PowerSync SQLite core extension",
11+
cause =
12+
Exception(
13+
"Calling powersync_init_static returned result code $rc",
14+
),
15+
)
16+
}
17+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int powersync_init_static();

0 commit comments

Comments
 (0)