@@ -6,47 +6,50 @@ Consider a Kotlin Multiplatform project that has an iOS target. You may want to
6
6
as a dependency to iOS developers working on native Swift projects. Using Kotlin Multiplatform tooling, you can provide
7
7
an artifact that would seamlessly integrate with their Xcode projects.
8
8
9
- This guide shows how to do this by building [ XCFrameworks] ( multiplatform-build-native-binaries.md#build-xcframeworks )
9
+ This tutorial shows how to do this by building [ XCFrameworks] ( multiplatform-build-native-binaries.md#build-xcframeworks )
10
10
with the Kotlin Gradle plugin.
11
11
12
- ## Prepare file locations
12
+ ## Set up remote integration
13
13
14
- To make your framework consumable, you need to upload two files:
15
- * A ZIP archive of the XCFramework. Upload it to a convenient file storage with direct access (for example,
16
- creating a GitHub release with the archive attached, using Amazon S3 or Maven).
14
+ To make your framework consumable, you'll need to upload two files:
15
+
16
+ * A ZIP archive with the XCFramework. You'll need to upload it to a convenient file storage with direct access (for example,
17
+ creating a GitHub release with the archive attached, using Amazon S3 or Maven).
17
18
Choose the option that is easiest to integrate into your workflow.
18
- * The ` Package.swift ` file describing the package. Prepare a Git repository and push it there.
19
- To decide how to organize your repositories, see the pros and cons of several options below.
19
+ * The ` Package.swift ` file describing the package. You'll need to push it to a separate Git repository.
20
+
21
+ #### Project configuration options {initial-collapse-state="collapsed"}
20
22
21
- ### Swift package distribution
23
+ In this tutorial, you'll store your XCFramework as a binary in your preferred file storage, and the ` Package.swift ` file
24
+ in a separate Git repository.
22
25
23
- Consider the following options for organizing your Git repositories:
26
+ However, you can configure your project differently. Consider the following options for organizing Git repositories:
24
27
25
- * Store the ` Package.swift ` file in an independent repository. This allows versioning it separately from the
26
- Kotlin Multiplatform project the file describes. This is the recommended approach: it allows scaling and generally easier
27
- to maintain.
28
+ * Store the ` Package.swift ` file and the code that should be packaged into an XCFramework in separate Git repositories.
29
+ This allows versioning the Swift manifest separately from the project the file describes. This is the recommended approach:
30
+ it allows scaling and is generally easier to maintain.
28
31
* Put the ` Package.swift ` file next to your Kotlin Multiplatform code. This is a more straightforward approach, but
29
- keep in mind in this case the Swift package and the code will use the same versioning. SPM uses
30
- Git tags for versioning packages, and this can conflict with tags used for the project.
31
- * Store the ` Package.swift ` within the consumer project's repository. This helps to avoid the versioning and maintenance issues.
32
+ keep in mind that, in this case, the Swift package and the code will use the same versioning. SPM uses
33
+ Git tags for versioning packages, which can conflict with tags used for your project.
34
+ * Store the ` Package.swift ` file within the consumer project's repository. This helps to avoid versioning and maintenance issues.
32
35
However, this approach can cause problems with multi-repository SPM setups of the consumer project and further automation:
33
36
34
37
* In a multi-package project, only one consumer package can depend on the external module (to avoid dependency conflicts
35
- within the project). So, all the logic that depends on your Kotlin Multiplatform module should be encapsulated in a particular consumer package.
36
- * If you publish the Kotlin Multiplatform project using an automated CI process, this process would need to include publishing the
37
- updated ` Package.swift ` file to the consumer repository. Such a phase in CI can be difficult to maintain as it may lead
38
- to conflicting updates of the consumer repository.
38
+ within the project). So, all the logic that depends on your Kotlin Multiplatform module should be encapsulated in a
39
+ particular consumer package.
40
+ * If you publish the Kotlin Multiplatform project using an automated CI process, this process would need to include
41
+ publishing the updated ` Package.swift ` file to the consumer repository. This may lead to conflicting updates of the
42
+ consumer repository and so such a phase in CI can be difficult to maintain.
43
+
44
+ ### Configure your multiplatform project
39
45
40
- ## Create the XCFramework and the Swift package manifest
46
+ In the following example, the shared code of a Kotlin Multiplatform project is stored locally in the ` shared ` module.
47
+ If your project is structured differently, substitute "shared" in code and path examples with your module's name.
41
48
42
- > The following example assumes that the shared code of your Kotlin Multiplatform project is stored in the ` shared ` module.
43
- > If your project is structured differently, substitute "shared" in code and path examples with your module's name.
44
- >
45
- {type="tip"}
49
+ To set up the publishing of an XCFramework:
50
+
51
+ 1 . Update your ` shared/build.gradle.kts ` configuration file with the ` XCFramework ` call in the iOS targets list:
46
52
47
- To provide a Swift package:
48
- 1 . Set up the publishing of an [ XCFramework] ( multiplatform-build-native-binaries.md#build-xcframeworks ) . Add the ` XCFramework `
49
- call to your iOS targets description in the ` shared/build.gradle.kts ` file:
50
53
``` kotlin
51
54
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
52
55
@@ -81,12 +84,22 @@ call to your iOS targets description in the `shared/build.gradle.kts` file:
81
84
82
85
The resulting framework will be created as the ` shared/build/XCFrameworks/release/Shared.xcframework ` folder in your project directory.
83
86
84
- 3 . Put the ` Shared.xcframework ` folder in a ZIP archive and calculate the checksum for the resulting archive, for example:
87
+ > In case you work with a Compose Multiplatform project, use the following Gradle task:
88
+ >
89
+ > ` ./gradlew :composeApp:assembleSharedReleaseXCFramework `
90
+ >
91
+ > You can then find the resulting framework in the ` composeApp/build/XCFrameworks/release/Shared.xcframework ` folder.
92
+ >
93
+ {type="tip"}
94
+
95
+ ### Prepare the XCFramework and the Swift package manifest
96
+
97
+ 1 . Put the ` Shared.xcframework ` folder in a ZIP archive and calculate the checksum for the resulting archive, for example:
85
98
86
99
` swift package compute-checksum Shared.xcframework.zip `
87
100
88
- 4 . <anchor name =" upload " ></anchor > Upload the ZIP file to the file storage of your choice.
89
- 5 . Create a ` Package.swift ` file with the following code:
101
+ 2 . <anchor name =" upload " ></anchor > Upload the ZIP file to the file storage of your choice.
102
+ 3 . Choose any directory and locally create a ` Package.swift ` file with the following code:
90
103
91
104
``` Swift
92
105
// swift-tools-version:5.3
@@ -109,39 +122,71 @@ call to your iOS targets description in the `shared/build.gradle.kts` file:
109
122
)
110
123
```
111
124
112
- 6 . Validate the manifest.
113
- One way to do this is to run the following shell command in the directory with the ` Package.swift ` file:
125
+ 4 . In the ` url ` field, specify the link to your ZIP archive with the XCFramework.
126
+ 5 . [ Optional] If you'd like to validate the resulting manifest, you can run the following shell command in the directory
127
+ with the ` Package.swift ` file:
114
128
115
129
``` shell
116
130
swift package reset && swift package show-dependencies --format json
117
131
```
118
132
119
- The output will describe any found errors, or show the successful download and parsing result if the manifest is correct.
133
+ The output will describe any errors found or show the successful download and parsing result if the manifest is correct.
120
134
121
- 7 . Push the ` Package.swift` file to the repository you settled on earlier . Make sure to create and push a git tag with the
122
- semantic version of the package.
135
+ 6 . Push the ` Package.swift` file to your remote repository . Make sure to create and push a Git tag with the
136
+ semantic version of the package.
123
137
124
- Now that both files are accessible, you can test the import in Xcode:
138
+ # ## Add the package dependency
139
+
140
+ Now that both files are accessible, you can add the package dependency:
141
+
142
+ 1. In Xcode, choose ** File | Add Package Dependencies** .
143
+ 2. In the search field, enter the URL of the Git repository with the ` Package.swift` file inside:
144
+
145
+ ! [Specify repo with the package file](native-spm-url.png)
125
146
126
- 1. Choose ** File | Add Package Dependencies...**
127
- 2. Provide the Git URL for the repository with the ` Package.swift` file.
128
147
3. Depending on the type of your project, the dialog will vary:
129
148
* If you' re making a Swift package, press the **Copy package** button. This will put a `.package` line in your clipboard.
130
149
Paste this line into the [Package.Dependency](https://developer.apple.com/documentation/packagedescription/package/dependency)
131
150
block of your own `Package.swift` file, and add the necessary product to the appropriate `Target.Dependency` block.
132
151
* For other Xcode projects, press the **Add package** button, then select products and corresponding targets for the package.
133
152
153
+ ### Check your setup
154
+
155
+ To check that everything is set up correctly, test the import in Xcode:
156
+
157
+ 1. In your project, navigate to the `ContentView.swift` file.
158
+ 2. Replace the code with the following snippet:
159
+
160
+ ```Swift
161
+ import SwiftUI
162
+ import Shared
163
+
164
+ struct ContentView: View {
165
+ var body: some View {
166
+ VStack {
167
+ Image(systemName: "globe")
168
+ .imageScale(.large)
169
+ .foregroundStyle(.tint)
170
+ Text("Hello, world! \(Shared.Platform_iosKt.getPlatform().name)")
171
+ }
172
+ .padding()
173
+ }
174
+ }
175
+
176
+ #Preview {
177
+ ContentView()
178
+ }
179
+ ```
180
+
181
+ Here, you import the `Shared` XCFramework and then use it to obtain the platform name in the `Text` field.
182
+
183
+ 3. Ensure that the preview is updated with the new text.
184
+
134
185
## Exporting multiple modules as an XCFramework
135
186
136
187
To make code from several Kotlin Multiplatform modules available as an iOS binary, combine these modules in a single
137
188
umbrella module. Then, build and export the XCFramework of this umbrella module.
138
189
139
- <!--TODO remove this note when https://youtrack.jetbrains.com/issue/KT-66565 is fixed-->
140
-
141
- > The name `umbrella` is reserved in Apple development. Don' t use it for the module you are exporting.
142
- >
143
- {type=" note" }
144
-
145
190
For example, you have a `network` and a `database` module, which you combine in an `together` module:
146
191
147
192
1. In the `together/build.gradle.kts` file, specify dependencies and the framework configuration:
@@ -203,8 +248,8 @@ For example, you have a `network` and a `database` module, which you combine in
203
248
./gradlew :together:assembleTogetherReleaseXCFramework
204
249
```
205
250
206
- 5. Follow steps 4–7 from [the previous section](# upload) for `together.xcframework`: archive, calculate the checksum, upload
207
- the archived XCFramework, create and push a ` Package.swift` file.
251
+ 5. Follow steps 4–7 from [the previous section](#upload) for `together.xcframework`: archive, calculate the checksum,
252
+ upload the archived XCFramework, create and push a `Package.swift` file.
208
253
209
- Now you can import the dependency into an Xcode project. After adding the ` import together` directive,
254
+ Now, you can import the dependency into an Xcode project. After adding the `import together` directive,
210
255
you should have classes from both the `network` and `database` modules available for import in Swift code.
0 commit comments