0
# iOS Integration
1
2
Platform-specific integration for embedding Compose Multiplatform in iOS UIKit applications. Provides seamless interoperability between Compose runtime and iOS UIKit framework.
3
4
## Capabilities
5
6
### ComposeUIViewController
7
8
Main entry point for hosting Compose content within iOS UIKit applications.
9
10
```kotlin { .api }
11
/**
12
* Creates a UIViewController that hosts Compose content
13
* @param content Composable content to display
14
* @return UIViewController containing the Compose content
15
*/
16
fun ComposeUIViewController(
17
content: @Composable () -> Unit
18
): UIViewController
19
20
/**
21
* Creates a UIViewController with custom configuration
22
* @param configure Configuration block for customizing the view controller
23
* @param content Composable content to display
24
* @return Configured UIViewController containing the Compose content
25
*/
26
fun ComposeUIViewController(
27
configure: UIViewController.() -> Unit = {},
28
content: @Composable () -> Unit
29
): UIViewController
30
```
31
32
**Usage Examples:**
33
34
```kotlin
35
// Basic usage in iOS app
36
class ViewController: UIViewController {
37
override fun viewDidLoad() {
38
super.viewDidLoad()
39
40
val composeVC = ComposeUIViewController {
41
MyComposeApp()
42
}
43
44
addChild(composeVC)
45
view.addSubview(composeVC.view)
46
composeVC.didMove(toParent = this)
47
}
48
}
49
50
// Advanced configuration
51
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
52
var window: UIWindow?
53
54
fun scene(scene: UIScene, willConnectTo session: UISceneSession, options: UISceneConnectionOptions) {
55
val windowScene = scene as UIWindowScene
56
window = UIWindow(windowScene = windowScene)
57
58
val rootVC = ComposeUIViewController(
59
configure = {
60
modalPresentationStyle = UIModalPresentationStyle.UIModalPresentationFullScreen
61
navigationController?.isNavigationBarHidden = true
62
}
63
) {
64
App() // Your main Compose app
65
}
66
67
window?.rootViewController = rootVC
68
window?.makeKeyAndVisible()
69
}
70
}
71
```
72
73
### UIKitView Integration
74
75
Embed native UIKit views within Compose compositions for seamless native interoperability.
76
77
```kotlin { .api }
78
/**
79
* Composable that embeds a UIKit UIView within Compose content
80
* @param factory Function that creates the UIView instance
81
* @param modifier Compose modifier for layout and styling
82
* @param update Callback for updating the UIView when composition changes
83
* @param onResize Callback when the view size changes
84
* @param onRelease Callback when the view is about to be disposed
85
*/
86
@Composable
87
fun UIKitView(
88
factory: () -> UIView,
89
modifier: Modifier = Modifier,
90
update: (UIView) -> Unit = {},
91
onResize: (UIView, CGRect) -> Unit = { _, _ -> },
92
onRelease: (UIView) -> Unit = {}
93
)
94
95
/**
96
* Typed variant for specific UIView subclasses
97
* @param T Specific UIView subclass type
98
* @param factory Function that creates the typed UIView instance
99
* @param modifier Compose modifier for layout and styling
100
* @param update Callback for updating the typed UIView
101
* @param onResize Callback when the view size changes
102
* @param onRelease Callback when the view is disposed
103
*/
104
@Composable
105
fun <T : UIView> UIKitView(
106
factory: () -> T,
107
modifier: Modifier = Modifier,
108
update: (T) -> Unit = {},
109
onResize: (T, CGRect) -> Unit = { _, _ -> },
110
onRelease: (T) -> Unit = {}
111
)
112
```
113
114
**Usage Examples:**
115
116
```kotlin
117
@Composable
118
fun MapViewExample() {
119
var showUserLocation by remember { mutableStateOf(false) }
120
121
// Embed native MKMapView in Compose
122
UIKitView(
123
factory = {
124
val mapView = MKMapView()
125
mapView.mapType = MKMapType.MKMapTypeStandard
126
mapView
127
},
128
modifier = Modifier
129
.fillMaxWidth()
130
.height(300.dp),
131
update = { mapView ->
132
mapView.showsUserLocation = showUserLocation
133
}
134
)
135
136
Button(onClick = { showUserLocation = !showUserLocation }) {
137
Text(if (showUserLocation) "Hide Location" else "Show Location")
138
}
139
}
140
141
@Composable
142
fun CameraPreviewExample() {
143
UIKitView(
144
factory = {
145
val previewView = UIView()
146
// Setup AVCaptureVideoPreviewLayer
147
val captureSession = AVCaptureSession()
148
val previewLayer = AVCaptureVideoPreviewLayer(session = captureSession)
149
previewView.layer.addSublayer(previewLayer)
150
previewView
151
},
152
modifier = Modifier.fillMaxSize(),
153
onResize = { view, rect ->
154
// Update preview layer frame
155
view.layer.sublayers?.firstOrNull()?.frame = rect
156
},
157
onRelease = { view ->
158
// Cleanup camera resources
159
(view.layer.sublayers?.firstOrNull() as? AVCaptureVideoPreviewLayer)
160
?.session?.stopRunning()
161
}
162
)
163
}
164
```
165
166
### iOS Lifecycle Integration
167
168
Integration with iOS application and view controller lifecycle events.
169
170
```kotlin { .api }
171
/**
172
* Effect that observes iOS application lifecycle events
173
* @param onActive Callback when app becomes active
174
* @param onInactive Callback when app becomes inactive
175
* @param onBackground Callback when app enters background
176
* @param onForeground Callback when app enters foreground
177
*/
178
@Composable
179
fun IOSApplicationLifecycleEffect(
180
onActive: () -> Unit = {},
181
onInactive: () -> Unit = {},
182
onBackground: () -> Unit = {},
183
onForeground: () -> Unit = {}
184
)
185
186
/**
187
* Effect that observes UIViewController lifecycle events
188
* @param onViewDidLoad Callback when view controller loads
189
* @param onViewWillAppear Callback when view will appear
190
* @param onViewDidAppear Callback when view did appear
191
* @param onViewWillDisappear Callback when view will disappear
192
* @param onViewDidDisappear Callback when view did disappear
193
*/
194
@Composable
195
fun IOSViewControllerLifecycleEffect(
196
onViewDidLoad: () -> Unit = {},
197
onViewWillAppear: () -> Unit = {},
198
onViewDidAppear: () -> Unit = {},
199
onViewWillDisappear: () -> Unit = {},
200
onViewDidDisappear: () -> Unit = {}
201
)
202
```
203
204
**Usage Examples:**
205
206
```kotlin
207
@Composable
208
fun LifecycleAwareContent() {
209
var isAppActive by remember { mutableStateOf(true) }
210
211
IOSApplicationLifecycleEffect(
212
onActive = {
213
isAppActive = true
214
// Resume timers, restart animations
215
},
216
onInactive = {
217
isAppActive = false
218
// Pause timers, save state
219
},
220
onBackground = {
221
// Save user data, pause network requests
222
},
223
onForeground = {
224
// Refresh data, resume network requests
225
}
226
)
227
228
if (isAppActive) {
229
ActiveContent()
230
} else {
231
InactiveOverlay()
232
}
233
}
234
```
235
236
### Memory Management
237
238
iOS-specific memory management utilities for proper integration with ARC and autorelease pools.
239
240
```kotlin { .api }
241
/**
242
* Effect that creates an autorelease pool for the composition scope
243
* Essential for managing Objective-C objects in Compose
244
*/
245
@Composable
246
fun AutoreleasePoolEffect()
247
248
/**
249
* Remember function that properly retains iOS objects
250
* @param calculation Factory for creating the iOS object
251
* @return Properly retained iOS object
252
*/
253
@Composable
254
fun <T : Any> rememberIOSObject(
255
vararg keys: Any?,
256
calculation: () -> T
257
): T
258
259
/**
260
* Effect for managing iOS object lifecycle with proper cleanup
261
* @param factory Creates the iOS object
262
* @param onDispose Cleanup callback when object should be released
263
*/
264
@Composable
265
fun <T : Any> IOSObjectLifecycleEffect(
266
vararg keys: Any?,
267
factory: () -> T,
268
onDispose: (T) -> Unit = {}
269
)
270
```
271
272
**Usage Examples:**
273
274
```kotlin
275
@Composable
276
fun IOSObjectManagementExample() {
277
// Proper autorelease pool management
278
AutoreleasePoolEffect()
279
280
// Retain location manager across recompositions
281
val locationManager = rememberIOSObject {
282
CLLocationManager().apply {
283
delegate = LocationDelegate()
284
}
285
}
286
287
// Manage camera capture session lifecycle
288
IOSObjectLifecycleEffect(
289
factory = {
290
AVCaptureSession().apply {
291
// Configure capture session
292
}
293
},
294
onDispose = { session ->
295
session.stopRunning()
296
}
297
)
298
}
299
```
300
301
### Threading and Dispatchers
302
303
iOS-specific threading integration ensuring proper main thread usage for UIKit operations.
304
305
```kotlin { .api }
306
/**
307
* Dispatcher for iOS main thread operations
308
* Ensures UIKit operations run on the main thread
309
*/
310
val IOSMainDispatcher: CoroutineDispatcher
311
312
/**
313
* Dispatcher for iOS background operations
314
* Uses iOS global concurrent queue
315
*/
316
val IOSBackgroundDispatcher: CoroutineDispatcher
317
318
/**
319
* Effect that ensures operations run on iOS main thread
320
* @param block Operations that require main thread execution
321
*/
322
@Composable
323
fun IOSMainThreadEffect(
324
vararg keys: Any?,
325
block: suspend CoroutineScope.() -> Unit
326
)
327
```
328
329
**Usage Examples:**
330
331
```kotlin
332
@Composable
333
fun ThreadingExample() {
334
val data = remember { mutableStateOf<List<String>>(emptyList()) }
335
336
LaunchedEffect(Unit) {
337
// Background data loading
338
withContext(IOSBackgroundDispatcher) {
339
val result = loadDataFromNetwork()
340
341
// Switch to main thread for UI updates
342
withContext(IOSMainDispatcher) {
343
data.value = result
344
}
345
}
346
}
347
348
// Main thread effect for UIKit operations
349
IOSMainThreadEffect {
350
// This automatically runs on main thread
351
UIView.animate(
352
withDuration = 0.3,
353
animations = {
354
// UIKit animations
355
}
356
)
357
}
358
}
359
```
360
361
### Platform Detection
362
363
Utilities for detecting iOS platform characteristics and capabilities.
364
365
```kotlin { .api }
366
/**
367
* iOS platform information
368
*/
369
object IOSPlatform {
370
/** Current iOS version */
371
val version: String
372
373
/** Device model identifier */
374
val deviceModel: String
375
376
/** Whether running on iPad */
377
val isIPad: Boolean
378
379
/** Whether running on iPhone */
380
val isIPhone: Boolean
381
382
/** Whether running in iOS Simulator */
383
val isSimulator: Boolean
384
385
/** Screen scale factor */
386
val screenScale: Float
387
388
/** Whether dark mode is enabled */
389
val isDarkMode: Boolean
390
391
/** Current locale */
392
val locale: NSLocale
393
}
394
395
/**
396
* Composable that provides iOS platform information as state
397
* @return State containing current iOS platform information
398
*/
399
@Composable
400
fun rememberIOSPlatformState(): State<IOSPlatform>
401
```
402
403
**Usage Examples:**
404
405
```kotlin
406
@Composable
407
fun PlatformAdaptiveContent() {
408
val platformState by rememberIOSPlatformState()
409
410
when {
411
platformState.isIPad -> {
412
// iPad-specific layout
413
TwoColumnLayout()
414
}
415
platformState.isIPhone -> {
416
// iPhone-specific layout
417
SingleColumnLayout()
418
}
419
}
420
421
// Adapt to dark mode
422
val colors = if (platformState.isDarkMode) {
423
DarkColorScheme
424
} else {
425
LightColorScheme
426
}
427
428
MaterialTheme(colorScheme = colors) {
429
Content()
430
}
431
}
432
```
433
434
## Error Handling
435
436
iOS-specific error handling and crash prevention.
437
438
```kotlin { .api }
439
/**
440
* Exception thrown when UIKit operations are called off main thread
441
*/
442
class IOSMainThreadException(message: String) : IllegalStateException(message)
443
444
/**
445
* Exception thrown when iOS object lifecycle is violated
446
*/
447
class IOSObjectLifecycleException(message: String) : IllegalStateException(message)
448
```
449
450
## Performance Considerations
451
452
### Memory Management
453
- Use `AutoreleasePoolEffect` for compositions that create many Objective-C objects
454
- Properly dispose of camera sessions, location managers, and other resource-heavy objects
455
- Monitor memory usage with iOS Instruments when using heavy UIKit integration
456
457
### Threading
458
- Always use `IOSMainDispatcher` for UIKit operations
459
- Use `IOSBackgroundDispatcher` for CPU-intensive work
460
- Avoid blocking the main thread in Compose content
461
462
### Resource Cleanup
463
- Implement proper cleanup in `onRelease` callbacks for UIKitView
464
- Use `IOSObjectLifecycleEffect` for objects requiring explicit cleanup
465
- Monitor for memory leaks when bridging between Compose and UIKit