1- import co.touchlab.faktory.KmmBridgeExtension
2- import co.touchlab.faktory.artifactmanager.ArtifactManager
3- import co.touchlab.faktory.capitalized
41import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
5- import java.security.MessageDigest
2+ import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
63
74plugins {
85 alias(libs.plugins.kotlinMultiplatform)
9- alias(libs.plugins.kmmbridge)
106 alias(libs.plugins.skie)
11- alias(libs.plugins.mavenPublishPlugin)
127 alias(libs.plugins.kotlinter)
13- id(" com.powersync.plugins.sonatype" )
148}
159
1610kotlin {
11+ val xcf = XCFramework ()
12+
1713 listOf (
1814 iosX64(),
1915 iosArm64(),
@@ -22,8 +18,14 @@ kotlin {
2218 macosX64(),
2319 ).forEach {
2420 it.binaries.framework {
21+ baseName = " PowerSyncKotlin"
22+ xcf.add(this )
23+
2524 export(project(" :core" ))
2625 isStatic = true
26+
27+ binaryOption(" bundleId" , " PowerSyncKotlin" )
28+ binaryOption(" bundleVersion" , project.version.toString())
2729 }
2830 }
2931
@@ -64,180 +66,22 @@ configurations.all {
6466 }
6567}
6668
67- kmmbridge {
68- artifactManager.set(SonatypePortalPublishArtifactManager (project, repositoryName = null ))
69- artifactManager.finalizeValue()
70- spm()
71- }
72-
73- // We need this so that when a user includes the package in XCode they are able to
74- // import the package using Github
75- if (System .getenv().containsKey(" CI" )) {
76- // Setup github publishing based on GitHub action variables
77- addGithubPackagesRepository()
78- }
79-
80- // This is required for KMMBridge zip to be uploaded to Sonatype (Maven Central)
81- // Since this will only ever be used in this build file it does not make sense to make a
82- // plugin to use this.
83- class SonatypePortalPublishArtifactManager (
84- val project : Project ,
85- private val publicationName : String = " KMMBridgeFramework" ,
86- artifactSuffix : String = " kmmbridge" ,
87- private val repositoryName : String?
88- ) : ArtifactManager {
89- private val group: String = project.group.toString().replace(" ." , " /" )
90- private val kmmbridgeArtifactId =
91- " ${project.name} -$artifactSuffix "
92- private val zipName = " powersync-$artifactSuffix "
93- private val LIBRARY_VERSION : String by project
94-
95- // This is the URL that will be added to Package.swift in Github package so that
96- // KMMBridge is downloaded when a user includes the package in XCode
97- private val MAVEN_CENTRAL_PACKAGE_ZIP_URL = " https://repo1.maven.org/maven2/com/powersync/${zipName} /${LIBRARY_VERSION } /${zipName} -${LIBRARY_VERSION } .zip"
98-
99- override fun deployArtifact (
100- project : Project ,
101- zipFilePath : File ,
102- version : String
103- ): String = MAVEN_CENTRAL_PACKAGE_ZIP_URL
104-
105- override fun configure (
106- project : Project ,
107- version : String ,
108- uploadTask : TaskProvider <Task >,
109- kmmPublishTask : TaskProvider <Task >
110- ) {
111- val zipXCFramework = project.tasks.named<Zip >(" zipXCFramework" )
112- zipXCFramework.configure {
113- // KMMBridge uses the Gradle Zip tasks to create XCFramework archives, but Gradle
114- // doesn't support symlinks. XCFrameworks for macOS need to use symlinks though, so we
115- // patch the task to generate zip files properly.
116- doLast {
117- val bridge = project.extensions.getByName<KmmBridgeExtension >(" kmmbridge" )
118- val source = project.layout.buildDirectory.map { it.dir(" XCFrameworks/${bridge.buildType.get().name} " ) }.get().asFile
119-
120- val out = archiveFile.get().asFile
121- out .delete()
69+ listOf (" Debug" , " Release" ).forEach { buildType ->
70+ tasks.register<Exec >(" build$buildType " ) {
71+ group = " build"
72+ description = " Create an XCFramework archive for $buildType "
12273
123- providers.exec {
124- executable = " zip"
125- args(" -r" , " --symlinks" , out .absolutePath, " PowerSyncKotlin.xcframework" )
126- workingDir(source)
127- }.result.get().assertNormalExitValue()
128- }
129- }
130-
131- project.extensions.getByType<PublishingExtension >().publications.create(
132- publicationName,
133- MavenPublication ::class .java,
134- ) {
135- this .version = version
136- val archiveProvider = zipXCFramework.flatMap {
137- it.archiveFile
138- }
139- artifact(archiveProvider) {
140- extension = " zip"
141- }
142- artifactId = kmmbridgeArtifactId
143- }
144-
145- // Register the task
146- project.tasks.register<UpdatePackageSwiftChecksumTask >(" updatePackageSwiftChecksum" ) {
147- artifactId.set(kmmbridgeArtifactId)
148- zipUrl.set(MAVEN_CENTRAL_PACKAGE_ZIP_URL )
149- dependsOn(" updatePackageSwift" )
150- }
151-
152- // Make sure this task runs after updatePackageSwift
153- project.tasks.named(" kmmBridgePublish" ) {
154- dependsOn(" updatePackageSwiftChecksum" )
155- }
74+ val originalFramework = tasks.getByName(" assemblePowerSyncKotlin${buildType} XCFramework" )
75+ dependsOn(originalFramework)
15676
157- publishingTasks().forEach {
158- uploadTask.configure {
159- dependsOn(it)
160- }
161- }
162- try {
163- project.tasks.named(" publish" ).also { task ->
164- task.configure {
165- dependsOn(kmmPublishTask)
166- }
167- }
168- } catch (_: UnknownTaskException ) {
169- project.logger.warn(" Gradle publish task not found" )
170- }
171- }
172-
173- private fun publishingTasks (): List <TaskProvider <Task >> {
174- val publishingExtension = project.extensions.getByType<PublishingExtension >()
175-
176- // Either the user has supplied a correct name, or we use the default. If neither is found, fail.
177- val publicationNameCap =
178- publishingExtension.publications
179- .getByName(
180- publicationName,
181- ).name
182- .capitalized()
183-
184- return publishingExtension.repositories
185- .filterIsInstance<MavenArtifactRepository >()
186- .map { repo ->
187- val repositoryName = repo.name.capitalized()
188- val publishTaskName =
189- " publish${publicationNameCap} PublicationTo${repositoryName} Repository"
190- // Verify that the "publish" task exists before collecting
191- project.tasks.named(publishTaskName)
192- }
193- }
194- }
195-
196- // This task is used to update Package.swift with the checksum of the zip file
197- // located on maven central.
198- abstract class UpdatePackageSwiftChecksumTask : DefaultTask () {
199- @get:Input
200- abstract val artifactId: Property <String >
201-
202- @get:Input
203- abstract val zipUrl: Property <String >
204-
205- @TaskAction
206- fun updateChecksum () {
207- val LIBRARY_VERSION : String by project
208-
209- val zipFile = project.file(" ${project.layout.buildDirectory.get()} /tmp/${artifactId.get().lowercase()} -$LIBRARY_VERSION .zip" )
210-
211- // Download the zip file
212- zipFile.parentFile.mkdirs()
213- project.uri(zipUrl.get()).toURL().openStream().use { input ->
214- zipFile.outputStream().use { output ->
215- input.copyTo(output)
216- }
217- }
218-
219- // Compute the checksum
220- val checksum =
221- zipFile.inputStream().use { input ->
222- val digest = MessageDigest .getInstance(" SHA-256" )
223- val buffer = ByteArray (8192 )
224- var bytes = input.read(buffer)
225- while (bytes >= 0 ) {
226- digest.update(buffer, 0 , bytes)
227- bytes = input.read(buffer)
228- }
229- digest.digest().joinToString(" " ) { " %02x" .format(it) }
230- }
77+ val source = project.layout.buildDirectory.map { it.dir(" XCFrameworks/${buildType.lowercase()} " ) }.get().asFile
78+ val archiveFile = project.layout.buildDirectory.map { it.file(" FrameworkArchives/PowersyncKotlin$buildType .zip" ) }.get().asFile
23179
232- // Update Package.swift
233- val packageSwiftFile = project.rootProject.file(" Package.swift" )
234- val updatedContent =
235- packageSwiftFile.readText().replace(
236- Regex (" let remoteKotlinChecksum = \" [a-f0-9]+\" " ),
237- " let remoteKotlinChecksum = \" $checksum \" " ,
238- )
239- packageSwiftFile.writeText(updatedContent)
80+ archiveFile.parentFile.mkdirs()
81+ archiveFile.delete()
24082
241- println (" Updated Package.swift with new checksum: $checksum " )
83+ executable = " zip"
84+ args(" -r" , " --symlinks" , archiveFile.absolutePath, " PowerSyncKotlin.xcframework" )
85+ workingDir(source)
24286 }
24387}
0 commit comments