Skip to content

This repository will contain instructors how you could start your first compose mutltiplatform project

License

Notifications You must be signed in to change notification settings

qamarelsafadi/ComposeMultiplatform

Repository files navigation

Logo

Compose Multiplatform

Compose

Screen.Recording.2023-05-07.at.9.51.32.PM.mov

Multiplatform simplifies and accelerates UI and share it between Android, IOS, Desktop and Web.


Repositroy

This repository will contain instructions to start your first Compose Multiplatform Project.

Plugin

Install KMM plugin in Android Studio

Instructions

  • Create a new KMM project using the plugin above

Screenshot 2023-02-25 at 6 58 46 PM Screenshot 2023-05-08 at 9 17 35 PM

Setup Compose for KMM

in your settings.gradle file add the following dependency

pluginManagement {
    repositories {
        google()
        gradlePluginPortal()
        mavenCentral()
        maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") // this one
    }
    
   plugins {
        kotlin("jvm").version("1.8.21")
        kotlin("multiplatform").version("1.8.21")
        kotlin("android").version("1.8.21")
        id("com.android.application").version("7.4.2")
        id("com.android.library").version("7.4.2")
        id("org.jetbrains.compose").version("1.4.3")
    }
}

in your build.gradle.kts add compose plugin

plugins {
    //trick: for the same plugin versions in all sub-modules
    id("com.android.application").version("8.2.0-alpha06").apply(false)
    id("com.android.library").version("8.2.0-alpha06").apply(false)
    kotlin("android").version("1.8.21").apply(false)
    kotlin("multiplatform").version("1.8.21").apply(false)
}


now inside shared module build.gradle.kts add these two plugins

plugins {
    kotlin("multiplatform")
    id("com.android.library")
    kotlin("native.cocoapods") // this 
    id("org.jetbrains.compose") // and this
}

in your kotlin block add the following lines

  iosX64()
  iosArm64()
  iosSimulatorArm64()
  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
        }
        extraSpecAttributes["resources"] = "['src/commonMain/resources/**', 'src/iosMain/resources/**']" // this is for images 
    }
    
    // in android block add these lines to support common resources
    
    sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
    sourceSets["main"].res.srcDirs("src/androidMain/res")
    sourceSets["main"].resources.srcDirs("src/commonMain/resources")
    

now BEFORE you sync you need to make sure about the following:

  • Install cocoapods
brew install cocoapods

  • cd to iosApp and init pod
 pod init
  • install your pods
pod install

In sourceSets

    sourceSets {
        val commonMain by getting {
           dependencies {
                implementation(compose.runtime)
                implementation(compose.foundation)
                implementation(compose.material)
                @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
                implementation(compose.components.resources)
            }
        }
       val androidMain by getting {
            dependencies {
                api("androidx.activity:activity-compose:1.6.1")
                api("androidx.appcompat:appcompat:1.6.1")
                api("androidx.core:core-ktx:1.9.0")
            }
        }
        val iosX64Main by getting
        val iosArm64Main by getting
        val iosSimulatorArm64Main by getting
        val iosMain by getting {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            iosSimulatorArm64Main.dependsOn(this)
        }
    }

and to avoid Compose targets '[uikit]' are experimental and may have bugs! Error add this in gradle.properties

org.jetbrains.compose.experimental.uikit.enabled=true

Sync now !

Let the magic begin

Inside your shared module commonMain directory create your first Composable function to use it for Android and IOS

@Composable
internal fun App(){
    Text(Greeting().greet())
}

In your AndroidMain make main.android class to use your App function

@Composable
fun Application(){
    App()
}

In your IosMain make main.ios class to use your App function

import androidx.compose.ui.window.ComposeUIViewController

fun MainViewController() = ComposeUIViewController { App() }

Now go to AndoroidApp module to use the function we made in main.android class

     Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    Application()
                }

Next go to IosApp module to use the function we made in main.ios class

import shared // this important to import don't forget it! 

@main
struct iOSApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
     }
  }
  
 // inside your ContentView class  
 
import SwiftUI
import shared

struct ComposeView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
        Main_iosKt.MainViewController()
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

struct ContentView: View {
    var body: some View {
        ComposeView()
                .ignoresSafeArea(.keyboard) // Compose has own keyboard handler
    }
}

Run

Add this to solve dependencies conflicts in gradle.properties

kotlin.native.cacheKind=none

now you can run your android normally, for IOS you need to run the following command first

 ./gradlew build
 ./gradlew :shared:linkPodDebugFrameworkIosSimulatorArm64

Now open iosApp.xcworkspace inside xcode and run the app! or Run it inside Android Studio itself

Resources

JetBrains Compose

Compose Mutliplatofrom Examples

Compose Mutliplatofrom Template



Happy Kotlin 🚀!