From 354b57ef3a6ddee4cf03c7df828cbba482825aa0 Mon Sep 17 00:00:00 2001 From: Dominik Dias Date: Thu, 3 Sep 2026 11:02:44 +0200 Subject: [PATCH 1/3] build(ios): link Firebase through a remote Swift package Kotlin's SwiftPM import resolved the FirebaseMessaging dependency that kmpnotifier-push-firebase declares by generating a Swift package under iosApp/KotlinMultiplatformLinkedPackage and wiring it into the Xcode project. Xcode resolves package references before it runs any build phase, and no Gradle sync generates that package, so it would have to be committed. Its subpackage directory names embed dependency versions, so every bump would leave the committed copy stale and fail the build with "Synthetic project regenerated" -- which Renovate cannot fix, since it never checks the branch out. Turn the import off and add firebase-ios-sdk to iosApp.xcodeproj as an ordinary remote Swift package, which is what KMPNotifier's own iOS setup documents. Nothing is generated into the source tree any more: a fresh clone opens and builds directly, and dependency bumps need no regenerated files. --- .gitignore | 6 +- gradle.properties | 8 ++ iosApp/iosApp.xcodeproj/project.pbxproj | 28 ++++ .../xcshareddata/swiftpm/Package.resolved | 123 ++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/.gitignore b/.gitignore index 1ff18864..1649ddce 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,8 @@ kotzilla.json androidApp/keystore/ # Code-review reports — throwaway artifacts written by the code-review skill -.claude/reviews/ \ No newline at end of file +.claude/reviews/ + +# Local SwiftPM working area (multi-GB) of the Kotlin/Native SPM integration. That integration is +# off via kotlin.disableSwiftPMImport, so this only guards against it reappearing. +.swiftpm-locks/ diff --git a/gradle.properties b/gradle.properties index a6470db1..b6ee9b07 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,3 +23,11 @@ mainClass=de.tabmates.composeapp.MainKt # client-version gate rejects a version that does not exist in the tag stream, and a value # ahead of it also makes the in-app update check believe the build is permanently current. APP_VERSION=1.0.0 + +# The Kotlin/Native SwiftPM import would resolve the iOS dependencies our Kotlin libraries declare +# (currently FirebaseMessaging, via kmpnotifier-push-firebase) by generating a local Swift package +# under iosApp/ and wiring it into the Xcode project. That package is generated from the dependency +# graph but has to exist before Xcode resolves packages, which no Gradle sync does — so it would +# have to be committed and would go stale on every dependency bump. Instead we add those SDKs to +# iosApp.xcodeproj as ordinary remote Swift packages, as KMPNotifier's own iOS setup documents. +kotlin.disableSwiftPMImport=true diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 0413b447..1d20437a 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -6,6 +6,10 @@ objectVersion = 77; objects = { +/* Begin PBXBuildFile section */ + F1B0A2C4D5E6F70819A2B3C4 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = F2C1B3D5E6F7081A2B3C4D5E /* FirebaseMessaging */; }; +/* End PBXBuildFile section */ + /* Begin PBXFileReference section */ D643D6045C11FE74F5CE1290 /* TabMatesApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TabMatesApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -41,6 +45,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F1B0A2C4D5E6F70819A2B3C4 /* FirebaseMessaging in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -85,6 +90,7 @@ ); name = iosApp; packageProductDependencies = ( + F2C1B3D5E6F7081A2B3C4D5E /* FirebaseMessaging */, ); productName = iosApp; productReference = D643D6045C11FE74F5CE1290 /* TabMatesApp.app */; @@ -114,6 +120,9 @@ ); mainGroup = 30782983EBF3997AB1AC52A7; minimizedProjectReferenceProxies = 1; + packageReferences = ( + F3D2C4E6F708192A3B4C5D6E /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + ); preferredProjectObjectVersion = 77; productRefGroup = A812E87C7ABF334E17AF133A /* Products */; projectDirPath = ""; @@ -370,6 +379,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + F3D2C4E6F708192A3B4C5D6E /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 12.14.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + F2C1B3D5E6F7081A2B3C4D5E /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = F3D2C4E6F708192A3B4C5D6E /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 806E4ABFAD122295F42EBAF6 /* Project object */; } diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..8c4c9981 --- /dev/null +++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,123 @@ +{ + "originHash" : "8051a8438965fea6e6201e0b87777290e28716696db9fa37c19b6b0d0fd28df6", + "pins" : [ + { + "identity" : "abseil-cpp-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/abseil-cpp-binary.git", + "state" : { + "revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5", + "version" : "1.2024072200.0" + } + }, + { + "identity" : "app-check", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/app-check.git", + "state" : { + "revision" : "3e33dd27dd4c69bd81c7c81fe61d8ccf58846902", + "version" : "11.3.1" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk.git", + "state" : { + "revision" : "346daa9f46316aa372b35b317e18224acc2e9063", + "version" : "12.18.0" + } + }, + { + "identity" : "google-ads-on-device-conversion-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk", + "state" : { + "revision" : "dc39082d8881109d35b94b1c122164c0e8d08a55", + "version" : "3.6.1" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "f04760d460296cc0fa430935a7be212e5bd67fc5", + "version" : "12.18.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "ba3358d3c3dbae8ef230b58a46b97ad65e84e974", + "version" : "10.1.1" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "92c8f6dc3ac375d6febdfcb3db68bc3d10633db3", + "version" : "8.1.3" + } + }, + { + "identity" : "grpc-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/grpc-binary.git", + "state" : { + "revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6", + "version" : "1.69.1" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "724a52eea6329b7e12d3ad8300d76ca9f3895fcc", + "version" : "5.3.1" + } + }, + { + "identity" : "interop-ios-for-google-sdks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "state" : { + "revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe", + "version" : "101.0.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1", + "version" : "1.22.5" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "3851d94a41890dea16dc3db34caf60e585cb4163", + "version" : "2.30910.1" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "f4a19a3c313dc2616c70bb49d29a799fb16be837", + "version" : "2.4.1" + } + } + ], + "version" : 3 +} From 4b098915a4712c3a2b237a5b5591dfe586dc5386 Mon Sep 17 00:00:00 2001 From: Dominik Dias Date: Thu, 3 Sep 2026 11:03:47 +0200 Subject: [PATCH 2/3] chore(ios): track GoogleService-Info.plist The iOS Firebase config was the only untracked half of the pair -- the Android counterpart, androidApp/google-services.json, has been in the repo since notifications were wired up. Without it the iOS app cannot configure Firebase on a fresh checkout or in CI. --- iosApp/iosApp/GoogleService-Info.plist | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 iosApp/iosApp/GoogleService-Info.plist diff --git a/iosApp/iosApp/GoogleService-Info.plist b/iosApp/iosApp/GoogleService-Info.plist new file mode 100644 index 00000000..32f93842 --- /dev/null +++ b/iosApp/iosApp/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + + API_KEY + AIzaSyDUMMYDUMMYDUMMYDUMMYDUMMYDUMMY000 + GCM_SENDER_ID + 000000000000 + PLIST_VERSION + 1 + BUNDLE_ID + de.tabmates.app.TabMatesApp + PROJECT_ID + tabmates-dummy + STORAGE_BUCKET + tabmates-dummy.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:000000000000:ios:0000000000000000000000 + + From 70a4baa394b3634586d69ae867a0668fbc1f2fd0 Mon Sep 17 00:00:00 2001 From: Dominik Dias Date: Thu, 3 Sep 2026 11:03:47 +0200 Subject: [PATCH 3/3] ci(ios): share the iosApp Xcode scheme The scheme only existed under xcuserdata/, which is gitignored, so it never left the machine that created it and `xcodebuild -scheme iosApp` could not resolve it on a runner or a fresh clone. --- .../xcshareddata/xcschemes/iosApp.xcscheme | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme diff --git a/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme b/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme new file mode 100644 index 00000000..dfb57366 --- /dev/null +++ b/iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +