Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,18 @@ As part of your evaluation, you'll need to decide if you're going to integrate K

### Android

The Android side is somewhat more straightforward. Kotlin is the preferred language for Android, and the library can be integrated as just another module library. We'll be updating soon with a general Android integration doc. In the meantime, the simplest method would be to copy the shared module into your standard Android build, and use the `app` module as a reference for dependency resolution.
The Android side is somewhat more straightforward. Kotlin is the preferred language for Android, and the library can be integrated as just another module library.
The main benefit of the :shared module is that it holds all the functionality needed to download, persist and display application's UI.
This is accomplished by it using
- Ktor - https://ktor.io/ as a Kotlin only library for handling downloads
- SQLDelight - https://cashapp.github.io/sqldelight/ as a Kotlin only library for persisting data
- Compose Multiplatform https://blog.jetbrains.com/kotlin/2023/05/compose-multiplatform-for-ios-is-in-alpha/ which is powered by Skia to allow displaying the same UI written in Jetpack Compose on multiple platforms.

### iOS

The iOS integration process is relatively new and has been iterating fast. Be prepared to spend more time with config related issues when integrating with a production build.
The iOS side is very similar to the Android one by leveraging the same technologies through :shared showcasing the major advantage of a Compose Multiplatform project - run once and run everywhere.

You can integrate with Cocoapods, or by directly including the Xcode framework. If you are an Android developer without extensive iOS build experience, be aware that this is a risky option. Production build systems, for any ecosystem, tend to be complex. You'll almost certainly need to recruit somebody with experience maintaining your iOS build.

See [IOS_PROJ_INTEGRATION.md](docs/IOS_PROJ_INTEGRATION.md) for iOS integration information.
See [IOS_PROJ_INTEGRATION.md](docs/IOS_PROJ_INTEGRATION.md) for how iOS is consuming :shared through a Podfile.

If you are attempting to integrate your KMP project with a production iOS application, please let us know what issues you run into and reach out with questions if stuck. This is an ongoing area of improvement for the KMP platform and we'd like to help make this as smooth as possible.

Expand Down
8 changes: 8 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id("com.android.application")
id("org.jetbrains.compose")
kotlin("android")
}

Expand Down Expand Up @@ -39,6 +40,13 @@ android {
}
}

// Using Compose gradle plugin v 1.4.1 which supports at most Kotlin 1.8.1
// And SQLDelight 2.0+ which supports at least Kotlin 1.8.2
// Quick workaround until we get some easier to match versions.
compose {
kotlinCompilerPlugin.set("org.jetbrains.compose.compiler:compiler:1.4.8")
}

dependencies {
implementation(project(":shared"))
implementation(libs.bundles.app.ui)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package co.touchlab.kampkit.android
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import co.touchlab.kampkit.android.ui.MainScreen
import co.touchlab.kampkit.android.ui.theme.KaMPKitTheme
import androidx.compose.foundation.isSystemInDarkTheme
import co.touchlab.kampkit.ui.MainScreen
import co.touchlab.kampkit.ui.theme.KaMPKitTheme
import co.touchlab.kampkit.injectLogger
import co.touchlab.kampkit.models.BreedViewModel
import co.touchlab.kermit.Logger
Expand All @@ -19,7 +20,7 @@ class MainActivity : ComponentActivity(), KoinComponent {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
KaMPKitTheme {
KaMPKitTheme(isSystemInDarkTheme(), true) {
MainScreen(viewModel, log)
}
}
Expand Down
47 changes: 0 additions & 47 deletions app/src/main/kotlin/co/touchlab/kampkit/android/ui/theme/Theme.kt

This file was deleted.

9 changes: 0 additions & 9 deletions app/src/main/res/drawable/ic_favorite_24px.xml

This file was deleted.

9 changes: 0 additions & 9 deletions app/src/main/res/drawable/ic_favorite_border_24px.xml

This file was deleted.

4 changes: 4 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
plugins {
alias(libs.plugins.gradleVersions)
alias(libs.plugins.ktlint) apply false
alias(libs.plugins.moko.resources) apply false

kotlin("multiplatform") version libs.versions.kotlin.get() apply false
kotlin("plugin.serialization") version libs.versions.kotlin.get() apply false
id("app.cash.sqldelight") version libs.versions.sqlDelight.get() apply false
id("com.android.library") version libs.versions.android.gradle.plugin.get() apply false
id("org.jetbrains.compose") version libs.versions.compose.gradle.plugin.get() apply(false)
}

allprojects {
Expand All @@ -17,13 +19,15 @@ allprojects {
mavenCentral()
maven("https://androidx.dev/storage/compose-compiler/repository/")
maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/")
gradlePluginPortal() // for moko
}
}

subprojects {
// TODO libs doesn't resolve if we do this
// apply(plugin = libs.plugins.ktlint.get().pluginId)
apply(plugin = "org.jlleitschuh.gradle.ktlint")
apply(plugin = "dev.icerock.mobile.multiplatform-resources")

configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
enableExperimentalRules.set(true)
Expand Down
4 changes: 4 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ kotlin.code.style=official
xcodeproj=./ios
# New Android source-set layout
kotlin.mpp.androidSourceSetLayoutVersion=2

# Compose Multiplatform
org.jetbrains.compose.experimental.uikit.enabled=true
kotlin.native.cacheKind=none
17 changes: 13 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
kotlin = "1.8.21"
kotlin = "1.8.22"

## SDK Versions
minSdk = "21"
Expand All @@ -8,11 +8,12 @@ compileSdk = "33"

# Dependencies
android-gradle-plugin = "7.4.2"
compose-gradle-plugin = "1.4.1"
ktlint-gradle = "11.4.2"
gradle-versions = "0.47.0"

compose = "1.4.3"
composeCompiler = "1.4.7"
composeCompiler = "1.4.8"

android-desugaring = "2.0.3"
androidx-core = "1.10.1"
Expand All @@ -22,9 +23,9 @@ androidx-lifecycle = "2.6.1"

junit = "4.13.2"

coroutines = "1.7.0"
coroutines = "1.7.2"
kotlinx-datetime = "0.4.0"
ktor = "2.3.1"
ktor = "2.3.2"

robolectric = "4.10.3"

Expand All @@ -35,6 +36,9 @@ multiplatformSettings = "1.0.0"
turbine = "1.0.0"
sqlDelight = "2.0.0-rc01"

moko-resources = "0.23.0"
moko-graphics = "0.9.0"

[libraries]
android-desugaring = { module = "com.android.tools:desugar_jdk_libs", version.ref = "android-desugaring" }
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
Expand Down Expand Up @@ -86,9 +90,14 @@ touchlab-kermit-simple = { module = "co.touchlab:kermit-simple", version.ref = "
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }

moko-resources = { module = "dev.icerock.moko:resources", version.ref = "moko-resources" }
moko-resources-compose = { module = "dev.icerock.moko:resources-compose", version.ref = "moko-resources" }
moko-graphics = { module = "dev.icerock.moko:graphics", version.ref = "moko-graphics" }

[plugins]
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-gradle" }
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradle-versions" }
moko-resources = { id = "dev.icerock.mobile.multiplatform-resources", version.ref = "moko-resources" }

[bundles]
app-ui = [
Expand Down
44 changes: 16 additions & 28 deletions ios/KaMPKitiOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
objects = {

/* Begin PBXBuildFile section */
0AE285002A6AD6B7000B6B60 /* ComposeContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE284FF2A6AD6B7000B6B60 /* ComposeContentView.swift */; };
0AE285022A6AD7BD000B6B60 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE285012A6AD7BD000B6B60 /* ContentView.swift */; };
0AE285042A6AD7D0000B6B60 /* IOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE285032A6AD7D0000B6B60 /* IOSApp.swift */; };
3DFF917C64A18A83DA010EE1 /* Pods_KaMPKitiOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B859F3FB23133D22AB9DD835 /* Pods_KaMPKitiOS.framework */; };
461C74AA2788F5F3004B1FFC /* CombineAdapters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461C74A92788F5F3004B1FFC /* CombineAdapters.swift */; };
46A5B5EF26AF54F7002EFEAA /* BreedListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A5B5EE26AF54F7002EFEAA /* BreedListScreen.swift */; };
46A5B60826B04921002EFEAA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46A5B60626B04920002EFEAA /* Main.storyboard */; };
46B5284D249C5CF400A7725D /* Koin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46B5284C249C5CF400A7725D /* Koin.swift */; };
F1465F0123AA94BF0055F7C3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1465F0023AA94BF0055F7C3 /* AppDelegate.swift */; };
F1465F0A23AA94BF0055F7C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F1465F0923AA94BF0055F7C3 /* Assets.xcassets */; };
F1465F0D23AA94BF0055F7C3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F1465F0B23AA94BF0055F7C3 /* LaunchScreen.storyboard */; };
F1465F1823AA94C00055F7C3 /* KaMPKitiOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1465F1723AA94C00055F7C3 /* KaMPKitiOSTests.swift */; };
Expand All @@ -37,16 +36,15 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
0AE284FF2A6AD6B7000B6B60 /* ComposeContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeContentView.swift; sourceTree = "<group>"; };
0AE285012A6AD7BD000B6B60 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
0AE285032A6AD7D0000B6B60 /* IOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOSApp.swift; sourceTree = "<group>"; };
1DFCC00C8DAA719770A18D1A /* Pods-KaMPKitiOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KaMPKitiOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS.release.xcconfig"; sourceTree = "<group>"; };
2A1ED6A4A2A53F5F75C58E5F /* Pods-KaMPKitiOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KaMPKitiOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS.release.xcconfig"; sourceTree = "<group>"; };
461C74A92788F5F3004B1FFC /* CombineAdapters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CombineAdapters.swift; sourceTree = "<group>"; };
46A5B5EE26AF54F7002EFEAA /* BreedListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreedListScreen.swift; sourceTree = "<group>"; };
46A5B60726B04920002EFEAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
46B5284C249C5CF400A7725D /* Koin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Koin.swift; sourceTree = "<group>"; };
B859F3FB23133D22AB9DD835 /* Pods_KaMPKitiOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_KaMPKitiOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ED1F782AF3705197012D0C33 /* Pods-KaMPKitiOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KaMPKitiOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-KaMPKitiOS/Pods-KaMPKitiOS.debug.xcconfig"; sourceTree = "<group>"; };
F1465EFD23AA94BF0055F7C3 /* KaMPKitiOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KaMPKitiOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
F1465F0023AA94BF0055F7C3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
F1465F0923AA94BF0055F7C3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
F1465F0C23AA94BF0055F7C3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
F1465F0E23AA94BF0055F7C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -129,14 +127,13 @@
F1465EFF23AA94BF0055F7C3 /* KaMPKitiOS */ = {
isa = PBXGroup;
children = (
F1465F0023AA94BF0055F7C3 /* AppDelegate.swift */,
46A5B60626B04920002EFEAA /* Main.storyboard */,
46B5284C249C5CF400A7725D /* Koin.swift */,
F1465F0923AA94BF0055F7C3 /* Assets.xcassets */,
F1465F0B23AA94BF0055F7C3 /* LaunchScreen.storyboard */,
F1465F0E23AA94BF0055F7C3 /* Info.plist */,
46A5B5EE26AF54F7002EFEAA /* BreedListScreen.swift */,
461C74A92788F5F3004B1FFC /* CombineAdapters.swift */,
0AE284FF2A6AD6B7000B6B60 /* ComposeContentView.swift */,
0AE285012A6AD7BD000B6B60 /* ContentView.swift */,
0AE285032A6AD7D0000B6B60 /* IOSApp.swift */,
);
path = KaMPKitiOS;
sourceTree = "<group>";
Expand Down Expand Up @@ -266,7 +263,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
46A5B60826B04921002EFEAA /* Main.storyboard in Resources */,
F1465F0D23AA94BF0055F7C3 /* LaunchScreen.storyboard in Resources */,
F1465F0A23AA94BF0055F7C3 /* Assets.xcassets in Resources */,
);
Expand Down Expand Up @@ -354,9 +350,9 @@
buildActionMask = 2147483647;
files = (
46B5284D249C5CF400A7725D /* Koin.swift in Sources */,
461C74AA2788F5F3004B1FFC /* CombineAdapters.swift in Sources */,
46A5B5EF26AF54F7002EFEAA /* BreedListScreen.swift in Sources */,
F1465F0123AA94BF0055F7C3 /* AppDelegate.swift in Sources */,
0AE285002A6AD6B7000B6B60 /* ComposeContentView.swift in Sources */,
0AE285022A6AD7BD000B6B60 /* ContentView.swift in Sources */,
0AE285042A6AD7D0000B6B60 /* IOSApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -392,14 +388,6 @@
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
46A5B60626B04920002EFEAA /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
46A5B60726B04920002EFEAA /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
F1465F0B23AA94BF0055F7C3 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
Expand Down Expand Up @@ -464,7 +452,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -522,7 +510,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -596,7 +584,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = KaMPKitiOSTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -617,7 +605,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = KaMPKitiOSTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
34 changes: 0 additions & 34 deletions ios/KaMPKitiOS/AppDelegate.swift

This file was deleted.

Loading