Hi <@UHAJKUSTU> I have one query, i setup the deco...
# decompose
s
Hi @Arkadii Ivanov I have one query, i setup the decompose experimental in my project, and its working fine now for for android, desktop, and web. But while setting up for iOS, i am doping it like this in iosMain module of kmm module. Just wanted to confirm if its fine or i am missing anything as i didnt found any sample for ios.
Copy code
val lifecycle = LifecycleRegistry()
        val rootComponentContext = DefaultComponentContext(lifecycle = lifecycle)
        val root = DefaultRootComponent(
            componentContext = rootComponentContext
        )

        MaterialTheme {
            Surface(
                modifier = Modifier
                    .fillMaxSize()
            ) {
                RootContent(component = root)
            }
        }
Its running successfully on ios as well, but just wanted to confirm if everything is setup correctly like life cycle and component context.
I have question related to this point that should i do this from ios xcode project as mentioned here: https://arkivanov.github.io/Decompose/getting-started/quick-start/#ios-with-swiftui Or is it fine from kmm isoMain module directly. I can see there(in swiftui) we are creating and destroying it manually. How it will handle that directly in compose (in iosMain module of kmm)?
a
It seems you are doing it correctly. This should be done in the integration point. In your case with Compose for iOS, it's in iosMain. So it looks good. Don't forget to also drive the lifecycle correctly. Here is one of the ways of doing it: https://github.com/arkivanov/Decompose/blob/compose-experimental/sample/app-darwin-compose/src/uikitMain/kotlin/com/arkivanov/sample/app/Main.kt
s
That will also go in same iosMain module of compose and it will connect it with ios application lifecycle, right?
a
Should be, yes
But if your integration point is in Swift, then it might be better to do that also in Swift. Somewhere here: https://github.com/JetBrains/compose-multiplatform/blob/master/examples/imageviewer/iosApp/iosApp/iOSApp.swift
s
Ok got it, but in my case entry point is in compose, so it will be fine to do that in iosMain. If we use swift ui from kmm app, then its desired to do that in swift file as in decompose's official todo app example in compose multiplatform examples, right?
a
Yes. My point was that it's also possible to integrate Compose from Swift, in which case it might be better to instance the root component and control the lifecycle in Swift.
s
Ok got it.🙌 thanku for detailed explanation. To be honest, i would specially thank u and say that your Support for decompose is great.
a
Thanks for the feedback! I appreciate that.
s
Hi @Arkadii Ivanov i have one query here, regarding setting lifecycle with ios properly. SO you recommended to use this sample: https://github.com/arkivanov/Decompose/blob/compose-experimental/sample/app-darwin-compose/src/uikitMain/kotlin/com/arkivanov/sample/app/Main.kt But how i will use it inside iosApp.swift in xcode ios project. Currrently i m using it like this in iosApp.swift file :
Copy code
@main
struct iOSApp: App {
	var body: some Scene {
		WindowGroup {
			GeometryReader { geo in
                ComposeViewControllerToSwiftUI(
                    topSafeArea: Float(<http://geo.safeAreaInsets.top|geo.safeAreaInsets.top>),
                    bottomSafeArea: Float(geo.safeAreaInsets.bottom)
                )
                .ignoresSafeArea()
            }
		}
	}
}

struct ComposeViewControllerToSwiftUI: UIViewControllerRepresentable {
    private let topSafeArea: Float
    private let bottomSafeArea: Float

    init(topSafeArea: Float, bottomSafeArea: Float) {
        self.topSafeArea = topSafeArea
        self.bottomSafeArea = bottomSafeArea
    }

    func makeUIViewController(context: Context) -> UIViewController {
        return Main_iosKt.MainViewController(
            topSafeArea: topSafeArea,
            bottomSafeArea: bottomSafeArea
        )
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
    }
}
Calling the Main_iosKt.MainViewController in makeUIViewController. ANd this MainViewController is my entry point in isoMain module of kmm
Copy code
@OptIn(ExperimentalDecomposeApi::class)
fun MainViewController(
    topSafeArea: Float,
    bottomSafeArea: Float
): UIViewController {
    return ComposeUIViewController {
        val density = LocalDensity.current

        val topSafeAreaDp = with(density) { topSafeArea.toDp() }
        val bottomSafeAreaDp = with(density) { bottomSafeArea.toDp() }
        val safeArea = PaddingValues(top = topSafeAreaDp + 32.dp/*, bottom = bottomSafeAreaDp*/)


        val lifecycle = LifecycleRegistry()
        val rootComponentContext = DefaultComponentContext(lifecycle = lifecycle)
        val root = RootComponentImpl(
            componentContext = rootComponentContext
        )

        MaterialTheme {
            Surface(
                modifier = Modifier
                    .fillMaxSize()
                //.padding(safeArea),
            ) {
                RootContent(component = root)
            }
        }

    }
}
But according to your recommendation, how i will integrate that main() method from your sample in xcode ios project :
Copy code
fun main() {
    val args = emptyArray<String>()
    memScoped {
        val argc = args.size + 1
        val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues()
        autoreleasepool {
            UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate))
        }
    }
}
this one?
a
Yeah, if you need to integrate on the Swift side, you can check the example: https://github.com/arkivanov/Decompose/blob/master/sample/app-ios/app-ios/app_iosApp.swift Notice, that if you don't need the state preservation (StateKeeper), you can omit that code. Just use DefaultComponentContext(lifecycle) constructor.
s
And for that i need to export decompose to ios as well, right?
a
Correct
And Essenty lifecycle
s
But i am getting following issue while using export in cocoapods:
Copy code
e: /Users/sunil/AndroidStudioProjects/ComposeInstagramCloneMultiplatform/shared/build.gradle.kts:3:27: Symbol is declared in module 'jdk.management.agent' which does not export package 'jdk.internal.agent'
I think its using wrong export method here, its importing this line :
Copy code
import jdk.internal.agent.ConnectorAddressLink.export
this is my code in cocoapods:
Copy code
cocoapods {
    version = "1.0.0"
    summary = "Some description for the Shared Module"
    homepage = "Link to the Shared Module homepage"
    ios.deploymentTarget = "14.1"
    podfile = project.file("../iosApp/Podfile")
    framework {
        baseName = "shared"
        isStatic = true
    }

    export("com.arkivanov.decompose:decompose:$decomposeVersion")

    extraSpecAttributes["resources"] =
        "['src/commonMain/resources/**', 'src/iosMain/resources/**']"
}
a
First time I see this error. Most likely you are using incorrect import.
s
Yeah, but its not showing other imports suggestions, only single suggestion its showing, and that is the wrong one
a
Maybe try asking in #multiplatform channel? This doesn't look related to Decompose. 😀
s
ok
HI that issue is resolved, But now i m facing this issue
Copy code
Execution failed for task ':shared:linkPodDebugFrameworkIosSimulatorArm64'.
> Following dependencies exported in the podDebugFramework binary are not specified as API-dependencies of a corresponding source set:
  
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.decompose/decompose-iossimulatorarm64/2.0.0-compose-experimental-beta-01/3cafd07f2ad9c583e3c9efb805c24423c1a13ab6/decompose.klib]
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.essenty/lifecycle-iossimulatorarm64/1.1.0/c46194db2fd5b49be2f33029c1b7eeedab253b29/lifecycle.klib]
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.essenty/utils-internal-iossimulatorarm64/1.1.0/1a1d5d21a37edf5489c833c9945d88a32adaef6d/utils-internal.klib]
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.essenty/state-keeper-iossimulatorarm64/1.1.0/69d9828e944fc495433edb9537004902c2ba237c/state-keeper.klib]
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.essenty/parcelable-iossimulatorarm64/1.1.0/ef6aef00d416366a8a6aa9492daf9cefa7c0e1f8/parcelable.klib]
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.parcelize.darwin/runtime-iossimulatorarm64/0.1.4/46055c4c6ffbf1a823d3f4d0335aa9bf7db57c78/runtime.klib]
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.essenty/instance-keeper-iossimulatorarm64/1.1.0/412479888f1c5b0b8b4e16ffd1125bc700fb8208/instance-keeper.klib]
  Files: [/Users/sunil/.gradle/caches/modules-2/files-2.1/com.arkivanov.essenty/back-handler-iossimulatorarm64/1.1.0/83e021cb2ccc1fbbf23e79239f0d67ea814859c9/back-handler.klib]
  
  Please add them in the API-dependencies and rerun the build.
SO which dependencies i need to export, currently i m exporting only decompose?
a
Try exporting
decompose
and
lifecycle
for now, and don't forget to specify those dependencies as
api
.
s
where we need to specify as api?
in the iosMain
source set
Its like this:
Copy code
val iosMain by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            iosSimulatorArm64Main.dependsOn(this)

            dependencies {
                api("com.arkivanov.decompose:decompose:$decomposeVersion")
                api("com.arkivanov.essenty:lifecycle:$essentyVersion")
                implementation("com.arkivanov.decompose:extensions-compose-jetbrains:$decomposeVersion")
            }

        }
it worked
a
Yep, this looks correct
s
Thanx its done. printed logs and Verfieid as well, callbacks are in alignment with UIApplication lifecycle.
a
Yay! Glad it worked for you!
s
haha, thanx all credit to you for helping out🙌
110 Views