Skip to content

Commit 98e6d62

Browse files
authored
Add missing default router context and lifecycle extensions for ios target (#74)
* Add missing default router context declarations for apple and js
1 parent c844de1 commit 98e6d62

16 files changed

Lines changed: 146 additions & 65 deletions

File tree

README.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,10 @@ class DetailInstance(savedState: SavedStateHandle, detail: String) : InstanceKee
195195
**build.gradle.kts**
196196
```kotlin
197197
fun main() {
198-
val lifecycle = LifecycleRegistry()
199-
val rootRouterContext = RouterContext(lifecycle = lifecycle)
198+
val windowState: WindowState = rememberWindowState()
199+
val rootRouterContext: RouterContext = defaultRouterContext(windowState = windowState)
200200

201201
application {
202-
val windowState: WindowState = rememberWindowState()
203-
LifecycleController(lifecycle, windowState)
204-
205202
Window(state = windowState) {
206203
CompositionLocalProvider(LocalRouterContext provides rootRouterContext) {
207204
MaterialTheme {
@@ -230,8 +227,14 @@ class DetailInstance(savedState: SavedStateHandle, detail: String) : InstanceKee
230227
}
231228
```
232229
> [!IMPORTANT]
233-
> You will need to tie root `RouterContext`'s lifecycle to an `AppDelegate`. See example kotlin app delegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/src/iosMain/kotlin/io/github/xxfast/decompose/router/app/AppDelegate.kt), or swift delegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/ios/ios/AppDelegate.swift). Read more on the docs [here](https://arkivanov.github.io/Decompose/getting-started/quick-start/#ios-with-swiftui)
234-
230+
> You will need to tie root `RouterContext`'s lifecycle to an `AppDelegate`.
231+
> * See Kotlin app delegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/src/iosMain/kotlin/io/github/xxfast/decompose/router/app/AppDelegate.kt),
232+
> * See Swift UIKit AppDelegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/ios/ios/UIKitAppDelegate.swift).
233+
> * See SwiftUI App [here](https://github.com/xxfast/Decompose-Router/blob/main/app/ios/ios/SwiftUIApp.swift).
234+
> * Read more on the docs [here](https://arkivanov.github.io/Decompose/getting-started/quick-start/#ios-with-swiftui)
235+
236+
> [!NOTE]
237+
> To invoke decompose router's `defaultRouterContext()` from swift, you will need to export decompose-router from your shared module
235238
</details>
236239
237240
<details>

app/build.gradle.kts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ kotlin {
3030
it.binaries{
3131
framework {
3232
baseName = "app"
33+
34+
// Only need this if you wish to add your own AppDelegate in swift
35+
export(project(":decompose-router"))
3336
}
3437

3538
executable {
@@ -59,7 +62,8 @@ kotlin {
5962
sourceSets {
6063
val commonMain by getting {
6164
dependencies {
62-
implementation(project(":decompose-router"))
65+
// Only need to add this as api if you wish to add your own AppDelegate in swift
66+
api(project(":decompose-router"))
6367

6468
implementation(compose.runtime)
6569
implementation(compose.foundation)

app/ios/ios.xcodeproj/project.pbxproj

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
/* Begin PBXBuildFile section */
1010
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
1111
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
12-
2152FB042600AC8F00CF470E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* AppDelegate.swift */; };
12+
2152FB042600AC8F00CF470E /* UIKitAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* UIKitAppDelegate.swift */; };
13+
DB85742B2AE2331E0069250C /* SwiftUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB85742A2AE2331E0069250C /* SwiftUIApp.swift */; };
1314
/* End PBXBuildFile section */
1415

1516
/* Begin PBXCopyFilesBuildPhase section */
@@ -28,9 +29,10 @@
2829
/* Begin PBXFileReference section */
2930
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
3031
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
31-
2152FB032600AC8F00CF470E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
32+
2152FB032600AC8F00CF470E /* UIKitAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitAppDelegate.swift; sourceTree = "<group>"; };
3233
7555FF7B242A565900829871 /* ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ios.app; sourceTree = BUILT_PRODUCTS_DIR; };
3334
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
35+
DB85742A2AE2331E0069250C /* SwiftUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIApp.swift; sourceTree = "<group>"; };
3436
/* End PBXFileReference section */
3537

3638
/* Begin PBXFrameworksBuildPhase section */
@@ -74,8 +76,9 @@
7476
children = (
7577
058557BA273AAA24004C7B11 /* Assets.xcassets */,
7678
7555FF8C242A565B00829871 /* Info.plist */,
77-
2152FB032600AC8F00CF470E /* AppDelegate.swift */,
79+
2152FB032600AC8F00CF470E /* UIKitAppDelegate.swift */,
7880
058557D7273AAEEB004C7B11 /* Preview Content */,
81+
DB85742A2AE2331E0069250C /* SwiftUIApp.swift */,
7982
);
8083
path = ios;
8184
sourceTree = "<group>";
@@ -179,7 +182,8 @@
179182
isa = PBXSourcesBuildPhase;
180183
buildActionMask = 2147483647;
181184
files = (
182-
2152FB042600AC8F00CF470E /* AppDelegate.swift in Sources */,
185+
2152FB042600AC8F00CF470E /* UIKitAppDelegate.swift in Sources */,
186+
DB85742B2AE2331E0069250C /* SwiftUIApp.swift in Sources */,
183187
);
184188
runOnlyForDeploymentPostprocessing = 0;
185189
};

app/ios/ios/SwiftUIApp.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// App.swift
3+
// ios
4+
//
5+
// Created by Rajapaksage Isuru Rajapakse on 20/10/2023.
6+
// Copyright © 2023 orgName. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
import app
11+
12+
class DefaultRouterHolder : ObservableObject {
13+
let defaultRouterContext: RouterContext = DefaultRouterContextKt.defaultRouterContext()
14+
15+
deinit {
16+
// Destroy the root component before it is deallocated
17+
defaultRouterContext.destroy()
18+
}
19+
}
20+
21+
class AppDelegate: NSObject, UIApplicationDelegate {
22+
let holder: DefaultRouterHolder = DefaultRouterHolder()
23+
}
24+
25+
@main
26+
struct SwiftUIApp: App {
27+
@UIApplicationDelegateAdaptor var delegate: AppDelegate
28+
@Environment(\.scenePhase) var scenePhase: ScenePhase
29+
30+
var defaultRouterContext: RouterContext { delegate.holder.defaultRouterContext }
31+
32+
var body: some Scene {
33+
WindowGroup {
34+
HomeView(routerContext: defaultRouterContext)
35+
}
36+
.onChange(of: scenePhase) { newPhase in
37+
switch newPhase {
38+
case .background: defaultRouterContext.stop()
39+
case .inactive: defaultRouterContext.pause()
40+
case .active: defaultRouterContext.resume()
41+
@unknown default: break
42+
}
43+
}
44+
}
45+
}
46+
47+
struct HomeView: UIViewControllerRepresentable {
48+
let routerContext: RouterContext
49+
50+
func makeUIViewController(context: Context) -> UIViewController {
51+
return ApplicationKt.HomeUIViewController(routerContext: routerContext)
52+
}
53+
54+
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
55+
}
56+
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
import SwiftUI
22
import app
33

4-
@UIApplicationMain
5-
class AppDelegate: UIResponder, UIApplicationDelegate {
4+
//@UIApplicationMain
5+
class UIKitAppDelegate: UIResponder, UIApplicationDelegate {
66
var window: UIWindow?
77

8-
var rootRouterContext = RouterContextKt.defaultRouterContext()
8+
var rootRouterContext = DefaultRouterContextKt.defaultRouterContext()
99

1010
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
1111
window = UIWindow(frame: UIScreen.main.bounds)
12-
let mainViewController = ApplicationKt.MainUIController(routerContext: rootRouterContext)
12+
let mainViewController = ApplicationKt.HomeUIViewController(routerContext: rootRouterContext)
1313
window?.rootViewController = mainViewController
1414
window?.makeKeyAndVisible()
1515
return true
1616
}
1717

18-
1918
func applicationDidBecomeActive(_ application: UIApplication) {
20-
RouterContextKt.resume(rootRouterContext.lifecycle)
19+
rootRouterContext.resume()
2120
}
2221

2322
func applicationWillResignActive(_ application: UIApplication) {
24-
RouterContextKt.stop(rootRouterContext.lifecycle)
23+
rootRouterContext.stop()
2524
}
2625

2726
func applicationWillTerminate(_ application: UIApplication) {
28-
RouterContextKt.destroy(rootRouterContext.lifecycle)
27+
rootRouterContext.destroy()
2928
}
3029
}
3130

app/src/desktopMain/kotlin/io/github/xxfast/decompose/router/app/Application.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,12 @@ import com.arkivanov.essenty.lifecycle.LifecycleRegistry
1212
import io.github.xxfast.decompose.router.LocalRouterContext
1313
import io.github.xxfast.decompose.router.RouterContext
1414
import io.github.xxfast.decompose.router.app.screens.HomeScreen
15+
import io.github.xxfast.decompose.router.defaultRouterContext
1516

16-
@OptIn(ExperimentalDecomposeApi::class)
1717
fun main() {
18-
val lifecycle = LifecycleRegistry()
19-
val rootRouterContext = RouterContext(lifecycle = lifecycle)
20-
2118
application {
2219
val windowState: WindowState = rememberWindowState()
23-
LifecycleController(lifecycle, windowState)
20+
val rootRouterContext: RouterContext = defaultRouterContext(windowState = windowState)
2421

2522
Window(
2623
title = "App",

app/src/iosMain/kotlin/io/github/xxfast/decompose/router/app/AppDelegate.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package io.github.xxfast.decompose.router.app
22

3-
import com.arkivanov.essenty.lifecycle.destroy
4-
import com.arkivanov.essenty.lifecycle.resume
5-
import com.arkivanov.essenty.lifecycle.stop
63
import io.github.xxfast.decompose.router.RouterContext
7-
import io.github.xxfast.decompose.router.app.utils.registry
84
import io.github.xxfast.decompose.router.defaultRouterContext
5+
import io.github.xxfast.decompose.router.destroy
6+
import io.github.xxfast.decompose.router.resume
7+
import io.github.xxfast.decompose.router.stop
98
import kotlinx.cinterop.BetaInteropApi
109
import kotlinx.cinterop.ExperimentalForeignApi
1110
import platform.UIKit.UIApplication
@@ -34,20 +33,20 @@ class AppDelegate @OverrideInit constructor() : UIResponder(), UIApplicationDele
3433
didFinishLaunchingWithOptions: Map<Any?, *>?
3534
): Boolean {
3635
window = UIWindow(frame = UIScreen.mainScreen.bounds)
37-
window!!.rootViewController = MainUIController(routerContext)
36+
window!!.rootViewController = HomeUIViewController(routerContext)
3837
window!!.makeKeyAndVisible()
3938
return true
4039
}
4140

4241
override fun applicationDidBecomeActive(application: UIApplication) {
43-
routerContext.lifecycle.registry.resume()
42+
routerContext.resume()
4443
}
4544

4645
override fun applicationWillResignActive(application: UIApplication) {
47-
routerContext.lifecycle.registry.stop()
46+
routerContext.stop()
4847
}
4948

5049
override fun applicationWillTerminate(application: UIApplication) {
51-
routerContext.lifecycle.registry.destroy()
50+
routerContext.destroy()
5251
}
5352
}

app/src/iosMain/kotlin/io/github/xxfast/decompose/router/app/Application.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fun main() {
3737
}
3838

3939
@OptIn(ExperimentalDecomposeApi::class)
40-
fun MainUIController(routerContext: RouterContext): UIViewController = ComposeUIViewController {
40+
fun HomeUIViewController(routerContext: RouterContext): UIViewController = ComposeUIViewController {
4141
CompositionLocalProvider(
4242
LocalRouterContext provides routerContext,
4343
) {

app/src/iosMain/kotlin/io/github/xxfast/decompose/router/app/utils/RouterContext.kt

Lines changed: 0 additions & 15 deletions
This file was deleted.

decompose-router/api/android/decompose-router.api

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
public final class io/github/xxfast/decompose/router/DefaultRouterContextKt {
2+
public static final fun defaultRouterContext (Landroidx/activity/ComponentActivity;)Lio/github/xxfast/decompose/router/RouterContext;
3+
public static final fun defaultRouterContext (Landroidx/fragment/app/Fragment;Landroidx/activity/OnBackPressedDispatcher;)Lio/github/xxfast/decompose/router/RouterContext;
4+
}
5+
16
public final class io/github/xxfast/decompose/router/Router : com/arkivanov/decompose/router/stack/StackNavigation {
27
public static final field $stable I
38
public fun <init> (Lcom/arkivanov/decompose/router/stack/StackNavigation;Landroidx/compose/runtime/State;)V
@@ -17,11 +22,6 @@ public final class io/github/xxfast/decompose/router/RouterContext : com/arkivan
1722
public fun getStateKeeper ()Lcom/arkivanov/essenty/statekeeper/StateKeeper;
1823
}
1924

20-
public final class io/github/xxfast/decompose/router/RouterContextExtKt {
21-
public static final fun defaultRouterContext (Landroidx/activity/ComponentActivity;)Lio/github/xxfast/decompose/router/RouterContext;
22-
public static final fun defaultRouterContext (Landroidx/fragment/app/Fragment;Landroidx/activity/OnBackPressedDispatcher;)Lio/github/xxfast/decompose/router/RouterContext;
23-
}
24-
2525
public final class io/github/xxfast/decompose/router/RouterContextKt {
2626
public static final fun getLocalRouterContext ()Landroidx/compose/runtime/ProvidableCompositionLocal;
2727
}

0 commit comments

Comments
 (0)