Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conference deep link for iOS #1222

Merged
merged 20 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a016e83
Add a confetti deep link for Android
StylianosGakis Mar 29, 2024
a88c168
Add initial conference ID to AppComponent
StylianosGakis Mar 29, 2024
f6d090b
Extract the conferenceId from the deep link and pass to DefaultAppCom…
StylianosGakis Mar 29, 2024
ad36281
Pass a nil initialConferenceId for the iOS client
StylianosGakis Mar 29, 2024
5093f25
add .well_known file
martinbonnin Mar 29, 2024
eb4fbf4
Revert "add .well_known file"
martinbonnin Mar 29, 2024
b2b3e44
Update the deep link to use `https://confetti-app.dev/` as the base url
StylianosGakis Mar 29, 2024
5c0b527
Add a public function on AppComponent to handle deep link
StylianosGakis Mar 29, 2024
87312bb
Add Xcode configuration to handle universal links
StylianosGakis Mar 29, 2024
d3e8d6a
Add //todo for where the iOS deep link code will be added
StylianosGakis Mar 29, 2024
153f9c8
Add the .well-known part necessary for the iOS app
StylianosGakis Mar 29, 2024
65ae1ea
Merge branch 'stylianos/conference-deep-link' into stylianos/conferen…
StylianosGakis Mar 29, 2024
8d0c350
Extract the right parts out of the deep link and pass to AppComponent
StylianosGakis Mar 30, 2024
c88984e
Merge branch 'refs/heads/stylianos/conference-deep-link' into stylian…
StylianosGakis Apr 7, 2024
aec1b4e
Merge branch 'refs/heads/stylianos/conference-deep-link' into stylian…
StylianosGakis Apr 7, 2024
48f0fea
Recreate the iOS app UI on a new deep link incoming
StylianosGakis Apr 7, 2024
407dd24
Merge branch 'refs/heads/main' into stylianos/conference-deep-link-fo…
StylianosGakis Apr 14, 2024
d9c3999
Destroy the old lifecycle before starting a new one
StylianosGakis Apr 14, 2024
c79600a
Remove reRender hack in favor of an ObservableObject
StylianosGakis Apr 14, 2024
9500a8c
Remove extra AppComponentHolder
StylianosGakis Apr 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions iosApp/iosApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
1AF675CF28F1F20B00CC1C26 /* SessionListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionListView.swift; sourceTree = "<group>"; };
1AF675D128F1F21700CC1C26 /* SessionDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDetailsView.swift; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
550D7BF32BB75551004D5D59 /* iosApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iosApp.entitlements; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* Confetti.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Confetti.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF82242A565900829871 /* ConfettiApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfettiApp.swift; sourceTree = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -225,6 +226,7 @@
7555FF7D242A565900829871 /* iosApp */ = {
isa = PBXGroup;
children = (
550D7BF32BB75551004D5D59 /* iosApp.entitlements */,
1A584D0F2B8277440047DDD2 /* Recommendations */,
1AC8AB652AD2997C0067704E /* Venue */,
1AF675CA28F1F0F300CC1C26 /* Speakers */,
Expand Down Expand Up @@ -752,6 +754,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = iosApp/iosApp.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1.0.2;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
Expand Down Expand Up @@ -786,6 +789,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = iosApp/iosApp.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1.0.2;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
Expand Down
22 changes: 18 additions & 4 deletions iosApp/iosApp/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,33 @@
import SwiftUI
import ConfettiKit

class AppDelegate : NSObject, UIApplicationDelegate {
class AppDelegate : NSObject, UIApplicationDelegate, ObservableObject {

let root: AppComponent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could conform AppDelegate to ObservableObject for simplicity? And just make this root property @Published var. Can you try that? If for some reason this is not possible or not working, then maybe move the AppComponent creation and replacing logic to AppComponentHolder?

Otherwise looks good!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeah I didn't try to make AppDelegate an ObservableObject since I wasn't sure if that would be a weird thing to be that and an UIApplicationDelegate at the same time. I will give that a shot.

If that does not work for whatever reason, when you say "maybe move the AppComponent creation and replacing logic to AppComponentHolder" I assume you mean so that AppDelegate just calls a small function in init() and on onConferenceDeepLink so that the bulk of the work is done in there instead.

Will pick this up some next week, hopefully earlier rather than later inside of it. Thanks for the feedback 😊

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when you say "maybe move the AppComponent creation and replacing logic to AppComponentHolder"

Yes. Just create the AppComponent together with its ComponentContext and Lifecycle inside AppComponentHolder. And also add onConferenceDeepLink to AppComponentHolder instead, and call that from AppDelegate. I think this would be cleaner. But the first option with conforming AppDelegate to ObservableObject sounds even better.

Copy link
Collaborator Author

@StylianosGakis StylianosGakis Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey making AppDelegate conform to ObservableObject just worked, after fighting with it for a bit 😅 Thanks for your tips!

private var applicationLifecycle: ApplicationLifecycle
@Published var appComponent: AppComponent

override init() {
KoinKt.doInitKoin()

root = DefaultAppComponent(
componentContext: DefaultComponentContext(lifecycle: ApplicationLifecycle()),
applicationLifecycle = ApplicationLifecycle()
appComponent = DefaultAppComponent(
componentContext: DefaultComponentContext(lifecycle: applicationLifecycle),
onSignOut: {},
onSignIn: {},
isMultiPane: UIDevice.current.userInterfaceIdiom != UIUserInterfaceIdiom.phone,
initialConferenceId: nil
)
}

func onConferenceDeepLink(conferenceId: String) {
applicationLifecycle.destroy()
applicationLifecycle = ApplicationLifecycle()
appComponent = DefaultAppComponent(
componentContext: DefaultComponentContext(lifecycle: applicationLifecycle),
onSignOut: {},
onSignIn: {},
isMultiPane: UIDevice.current.userInterfaceIdiom != UIUserInterfaceIdiom.phone,
initialConferenceId: conferenceId
)
}
}
22 changes: 21 additions & 1 deletion iosApp/iosApp/iOSApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ struct iOSApp: App {

var body: some Scene {
WindowGroup {
ConfettiApp(appDelegate.root)
ConfettiIosApp(appDelegate: appDelegate)
.onOpenURL(perform: { url in
let pathComponents = url.pathComponents
if pathComponents.count != 3 { return }
if pathComponents[1] != "conference" { return }
let conferenceId = pathComponents[2]
for char in conferenceId {
if !char.isLetter && !char.isNumber { return }
}
appDelegate.onConferenceDeepLink(conferenceId: conferenceId)
})
}
.onChange(of: phase) { newPhase in
switch newPhase {
Expand All @@ -26,6 +36,16 @@ struct iOSApp: App {
}
}

struct ConfettiIosApp : View {
@ObservedObject
var appDelegate: AppDelegate


var body: some View {
ConfettiApp(appDelegate.appComponent)
}
}

func scheduleDataRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "refreshData")
request.earliestBeginDate = .now.addingTimeInterval(24 * 3600)
Expand Down
10 changes: 10 additions & 0 deletions iosApp/iosApp/iosApp.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?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>com.apple.developer.associated-domains</key>
<array>
<string>applinks:confetti-app.dev</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ class DefaultAppComponent(
init {
coroutineScope.launch {
if (initialConferenceId != null) {
// todo, consider changing how conference theme colors are decided so that only knowing the conference
// ID is enough to also get the right color
repository.setConference(initialConferenceId, null)
showConference(conference = initialConferenceId, conferenceThemeColor = null)
selectAndNavigateToDeepLinkedConference(initialConferenceId)
} else {
val conference: String = repository.getConference()
if (conference == AppSettings.CONFERENCE_NOT_SET) {
Expand All @@ -81,6 +78,13 @@ class DefaultAppComponent(
}
}

private suspend fun selectAndNavigateToDeepLinkedConference(conferenceId: String) {
// todo, consider changing how conference theme colors are decided so that only knowing the conference
// ID is enough to also get the right color
repository.setConference(conference = conferenceId, conferenceThemeColor = null)
showConference(conference = conferenceId, conferenceThemeColor = null)
}

private fun onUserChanged(uid: String?) {
navigation.navigate { oldStack ->
oldStack.map { config ->
Expand Down
Loading