CLAUDE LABJP
2.1.278 — The auto mode classifier now runs server-side by default on the Claude API, Enterprise, Bedrock, Vertex and Foundry. You are not billed for the classifier, and /status gained an Auto mode server lineTASKOUT — The TaskOutput tool is gone. taskOutputMaxChars and TASK_MAX_OUTPUT_LENGTH no longer do anything, and background output is read with Read instead10/07 — The old management-configuration key spellings are accepted until noon PT on October 7, seventeen days from now. After that, entries that still use them stop working until you rewrite themBUNPANIC — Reports are coming in of the newest build crashing on launch alone. Earlier builds still run on the same machine, which points at the release rather than the environmentNEW — Deciding what belongs in Cowork and what belongs in Claude Code, using the approval boundary as the lineSONNET4.5 — A date in a deprecation table is a floor, not an end date. Sonnet 4.5 is still active and no deprecation notice has been posted2.1.278 — The auto mode classifier now runs server-side by default on the Claude API, Enterprise, Bedrock, Vertex and Foundry. You are not billed for the classifier, and /status gained an Auto mode server lineTASKOUT — The TaskOutput tool is gone. taskOutputMaxChars and TASK_MAX_OUTPUT_LENGTH no longer do anything, and background output is read with Read instead10/07 — The old management-configuration key spellings are accepted until noon PT on October 7, seventeen days from now. After that, entries that still use them stop working until you rewrite themBUNPANIC — Reports are coming in of the newest build crashing on launch alone. Earlier builds still run on the same machine, which points at the release rather than the environmentNEW — Deciding what belongs in Cowork and what belongs in Claude Code, using the approval boundary as the lineSONNET4.5 — A date in a deprecation table is a floor, not an end date. Sonnet 4.5 is still active and no deprecation notice has been posted
Articles/API & SDK
API & SDK/2026-04-14Advanced

Claude API × Kotlin Multiplatform — Building Production AI Features for iOS and Android

Integrating Claude API with Kotlin Multiplatform (KMP) to ship production-quality AI assistant features on iOS and Android. Stream termination, mid-stream error events, retry strategies, expect/actual alignment, and testing — written from an indie developer's production experience.

kotlin-multiplatformkmpclaude-api82ios14android9mobile4aisdk5

Premium Article

The hardest part of Kotlin Multiplatform isn't writing shared code — it's accepting that the gap between "runs in commonMain" and "works properly on both platforms" is often wider than you'd expect. You can unify your networking with Ktor, but getting Claude API's streaming responses to flow correctly to your UI thread, with proper error handling and retry behaviour, takes careful design.

I build iOS and Android apps on my own, and I have been adding Claude API as an in-app assistant to several of them. I reached for KMP for an unglamorous reason: maintaining two separate codebases had stopped being realistic for one person.

What I did not expect was how often iOS-only or Android-only code behaves differently once it moves into a KMP project — and how many of those differences compile cleanly, which is exactly what delays discovery.

This article is the record of that work. It covers what I actually did to take Claude API from "runs in KMP" to "runs reliably for 24 hours in production alongside AdMob mediation," with the design decisions, pitfalls, and operational numbers I encountered as an indie developer. My goal is straightforward: to save you from getting stuck in the places where I got stuck.

Project Structure and Design Philosophy

Here's the recommended folder structure for Claude API integration in KMP:

shared/
├── src/
│   ├── commonMain/
│   │   └── kotlin/
│   │       └── com/example/ai/
│   │           ├── ClaudeClient.kt       # API client
│   │           ├── ClaudeModels.kt       # Request/response models
│   │           ├── StreamingHandler.kt   # Streaming logic
│   │           └── RetryPolicy.kt        # Retry and error handling
│   ├── androidMain/
│   │   └── kotlin/
│   │       └── com/example/ai/
│   │           └── PlatformClient.android.kt  # Android-specific
│   └── iosMain/
│       └── kotlin/
│           └── com/example/ai/
│               └── PlatformClient.ios.kt      # iOS-specific
androidApp/
iosApp/

Why this structure: Communication logic — request building, JSON parsing, and retry handling — has no platform differences, so it belongs entirely in commonMain. Only genuinely platform-specific concerns (SSL certificate pinning, Keychain/EncryptedSharedPreferences storage) go into androidMain and iosMain. This separation means bug fixes and features land in one place, not two.

Step 1: Gradle Configuration and Ktor Client

// shared/build.gradle.kts
plugins {
    kotlin("multiplatform")
    kotlin("plugin.serialization")
    id("com.android.library")
}
 
kotlin {
    androidTarget()
 
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
        }
    }
 
    sourceSets {
        commonMain.dependencies {
            // Ktor — the KMP-native HTTP client
            implementation("io.ktor:ktor-client-core:3.1.2")
            implementation("io.ktor:ktor-client-content-negotiation:3.1.2")
            implementation("io.ktor:ktor-serialization-kotlinx-json:3.1.2")
            implementation("io.ktor:ktor-client-logging:3.1.2")
 
            // kotlinx.serialization — JSON parsing
            implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
 
            // kotlinx.coroutines — async/flow
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1")
        }
 
        androidMain.dependencies {
            // Android: OkHttp engine (connection pooling, HTTP/2)
            implementation("io.ktor:ktor-client-okhttp:3.1.2")
        }
 
        iosMain.dependencies {
            // iOS: Darwin engine wraps NSURLSession
            implementation("io.ktor:ktor-client-darwin:3.1.2")
        }
    }
}

Why OkHttp for Android and Darwin for iOS: OkHttp isn't available on iOS. The Darwin engine wraps NSURLSession, which integrates naturally with iOS-specific SSL and proxy settings. On Android, OkHttp's connection pool and HTTP/2 support are significant practical advantages for real devices on mobile networks.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why the obvious SSE implementation never fires `StreamEvent.Done`, how a Claude API stream actually terminates, and the measured difference after the fix
Operational knowledge not in the official docs: expect/actual signature alignment, Kotlin/Native GC tuning, SKIE / Swift Concurrency interop
A 14-item pre-release checklist covering API key protection, Crashlytics wiring, and behaviour on poor mobile networks
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

API & SDK2026-05-13
Design Decisions Every Indie Developer Faces When Integrating Claude API into Mobile Apps
The design decisions indie mobile developers hit when integrating Claude API — model selection, async UX, context management, offline resilience, and cost control — with working code and a per-user cost table recalculated for the September 2026 price change.
API & SDK2026-05-02
Calling Claude API from iOS Shortcuts: A Personal Setup for Reshaping Selected Text on the Fly
A personal setup guide for invoking the Claude API directly from iOS Shortcuts. Reshape selected text in seconds with a Cloudflare Workers proxy that keeps your API key off the device.
Claude Code2026-04-07
Claude Code × Flutter: Complete App Development Guide — Accelerating Mobile Development with Dart and AI
A practical guide to using Claude Code for Flutter development. From auto-generating Dart code to state management, UI design, test automation, and App Store submission — a complete roadmap for indie developers.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links