diff --git a/.github/workflows/publish-on-maven.yml b/.github/workflows/publish-on-maven.yml index 171df21..ed93b4e 100644 --- a/.github/workflows/publish-on-maven.yml +++ b/.github/workflows/publish-on-maven.yml @@ -30,11 +30,29 @@ jobs: publish: needs: build-natives - runs-on: ubuntu-latest + # MUST stay on macOS: iosArm64 / iosSimulatorArm64 are disabled on any other + # host, and Kotlin then writes the root module metadata with Gradle-default + # coordinates for them (`composewebview:webview-compose-iosarm64:unspecified`), + # which makes the release unresolvable for iOS consumers (issue #51). + # :webview-compose:verifyPublicationCoordinates guards against a regression. + runs-on: macos-15 steps: - name: Checkout code uses: actions/checkout@v4 + - name: Select Xcode 26+ (Compose 1.11 needs iOS 26 SDK) + run: | + # Same selection as the iOS jobs in pr-build-check.yml. + XCODE=$(ls -d /Applications/Xcode_26*.app 2>/dev/null | sort -V | tail -1 || true) + if [ -z "$XCODE" ]; then + XCODE=$(ls -d /Applications/Xcode_16*.app 2>/dev/null | sort -V | tail -1 || true) + fi + if [ -n "$XCODE" ]; then + echo "Using $XCODE" + sudo xcode-select -s "$XCODE" + fi + xcodebuild -version + - name: Download native artifacts uses: actions/download-artifact@v4 with: diff --git a/webview-compose/build.gradle.kts b/webview-compose/build.gradle.kts index a203ec5..933251e 100644 --- a/webview-compose/build.gradle.kts +++ b/webview-compose/build.gradle.kts @@ -1,6 +1,7 @@ @file:OptIn(ExperimentalWasmDsl::class) import com.vanniktech.maven.publish.KotlinMultiplatform +import groovy.json.JsonSlurper import org.apache.tools.ant.taskdefs.condition.Os import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl @@ -208,3 +209,55 @@ mavenPublishing { description.set("Compose Multiplatform WebView library for Desktop, Android and iOS") } } + +// The root KMP module metadata redirects every target variant to a sibling module +// through an `available-at` entry. Targets that are disabled on the publishing host +// (Apple targets anywhere but macOS) keep Gradle's default project coordinates, so +// the release ships pointing at `composewebview:webview-compose-iosarm64:unspecified` +// and no iOS consumer can resolve it (issue #51). Fail the publish instead. +val verifyPublicationCoordinates by tasks.registering { + description = "Checks that the KMP root module metadata only points at modules being published" + group = "verification" + + val metadataFile = tasks.named( + "generateMetadataFileForKotlinMultiplatformPublication" + ).flatMap { it.outputFile } + + inputs.file(metadataFile) + + doLast { + @Suppress("UNCHECKED_CAST") + val root = JsonSlurper().parse(metadataFile.get().asFile) as Map + + @Suppress("UNCHECKED_CAST") + val component = root["component"] as Map + val group = component["group"] + val version = component["version"] + + @Suppress("UNCHECKED_CAST") + val variants = root["variants"] as? List> ?: emptyList() + val dangling = variants.mapNotNull { variant -> + @Suppress("UNCHECKED_CAST") + val at = variant["available-at"] as? Map ?: return@mapNotNull null + if (at["group"] == group && at["version"] == version) return@mapNotNull null + "${variant["name"]} -> ${at["group"]}:${at["module"]}:${at["version"]}" + } + + check(dangling.isEmpty()) { + buildString { + appendLine("Root module metadata points at modules outside this publication:") + dangling.forEach { appendLine(" $it") } + appendLine("Expected $group:*:$version.") + append( + "Publish from a host that can build every declared target " + + "(macOS is required for the iOS targets)." + ) + } + } + logger.lifecycle("Publication coordinates OK: ${variants.size} variants under $group:*:$version") + } +} + +tasks.withType().configureEach { + dependsOn(verifyPublicationCoordinates) +}