Skip to content

Add iOS targets#218

Merged
dokar3 merged 1 commit intomainfrom
add-ios-targets
Apr 14, 2026
Merged

Add iOS targets#218
dokar3 merged 1 commit intomainfrom
add-ios-targets

Conversation

@dokar3
Copy link
Copy Markdown
Owner

@dokar3 dokar3 commented Apr 14, 2026

Summary by CodeRabbit

  • New Features

    • Added native iOS support with app for iPhone and iPad devices
  • Bug Fixes

    • Fixed IME inset handling in sheet backgrounds
  • Documentation

    • Updated supported platforms list to include iOS

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
[REDACTED]

[REDACTED]

Suggested cleanup

[REDACTED]

🤖 Prompt for AI Agents

[REDACTED]

sample-ios/Configuration/Config.xcconfig (1)

1-1: Optional: add a short comment for TEAM_ID placeholder.

A brief note that it should be set locally for physical-device signing can reduce contributor setup friction.

Suggested tweak
+// Set your Apple Developer Team ID locally when running on a physical device.
 TEAM_ID=
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sample-ios/Configuration/Config.xcconfig` at line 1, Add a short inline
comment next to the TEAM_ID placeholder explaining that TEAM_ID must be set
locally for signing on physical devices (e.g., "set your Apple Developer Team ID
for device signing; leave blank for CI/simulators"), so update the TEAM_ID line
in Config.xcconfig to include that note; reference the TEAM_ID placeholder so
contributors know where to set their local value and that it isn't required for
simulator builds or CI.
sample-ios/iosApp/Info.plist (1)

32-35: Remove manual architecture capability declaration for modern iOS targets.

The UIRequiredDeviceCapabilities entry listing armv7 is obsolete for modern iOS applications. Current guidance from Apple recommends omitting both armv7 and arm64 entries for apps targeting iOS 15+, as modern deployment configurations automatically target arm64 and Xcode handles architecture settings through build configuration. Keeping this entry unnecessarily restricts device compatibility. Either remove the key entirely or replace with an empty array.

Proposed update
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>armv7</string>
-	</array>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sample-ios/iosApp/Info.plist` around lines 32 - 35, Remove the manual
architecture requirement from Info.plist by deleting the
UIRequiredDeviceCapabilities key or replacing its array so it no longer contains
the "armv7" entry; locate the UIRequiredDeviceCapabilities key and the string
"armv7" in Info.plist and either remove the entire key/value pair or set the
array to empty to avoid restricting modern iOS targets.
sample/src/iosMain/kotlin/com/dokar/sheets/sample/Platform.ios.kt (1)

11-19: Unused state parameter.

The state parameter is accepted but not used in this stub implementation. Consider prefixing with underscore to suppress unused parameter warnings.

🔧 Suggested fix
 `@Composable`
 actual fun IntentPickerSheetContent(
-    state: BottomSheetState,
+    `@Suppress`("UNUSED_PARAMETER") state: BottomSheetState,
     modifier: Modifier,
 ) {

Or alternatively:

 `@Composable`
 actual fun IntentPickerSheetContent(
-    state: BottomSheetState,
+    state: BottomSheetState, // TODO: Use state when implementing iOS intent picker
     modifier: Modifier,
 ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sample/src/iosMain/kotlin/com/dokar/sheets/sample/Platform.ios.kt` around
lines 11 - 19, The IntentPickerSheetContent actual implementation declares a
parameter state: BottomSheetState that is unused; update the function signature
or parameter name to suppress the warning by prefixing the parameter with an
underscore (e.g., _state) or otherwise using state in the body, keeping the
function IntentPickerSheetContent, the BottomSheetState type and Modifier
parameter intact so callers remain compatible.
sample-ios/iosApp.xcodeproj/project.pbxproj (1)

133-151: Consider specifying input/output paths for incremental builds.

The "Compile Kotlin Framework" build phase has empty inputPaths and outputPaths, causing the Gradle task to run on every build. For faster incremental builds, consider specifying paths so Xcode can skip the phase when inputs haven't changed.

Example input/output specification:

inputPaths = (
    "$(SRCROOT)/../sample/src/",
);
outputPaths = (
    "$(SRCROOT)/../sample/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)/SheetsSample.framework",
);

Note: This optimization can be deferred since the current setup is functional and the KMP Gradle plugin manages framework generation reliably.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sample-ios/iosApp.xcodeproj/project.pbxproj` around lines 133 - 151, The
"Compile Kotlin Framework" PBXShellScriptBuildPhase currently has empty
inputPaths/outputPaths which forces the Gradle task to run every build; update
the PBXShellScriptBuildPhase entry named "Compile Kotlin Framework" to supply
appropriate inputPaths (e.g., the sample module source and any
build.gradle/Kotlin sources) and outputPaths (the generated framework path for
the current configuration/SDK) so Xcode can perform incremental checks before
running the shellScript "./gradlew :sample:embedAndSignAppleFrameworkForXcode";
ensure you reference the same phase by its name ("Compile Kotlin Framework") and
populate the inputPaths and outputPaths arrays with the SRCROOT-relative paths
that match your project layout.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@sample-ios/Configuration/Config.xcconfig`:
- Line 1: Add a short inline comment next to the TEAM_ID placeholder explaining
that TEAM_ID must be set locally for signing on physical devices (e.g., "set
your Apple Developer Team ID for device signing; leave blank for
CI/simulators"), so update the TEAM_ID line in Config.xcconfig to include that
note; reference the TEAM_ID placeholder so contributors know where to set their
local value and that it isn't required for simulator builds or CI.

In `@sample-ios/iosApp.xcodeproj/project.pbxproj`:
- Around line 133-151: The "Compile Kotlin Framework" PBXShellScriptBuildPhase
currently has empty inputPaths/outputPaths which forces the Gradle task to run
every build; update the PBXShellScriptBuildPhase entry named "Compile Kotlin
Framework" to supply appropriate inputPaths (e.g., the sample module source and
any build.gradle/Kotlin sources) and outputPaths (the generated framework path
for the current configuration/SDK) so Xcode can perform incremental checks
before running the shellScript "./gradlew
:sample:embedAndSignAppleFrameworkForXcode"; ensure you reference the same phase
by its name ("Compile Kotlin Framework") and populate the inputPaths and
outputPaths arrays with the SRCROOT-relative paths that match your project
layout.

[REDACTED]

In `@sample-ios/iosApp/Info.plist`:
- Around line 32-35: Remove the manual architecture requirement from Info.plist
by deleting the UIRequiredDeviceCapabilities key or replacing its array so it no
longer contains the "armv7" entry; locate the UIRequiredDeviceCapabilities key
and the string "armv7" in Info.plist and either remove the entire key/value pair
or set the array to empty to avoid restricting modern iOS targets.

In `@sample/src/iosMain/kotlin/com/dokar/sheets/sample/Platform.ios.kt`:
- Around line 11-19: The IntentPickerSheetContent actual implementation declares
a parameter state: BottomSheetState that is unused; update the function
signature or parameter name to suppress the warning by prefixing the parameter
with an underscore (e.g., _state) or otherwise using state in the body, keeping
the function IntentPickerSheetContent, the BottomSheetState type and Modifier
parameter intact so callers remain compatible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d8adee34-060d-4101-a64a-cf1b839a6d2a

📥 Commits

Reviewing files that changed from the base of the PR and between 82931af and 55bde16ad699376005011f96b65750278b7d79eb.

📒 Files selected for processing (17)

[REDACTED]

  • sample-ios/Configuration/Config.xcconfig
  • sample-ios/iosApp.xcodeproj/project.pbxproj
  • sample-ios/iosApp/ContentView.swift
  • sample-ios/iosApp/Info.plist
  • sample-ios/iosApp/iOSApp.swift
  • sample/build.gradle.kts
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/MainViewController.kt
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/Platform.ios.kt
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/SampleNavigation.kt
  • sheets-core/build.gradle.kts
  • sheets-core/src/commonMain/kotlin/com/dokar/sheets/BackgroundWithInsetsModifier.kt
  • sheets-core/src/commonMain/kotlin/com/dokar/sheets/CoreBottomSheetLayout.kt
  • sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt
  • sheets-m3/build.gradle.kts
  • sheets/build.gradle.kts
💤 Files with no reviewable changes (1)
  • sheets-core/src/commonMain/kotlin/com/dokar/sheets/BackgroundWithInsetsModifier.kt

Repository owner deleted a comment from coderabbitai bot Apr 14, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 14, 2026

📝 Walkthrough

Walkthrough

This pull request adds comprehensive iOS platform support to a Kotlin Multiplatform project. Changes include iOS Kotlin/Native targets in build configurations across modules, a new Xcode project setup with Swift entry points, iOS-specific Kotlin implementations, IME visibility handling adjustments, and documentation updates reflecting iOS as a now-supported target.

Changes

Cohort / File(s) Summary
iOS Build Configuration
sample-ios/Configuration/Config.xcconfig, sample-ios/iosApp.xcodeproj/project.pbxproj
Added Xcode project configuration with TEAM_ID, BUNDLE_ID, and APP_NAME settings. Defined iosApp target, build phases (including Kotlin/Native framework embedding), Swift source references, and platform-specific settings for signing, frameworks, and device configurations.
iOS Swift App Entry Points
sample-ios/iosApp/iOSApp.swift, sample-ios/iosApp/ContentView.swift, sample-ios/iosApp/Info.plist
Added SwiftUI app structure with @main entry point, WindowGroup scene, and ContentView composable. ContentView wraps a ComposeViewController that instantiates Kotlin MainViewController. Configured app metadata, versioning, and UI orientation constraints in Info.plist.
Kotlin Multiplatform iOS Targets
sheets-core/build.gradle.kts, sheets-m3/build.gradle.kts, sheets/build.gradle.kts, sample/build.gradle.kts
Added iOS Kotlin/Native targets (iosX64, iosArm64, iosSimulatorArm64) across four modules. Configured framework binary settings with baseName = "SheetsSample" and isStatic = true for sample module.
iOS Kotlin/Native Implementations
sample/src/iosMain/kotlin/com/dokar/sheets/sample/MainViewController.kt, sample/src/iosMain/kotlin/com/dokar/sheets/sample/SampleNavigation.kt, sample/src/iosMain/kotlin/com/dokar/sheets/sample/Platform.ios.kt
Added iOS entry function MainViewController creating ComposeUIViewController with theme state management. Implemented platform-specific SampleApp composable with IME demo disabled. Added placeholder IntentPickerSheetContent implementation returning "Not supported yet" text.
Core IME and Platform Handling
sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt, sheets-core/src/commonMain/kotlin/com/dokar/sheets/CoreBottomSheetLayout.kt, sheets-core/src/commonMain/kotlin/com/dokar/sheets/BackgroundWithInsetsModifier.kt
Added iOS platform-specific values (SecureFlagPolicy, defaultWindowSoftInputMode = 0, hasLightNavigationBar = false), isImeVisible() composable always returning false, and SheetHost implementation with Popup. Updated CoreBottomSheetLayout to exclude IME insets from navigation bar insets. Removed trailing whitespace.
Project Metadata
README.md, sample-ios/.gitignore
Updated README to reflect iOS as a supported target, replacing the previous "seeking contributions" note. Added .gitignore rule to exclude xcuserdata directories.

Sequence Diagram

sequenceDiagram
    actor User
    participant SwiftUI as SwiftUI<br/>(ContentView)
    participant Bridge as ComposeViewController<br/>(UIViewControllerRepresentable)
    participant Kotlin as Kotlin/Native<br/>(MainViewController)
    participant Compose as Compose UI<br/>(SampleApp)
    
    User->>SwiftUI: Launch App
    SwiftUI->>Bridge: Create ContentView with<br/>ComposeViewController
    Bridge->>Kotlin: makeUIViewController()<br/>→ MainViewController()
    Kotlin->>Compose: ComposeUIViewController renders<br/>SampleApp composable
    Compose->>Compose: Initialize dark theme state<br/>remember { mutableStateOf(false) }
    Compose-->>Kotlin: onUpdateDarkTheme callback
    Kotlin-->>Compose: isDarkTheme state updates
    Compose-->>User: Render themed UI
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hops of joy, iOS now takes flight,
Swift meets Kotlin in harmonious light,
From Xcode's nest to Compose's embrace,
The rabbit bids iOS a warm welcome place!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add iOS targets' directly and clearly summarizes the main change: adding iOS support (iosX64, iosArm64, iosSimulatorArm64 targets) across the build system and sample app.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-ios-targets

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt (1)

32-35: Use a one-time effect for IME state initialization.

SideEffect runs after every recomposition; here the state values are constant. Prefer a one-shot effect to avoid redundant writes.

♻️ Suggested simplification
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.SideEffect
@@
-    SideEffect {
+    LaunchedEffect(Unit) {
         state.imeVisible = false
         state.hasImeVisibilityUpdated = true
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt` around lines
32 - 35, Replace the recurring SideEffect with a one-time effect so you don't
repeatedly write the same values: change the SideEffect block that sets
state.imeVisible and state.hasImeVisibilityUpdated to a one-shot effect such as
LaunchedEffect keyed to Unit (or another stable key) so that state.imeVisible =
false and state.hasImeVisibilityUpdated = true run only once during
initialization rather than on every recomposition.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt`:
- Around line 25-42: The iOS SheetHost currently ignores the
DialogSheetBehaviors parameter; update the SheetHost function to inspect the
passed-in behaviors (DialogSheetBehaviors) and either map supported flags into
PopupProperties (e.g., set focusable/usePlatformInsets on the Popup) or, as a
minimal fail-fast guard, detect non-default/unsupported behavior flags and throw
a clear UnsupportedOperationException (or log and call onDismissRequest) so
callers get immediate feedback instead of silent no-ops; adjust the code around
the Popup/PopupProperties creation to use the computed properties and reference
SheetHost, DialogSheetBehaviors, PopupProperties, and Popup when implementing
this check/mapping.

---

Nitpick comments:
In `@sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt`:
- Around line 32-35: Replace the recurring SideEffect with a one-time effect so
you don't repeatedly write the same values: change the SideEffect block that
sets state.imeVisible and state.hasImeVisibilityUpdated to a one-shot effect
such as LaunchedEffect keyed to Unit (or another stable key) so that
state.imeVisible = false and state.hasImeVisibilityUpdated = true run only once
during initialization rather than on every recomposition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0158c90e-f1e1-4cb0-b3c8-afbe70f10856

📥 Commits

Reviewing files that changed from the base of the PR and between 55bde16ad699376005011f96b65750278b7d79eb and 1908a46.

📒 Files selected for processing (17)
  • README.md
  • sample-ios/.gitignore
  • sample-ios/Configuration/Config.xcconfig
  • sample-ios/iosApp.xcodeproj/project.pbxproj
  • sample-ios/iosApp/ContentView.swift
  • sample-ios/iosApp/Info.plist
  • sample-ios/iosApp/iOSApp.swift
  • sample/build.gradle.kts
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/MainViewController.kt
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/Platform.ios.kt
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/SampleNavigation.kt
  • sheets-core/build.gradle.kts
  • sheets-core/src/commonMain/kotlin/com/dokar/sheets/BackgroundWithInsetsModifier.kt
  • sheets-core/src/commonMain/kotlin/com/dokar/sheets/CoreBottomSheetLayout.kt
  • sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt
  • sheets-m3/build.gradle.kts
  • sheets/build.gradle.kts
💤 Files with no reviewable changes (1)
  • sheets-core/src/commonMain/kotlin/com/dokar/sheets/BackgroundWithInsetsModifier.kt
✅ Files skipped from review due to trivial changes (11)
  • sample-ios/.gitignore
  • README.md
  • sample-ios/iosApp/iOSApp.swift
  • sheets-core/build.gradle.kts
  • sheets-core/src/commonMain/kotlin/com/dokar/sheets/CoreBottomSheetLayout.kt
  • sheets-m3/build.gradle.kts
  • sample-ios/Configuration/Config.xcconfig
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/Platform.ios.kt
  • sample-ios/iosApp/Info.plist
  • sheets/build.gradle.kts
  • sample-ios/iosApp.xcodeproj/project.pbxproj
🚧 Files skipped from review as they are similar to previous changes (4)
  • sample-ios/iosApp/ContentView.swift
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/MainViewController.kt
  • sample/build.gradle.kts
  • sample/src/iosMain/kotlin/com/dokar/sheets/sample/SampleNavigation.kt

Comment on lines +25 to +42
internal actual fun SheetHost(
state: BottomSheetState,
behaviors: DialogSheetBehaviors,
showAboveKeyboard: Boolean,
onDismissRequest: () -> Unit,
content: @Composable () -> Unit,
) {
SideEffect {
state.imeVisible = false
state.hasImeVisibilityUpdated = true
}

Popup(
onDismissRequest = onDismissRequest,
properties = PopupProperties(
focusable = true,
usePlatformInsets = false,
),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

DialogSheetBehaviors is currently ignored in iOS SheetHost.

On Line 27, behaviors is accepted, but Lines 37-42 hardcode popup behavior. This makes behavior flags effectively no-op on iOS (e.g., dismissal controls), which creates cross-platform inconsistencies for callers.

💡 Minimal fail-fast guard (until full behavior mapping is implemented)
 `@Composable`
 internal actual fun SheetHost(
     state: BottomSheetState,
     behaviors: DialogSheetBehaviors,
     showAboveKeyboard: Boolean,
     onDismissRequest: () -> Unit,
     content: `@Composable` () -> Unit,
 ) {
+    require(behaviors.collapseOnBackPress && behaviors.collapseOnClickOutside) {
+        "iOS SheetHost currently does not support custom collapse behavior flags."
+    }
+
     SideEffect {
         state.imeVisible = false
         state.hasImeVisibilityUpdated = true
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sheets-core/src/iosMain/kotlin/com/dokar/sheets/Platform.ios.kt` around lines
25 - 42, The iOS SheetHost currently ignores the DialogSheetBehaviors parameter;
update the SheetHost function to inspect the passed-in behaviors
(DialogSheetBehaviors) and either map supported flags into PopupProperties
(e.g., set focusable/usePlatformInsets on the Popup) or, as a minimal fail-fast
guard, detect non-default/unsupported behavior flags and throw a clear
UnsupportedOperationException (or log and call onDismissRequest) so callers get
immediate feedback instead of silent no-ops; adjust the code around the
Popup/PopupProperties creation to use the computed properties and reference
SheetHost, DialogSheetBehaviors, PopupProperties, and Popup when implementing
this check/mapping.

@dokar3 dokar3 merged commit 11fbe14 into main Apr 14, 2026
2 checks passed
@dokar3 dokar3 deleted the add-ios-targets branch April 14, 2026 09:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant