mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
docs: add compose development guidelines and skills
Added a comprehensive collection of Compose development guidelines, best practices, and skill definitions in the .codex directory. Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
290
.codex/skills/compose-skill/references/ci-cd-distribution.md
Normal file
290
.codex/skills/compose-skill/references/ci-cd-distribution.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# CI/CD & Distribution
|
||||
|
||||
CI/CD and native distribution for Compose Multiplatform: Android, Desktop (JVM), and iOS.
|
||||
|
||||
## 1. Distribution Overview
|
||||
|
||||
| Platform | Output | Gradle Task | Notes |
|
||||
|----------|--------|-------------|-------|
|
||||
| Android | APK/AAB | `assembleRelease`/`bundleRelease` | Standard distribution |
|
||||
| Desktop macOS | DMG | `packageDmg` | Needs signing for Gatekeeper |
|
||||
| Desktop Windows | MSI | `packageMsi` | Optional signing |
|
||||
| Desktop Linux | DEB | `packageDeb` | Package manager format |
|
||||
| iOS | .app/.ipa | Xcode Archive | Gradle builds framework only |
|
||||
|
||||
## 2. GitHub Actions — Android
|
||||
|
||||
```yaml
|
||||
name: Android Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- run: ./gradlew :androidApp:assembleRelease
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: android-apk
|
||||
path: androidApp/build/outputs/apk/release/*.apk
|
||||
```
|
||||
|
||||
### With Signing
|
||||
|
||||
```yaml
|
||||
- name: Decode Keystore
|
||||
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > release.keystore
|
||||
|
||||
- run: ./gradlew :androidApp:assembleRelease
|
||||
env:
|
||||
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
||||
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
||||
```
|
||||
|
||||
## 3. GitHub Actions — Desktop Multi-Platform
|
||||
|
||||
```yaml
|
||||
name: Desktop Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build_macos: { type: boolean, default: true }
|
||||
build_windows: { type: boolean, default: true }
|
||||
build_linux: { type: boolean, default: true }
|
||||
|
||||
jobs:
|
||||
build-macos:
|
||||
if: ${{ inputs.build_macos }}
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with: { java-version: '21', distribution: 'temurin' }
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
- run: ./gradlew :desktopApp:packageDmg
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-dmg
|
||||
path: desktopApp/build/compose/binaries/main/dmg/*.dmg
|
||||
|
||||
build-windows:
|
||||
if: ${{ inputs.build_windows }}
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with: { java-version: '21', distribution: 'temurin' }
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
- run: ./gradlew :desktopApp:packageMsi
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-msi
|
||||
path: desktopApp/build/compose/binaries/main/msi/*.msi
|
||||
|
||||
build-linux:
|
||||
if: ${{ inputs.build_linux }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with: { java-version: '21', distribution: 'temurin' }
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
- run: ./gradlew :desktopApp:packageDeb
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-deb
|
||||
path: desktopApp/build/compose/binaries/main/deb/*.deb
|
||||
```
|
||||
|
||||
## 4. Desktop App Module
|
||||
|
||||
```kotlin
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.multiplatform)
|
||||
alias(libs.plugins.compose.multiplatform)
|
||||
alias(libs.plugins.compose.compiler)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
sourceSets {
|
||||
jvmMain.dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
implementation(projects.composeApp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compose.desktop {
|
||||
application {
|
||||
mainClass = "com.example.MainKt"
|
||||
|
||||
// Required for DataStore/serialization
|
||||
jvmArgs += listOf(
|
||||
"--add-opens", "java.base/java.lang=ALL-UNNAMED",
|
||||
"--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED"
|
||||
)
|
||||
|
||||
nativeDistributions {
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
||||
packageName = "MyApp"
|
||||
packageVersion = "1.0.0"
|
||||
modules("jdk.unsupported")
|
||||
|
||||
macOS {
|
||||
bundleID = "com.example.myapp"
|
||||
iconFile.set(project.file("icons/icon.icns"))
|
||||
// signing { sign.set(true); identity.set("Developer ID Application: ...") }
|
||||
}
|
||||
windows {
|
||||
iconFile.set(project.file("icons/icon.ico"))
|
||||
upgradeUuid = "YOUR-UUID" // Keep constant across versions
|
||||
}
|
||||
linux {
|
||||
iconFile.set(project.file("icons/icon.png"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. iOS Xcode Integration
|
||||
|
||||
iOS uses Xcode, not Gradle. Gradle builds the shared framework; Xcode embeds it.
|
||||
|
||||
### Framework in `composeApp`
|
||||
|
||||
```kotlin
|
||||
kotlin {
|
||||
listOf(iosArm64(), iosSimulatorArm64()).forEach {
|
||||
it.binaries.framework {
|
||||
baseName = "ComposeApp"
|
||||
isStatic = true // Required for App Store
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Xcode Build Phase Script
|
||||
|
||||
Add "Run Script" before "Compile Sources":
|
||||
|
||||
```bash
|
||||
cd "$SRCROOT/.."
|
||||
./gradlew :composeApp:embedAndSignAppleFrameworkForXcode
|
||||
```
|
||||
|
||||
### Swift Entry Point
|
||||
|
||||
```swift
|
||||
import SwiftUI
|
||||
import ComposeApp
|
||||
|
||||
@main
|
||||
struct iOSApp: App {
|
||||
init() { AppKt.doInitKoin() }
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ComposeViewControllerRepresentable().ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ComposeViewControllerRepresentable: UIViewControllerRepresentable {
|
||||
func makeUIViewController(context: Context) -> UIViewController {
|
||||
MainViewControllerKt.MainViewController()
|
||||
}
|
||||
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Signing
|
||||
|
||||
### Android
|
||||
|
||||
```kotlin
|
||||
android {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
storeFile = file("release.keystore")
|
||||
storePassword = System.getenv("KEYSTORE_PASSWORD")
|
||||
keyAlias = System.getenv("KEY_ALIAS")
|
||||
keyPassword = System.getenv("KEY_PASSWORD")
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release { signingConfig = signingConfigs.getByName("release") }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### macOS (Direct Distribution)
|
||||
|
||||
```kotlin
|
||||
macOS {
|
||||
signing {
|
||||
sign.set(true)
|
||||
identity.set("Developer ID Application: Your Name (TEAM_ID)")
|
||||
}
|
||||
notarization {
|
||||
appleID.set("your-email@example.com")
|
||||
password.set("@keychain:AC_PASSWORD")
|
||||
teamID.set("YOUR_TEAM_ID")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### iOS
|
||||
|
||||
Handled by Xcode via `CODE_SIGN_STYLE = Automatic` and `DEVELOPMENT_TEAM`.
|
||||
|
||||
## 7. Adding Desktop to Existing CMP Project
|
||||
|
||||
1. Add `jvm()` target in `composeApp`:
|
||||
```kotlin
|
||||
kotlin {
|
||||
jvm()
|
||||
sourceSets {
|
||||
jvmMain.dependencies { /* desktop deps */ }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Add KSP for JVM: `add("kspJvm", libs.room.compiler)`
|
||||
|
||||
3. Create `desktopApp` module with `compose.desktop {}` config
|
||||
|
||||
4. Add `include(":desktopApp")` to `settings.gradle.kts`
|
||||
|
||||
## 8. Gradle Tasks
|
||||
|
||||
| Platform | Build | Package | Run |
|
||||
|----------|-------|---------|-----|
|
||||
| Android | `assembleRelease` | `bundleRelease` | — |
|
||||
| Desktop | `jvmJar` | `packageDmg`/`packageMsi`/`packageDeb` | `run` |
|
||||
| iOS | `compileKotlinIosArm64` | Xcode Archive | Xcode |
|
||||
|
||||
## 9. Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| `InaccessibleObjectException` | Add `--add-opens` JVM args |
|
||||
| "App is damaged" on macOS | Enable code signing |
|
||||
| Framework not found in Xcode | Check `FRAMEWORK_SEARCH_PATHS` |
|
||||
| Windows MSI won't upgrade | Keep `upgradeUuid` constant |
|
||||
Reference in New Issue
Block a user