iOS application¶
Use the ios/app product type in a module to build an iOS application.
Using IntelliJ IDEA?
Make sure to install the Kotlin Multiplatform plugin to get proper support for Kotlin/Native and iOS.
Module layout¶
Here is an overview of the module layout for an iOS application:
my-ios-app/
├─ src/
│ ├─ KotlinCode.kt # (1)!
│ ├─ EntryPoint.swift # (2)!
│ ╰─ Info.plist
├─ module.yaml
╰─ module.xcodeproj # (3)!
- Kotlin code is optional. Everything could come from dependencies.
- The entrypoint of iOS apps must be a
@mainstruct in a Swift file. Read more - An Xcode project is required but it can be automatically generated by the Kotlin Toolchain the first time. Read more
Entry point¶
For iOS applications, the entry point is expected to be a @main struct in any Swift file in the src folder.
├─ src/
│ ├─ main.swift
│ ╰─ ...
├─ module.yaml
╰─ module.xcodeproj
...
@main
struct iosApp: App {
...
}
This is not customizable at the moment.
Running your application¶
You can run your application using the kotlin run command.
Prerequisite: Xcode must be installed, and the first launch must have been run
already (this is a one-time operation that can also be done via the command xcodebuild -runFirstLaunch).
Xcode Project¶
Currently, an Xcode project is required to build an iOS application in the Kotlin Toolchain.
It has to be named module.xcodeproj and located in the ios/app module root directory.
Normally, when the Kotlin project is created via kotlin init or via the IDE's Wizard, the appropriate Xcode project is
already there. This is currently the recommended way of creating projects that have an iOS app module.
However, if the Kotlin project is created from scratch, the default buildable Xcode project will be created automatically after the first project build. This project can later be customized and checked into a VCS.
If you want to migrate an existing Xcode project so it has Kotlin Toolchain support, you must manually ensure that:
- it is named
module.xcodeprojand is located in the root of theios/appmodule - it has a single iOS application target
- the target has
Debug&Releasebuild configurations, each containingKOTLIN_CLI_WRAPPER_PATH = <relative path to Kotlin wrapper script>. The path is relative to the Kotlin module root. - the target has a script build phase called
Build Kotlinwith the code:# !KOTLIN INTEGRATION STEP! # This script is managed by the Kotlin Toolchain, do not edit manually! "${KOTLIN_CLI_WRAPPER_PATH}" tool xcode-integration
Changes to the Xcode project that do not break these requirements are allowed.
So the iOS app module layout looks like this:
├─ src/
│ ├─ KotlinCode.kt # optional, if all the code is in the libraries
│ ├─ EntryPoint.swift
│ ├─ Info.plist
├─ module.yaml # ios/app
╰─ module.xcodeproj # xcode project
Tip
The Xcode project can be built normally from the Xcode IDE, if needed.
Swift support¶
Info
Swift sources are only fully supported in the src directory of the ios/app module.
While swift sources are, strictly speaking, managed by the Xcode project and, as such,
can reside in arbitrary locations, it's not recommended to have them anywhere outside the src directory - the tooling
might not work correctly.
To use Kotlin code from Swift, one must import the KotlinModules framework.
This framework is built from:
- the code inside the
ios/appmodule itself - the modules that
ios/appmodule depends on (e.g.- //shared) - all the external dependencies, transitively
Note
All declarations from the source Kotlin code are accessible to Swift, but external dependencies are not.
Publishing¶
The Kotlin Toolchain creates a regular Xcode project for an ios/app module. Use that project to configure
signing, create a release archive, and upload the application to App Store Connect.
You need a Mac with Xcode and an Apple Developer Program membership.
Prepare the application¶
Open the module.xcodeproj file of the iOS application module in Xcode, for example:
open ios-app/module.xcodeproj
In the project navigator, select the project and then the application target. Configure the following settings before creating an archive:
- Under Signing & Capabilities, select your development team and replace the default bundle identifier with a unique identifier for your application.
- Under General | Minimum Deployments, select the oldest iOS version that your application supports.
- Under Info | Custom iOS Target Properties | Supported interface orientations, keep only the orientations your application supports.
- Add an
AppIconasset catalog under the module'ssrcdirectory and provide the application icon. A 1024×1024 image is sufficient when the asset uses Xcode's single-size app icon format. - Under General | Identity, set the public-facing Version and the unique Build number.
Use a new build number for every upload
App Store Connect rejects another upload with the same version and build number. Increase the Build value
(CFBundleVersion) before every upload. Increase Version (CFBundleShortVersionString) when publishing a new
application version.
Register the same bundle identifier in Certificates, Identifiers & Profiles, then create the application in App Store Connect. The bundle identifier in Xcode, the registered identifier, and the App Store Connect application must match.
Distribute from the command line¶
You can ask your coding agent to archive and upload the iOS application to TestFlight, or run the commands below manually. Run them from the Kotlin project root and replace the module path and scheme if they differ in your project. You can list the available schemes with:
xcodebuild -list -project ios-app/module.xcodeproj
Create a release archive:
xcodebuild \
-project ios-app/module.xcodeproj \
-scheme app \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath build/release/ios-app.xcarchive \
-allowProvisioningUpdates \
archive
Create ios-app/ExportOptions.plist to configure an App Store Connect upload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store-connect</string>
<key>destination</key>
<string>upload</string>
<key>signingStyle</key>
<string>automatic</string>
</dict>
</plist>
Export and upload the archive:
xcodebuild -exportArchive \
-archivePath build/release/ios-app.xcarchive \
-exportOptionsPlist ios-app/ExportOptions.plist \
-exportPath build/release/export \
-allowProvisioningUpdates
With destination set to upload, the export command uploads the application to App Store Connect. After Apple
finishes processing the build, it becomes available in App Store Connect and can be assigned to TestFlight testers.
Distribute from Xcode¶
You can perform the same archive and upload steps in Xcode:
- In the macOS menu bar, select Product | Archive.
- After the archive is created successfully, Xcode opens the Organizer window. Select the new archive and click Distribute App.
- Select App Store Connect, then follow the upload flow.
After Apple finishes processing the build, continue in App Store Connect to distribute it through TestFlight or submit it for App Store review.