Can somebody share a build.gradle.kts file for com...
# compose-ios
t
Can somebody share a build.gradle.kts file for composeApp that shows how to update an Android/iOS project generated using the wizard at https://kmp.jetbrains.com/ to allow composeApp to leverage pods within iosMain? I've tried lots of configurations as suggested (https://kotlinlang.org/docs/native-cocoapods.html#update-podfile-for-xcode) , but I keep encountering various errors.
p
I have a project that uses cocoapods but wasn't generated with this wizard. What errors specifically you encountered?
Perhaps the versions of various dependencies mismatch. With KMP is important you pick the right dependency graph. Libraries are young and some don't offer backwards compatibility
t
I need the composeApp module to be able to pull in some pod libraries. The wizard exposes the ComposeApp module by defining a framework for each target.
Copy code
listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "ComposeApp"
            isStatic = true
        }
    }
All of the docs, show that you need to define the cocoapods extension if you want to include pods. I'm struggling to see how they are supposed to be used together. Should the old code be removed and only the cocoapods config block be used?
The wizard template doesn't include a xcworkspace. Will a workspace be required along with defining a Podfile to include the same pod dependencies for the iosApp module? That doesn't seem right, but I can't get it to build.
Of course, the simple template project builds fine, but it doesn't need to include any iOS pod libraries.
p
I see yeah
Back in time it needed the xcworkspace and also, the podfile I remember had to match the project name. To generate those you basically open the project with Xcode and also run the podfile gradle task
Not sure if things had changed, you had to run pod install sometimes for things to work too. I migrated all my stuff to plain frameworks. Just left 1 with cocoapods just in case. But I am not up-to-date with the latest on pods integration
t
I feel that this has been the most confusing part of maintaining a KMP project so far. Things are changing fast with project structure and cocoapods just feels clunky and difficult. I appreciate the advice.
βž• 1
p
I just checked the code integrating pods and podfile isn't needed anymore
πŸ‘ 1
I agree right
t
So you just have the configuration for cocoapods in build.gradle.kts for the shared module, which includes the pods you need?
p
In theory is the best option to integrate 3rd party objective-c libraries but I just prefer doing the other way, interfaces plus expect/actual factory functions plus dependency injection
βž• 2
Actually I am not using any third party πŸ˜“ using pod, I just use the plugin to generate the podframework
Check it here: https://github.com/pablichjenkov/amadeus-hotel-app/blob/main/shared/build.gradle.kts Is the simple case, doesn't work for you
t
I'll check that out. Thank you!
p
One of the reasons I moved to interface+di to integrate swift stuff was precisely cocoapods surprises.
πŸ™‚ 1
Plus pretty much every iOS developer that I know telling me is old and they don't use it πŸ€·πŸ»β€β™‚οΈ
j
Yeah was quite amazed long time KMP enforced cocoapods basically until recent 1.5.0 version. Was old before as well. I think Swift package manager mostly used? I just migrated away from cocoapods myself. Indeed very complex setup new iOS setup. I generated new iOS app by creating new project in Xcode and compared.
πŸ‘ 2
m
I'm currently writing an article about this. I agree, the cocoapods segue by the Jetbrains team was quite surprising. I'm not the biggest fan of using pods as I'm all in on spm, but pods were recommended up till just a few weeks ago. They changed the compose mp template to exclude the pods setup, the KMP wizard doesn't include it too and in the KMP Webinar the other day, the sentiment expressed was that pods are slowly getting deprecated, so no need to go in that direction. Needless to say, I actually agree with this step and would recommend going the interface+expect/actual+di like @Pablichjenkov mentioned.
πŸ‘ 2
t
Please post a link to your article when you finish it. I’d like to read it. Thanks for the advice.
πŸ‘ 3
p
Yes please, shared that
t
Nice article. I liked the style and it had some really good content.
p
Really good! Some feedback: Any reason why in Android
single<NetworkHelper> { AndroidNetworkHelper(androidContext()) }
and in iOS
single<NetworkHelper> { get<IosApplicationComponent>().networkHelper }
why not bellow line in iOS
single<NetworkHelper> { NetworkHelper() }
Just to have the same in both platforms so the reader won't question about this subtle difference.
m
Good question. My intention was to have the
ApplicationComponent
serve as the bridge for platform dependencies. In this case, I'm attempting to provide the
NetworkHelper
by getting it from the
IosApplicationComponent
since the
iosMain
source set is unaware of the
IosNetworkHelper()
class implemented in swift in the
iosApp
target. I also did something similar when passing
userDefaults
from iOS for
MultiplatformSettings
Copy code
single<Settings> { NSUserDefaultsSettings(get<IosApplicationComponent>().userDefaults) }
(
NSUserDefaults
is already part of Kotlin Native so this wasn't entirely necessary
) I understand why it raises eyebrows though, and of course, I'll attempt exploring some other way of passing dependencies to be more consistent.
j
Hungry to see next article using credential manager. Something I struggle with. Hybride interface with iOS Google sign in. Especially the activity result flow. And how do you setup google play services in Applicationcomponent if possible? Especially since in Android applies by Gradle plugin but iOS some odd stuff.
m
One more thing I wanted to point out, For Android, it was originally provided in similar fashion as well
Copy code
single<NetworkHelper> { get<AndroidApplicationComponent>().networkHelper }
However, the new KMP Compose UI template sorta merged the
androidApp
module into the
androidMain
source set and called it
composeApp
, so I simply just traced my steps back and made it all straightforward on the Android side.
βž• 1
Oh yeah, I'm already writing that @Joel Denke The Google Sign Configuration tutorial for iOS is a good source. You can use the Info.plist to set that up. I'm an iOS engineer also, so I'm not sure if that's why it was relatively straightforward for me to implement. I'd like to add that the
CredentialsManager
doesn't explicitly expose the Activity result flow to us, rather, it uses a suspending
credentialManager.getCredential()
function to retrieve the auth details. Under the hood, it launches a
HiddenActivity
which houses the bottom sheet dialog. On iOS, it just launches the usual modal webview and uses:
Copy code
.onOpenURL { url in
    GIDSignIn.sharedInstance.handle(url)
}
In the SwiftUI root scene. Lastly, I'm using a
GoogleAuthProvider
interface which I created, on both platforms to streamline the logic.
Copy code
interface GoogleAuthProvider {
    suspend fun login(
        context: PlatformContext,
        onAuthResult: (GoogleAuthResult) -> Unit,
        onAuthError: (Throwable) -> Unit,
    )

    suspend fun logout()
}
I actually learned loads of new tips while implementing this and I'm eager to share it.
πŸ‘€ 1
j
Yeah I try move this iOS vs Android in expect actual with ObjC interop in iOS for Google sign in. Works fine. But complex rewrite legacy Google sign in in Android into credential manager. Trying to have zero code in iOS and Android app. And Google having insane setup of Google play services wondered if you managed decouple or same problem I do :)
The problem for me want good architecture and decouple and have everything in my KMP code and nothing in iOS and Android apps except from initial setup method creating Koin, applicationcomponent. The iOS part was the easy thing for Google sign in. Issue with credential manager even though I am Android dev. Most problematic is we using Gradle plugins in KMP but I cant apply Google play services plugin into iosMain block 😁 To setup plist file without ugly code in AppDelegate causing race conditions if not call in right order.
Can add my code work now, Google sign in in iOS and Android. But code sucks 😁
m
Ohhh, I understand you now. Are you using Cocoapods?
j
Yes but only for Google Swift sign in
Want to apply Gradle Google play services to fetch plist file in iOS but json file in Android 😁
And dont call from iOS app or Android app at all.
For credential manager google dont provide sample how implement with Google sign in with proper bottomsheet integration. This also curious how you solved 😁
m
I see. That's actually a bit more involved. I like that. Hopefully as KMP matures, we'll have official libraries that automagically handle these things.
For now, it'll be difficult to truly decouple like you want
j
Yeah hoped gitlive firebase doing cloud messaging and play service setup parsing KMP but feels they abandoned that?
πŸ‘† 1
I probably need create my own Google play service KMP plugin 🀣
End goal zero code in app level and 100% code sharing through shared module with large scale app. And using Swift interop and Swift libraries directly in KMP code.
πŸ’― 2
Very close to this now. Almost nothing in app level. Trying avoid the pattern of application component inject iOS and Android SDK things, rather reverse direction :)
Given that I can use nice kotlin libs for iOS to use Swift SDK 😁
And ofc same for web and desktop. Hence want to decouple everything to avoid fragmentation of expect app level satisfy dependency tree backwards.
Hmm want to write articles about this topic as very complex 😁
πŸ”₯ 1
If can want to not using Google play services at all but Google forcing us 😘 Want agnostic firebase integration without play services. Decrypt project setup with kotlin dsl instead of json file or plist file. Huawei semi solved this but they do not offer agnostic service for Cloud messaging with iOS 😁
Basic Google login with OAuth should be simple. Especially with passkeys and credentials manager. But notifications next level madness get KMP. It works now for me but it aint pretty
p
I gotcha now, yes I completely missed that, you are correct, iOSMain has no knowledge of swift side declared classes. I would prefer using the
AndroidApplicationComponent(). networkHelper
just to be symmetric o both platforms but just personal preference. Looking forward to that second part πŸ’―πŸ”₯πŸŽ‰