<https://twitter.com/joreilly/status/1773437212559...
# confetti
j
s
Wouldn’t it be nice to be able to also paste a real Confetti deep link along in those posts so people who have the app installed already can just click it and directly go to the right destination? As far as I can tell right now Confetti does not have any deep link support. From the decompose docs https://arkivanov.github.io/Decompose/navigation/stack/deeplinking/#handling-deep-links it looks like it’d have to be some manual hooking-up, but looks possible. With that said I have no idea how to make it work for iOS, but I have some idea for Android 😄
👍 2
💯 2
Did this quick draft here https://github.com/joreilly/Confetti/pull/1214 Some things to consider as I write in there too: Conference colors from a deep link aren’t known, so maybe something needs to change there in how the colors are fetched. Getting them from the ID instead of having to have them already is one idea. I just made them normal deep links for now which can be tested by doing something like
Copy code
adb shell am start -a android.intent.action.VIEW -d "<confetti://conference/androidmakers2024>"
But they are not clickable out in the wild if there’s just “confetti://conference/androidmakers2024”. As far as I understand. I’ve done this before in our apps where I made
autoVerify
work, by using firebase deep links, where they add the right .well_known files and so on. But in this context I don’t think I can do this alone since I don’t know if we have a url which we can do this for in the first place for Confetti. If someone has initial thoughts on this I would be happy to hear it. I will try to look more into this soon.
j
@mbonnin I think we have URL we can use for this?
m
Conference colors from a deep link aren’t known
Yup, this seems like what @yschimke was also hinting at here https://github.com/joreilly/Confetti/pull/1176#issue-2175635103
👍 1
1
I think we have URL we can use for this?
For the
.well_known
stuff? I don't think we host anything but I can add that
I think we could even aim for
<https://confetti-app.dev/conference/androidmakers2024>
Although TBH for most mobile apps, I wish they did not do this as it's either: • not working well or • not exposing the same feature set as the mobile website
Thinking about this more, I don't think we need a
.well_known
file to support
confetti://
deep links? This is only if we want
https://
deep links but personally I'm fine supporting only
confetti://
for the reasons above
On another topic, awesome feature 😃 👏
🙌 1
s
If we do only support
confetti://
, how do we for example attach the link to the tweet that John did? In a way that people can just click it and go to the right place inside the app? That was my original use case here. Hence why I brought up the https link. If there's a way to make it work with the confetti scheme which I am unaware of them that would be amazing.
m
Looks like you're right, Chrome doesn't support non https:// urls
Wasn't there a way? maybe with
android-app://
or something?
s
Unfortunately I am not aware of any way to do this 😕 Couldn't find something googling for it either so far.
m
I'm almost sure this was possible at some point but maybe that point was like 10 years ago 😅
confetti://
works in Firefox 🙂
😲 1
So I guess Chrome removed support at some point in the last 10 years
Which doesn't help you in the short term. I'll add the
.well_known
file
@John O'Reilly Can you grab the sha256 of the release keystore? Do you still have it around somewhere?
Copy code
keytool -list -v -keystore androidApp/release.keystore
@Stylianos Gakis I just merged
.well-known
for the debug keystore (PR). You should be able to test in a few minutes. Apologies I mistakenly pushed to your branch and reverted after than.
👀 1
And now with release keystores courtesy of @John O'Reilly 💙 https://github.com/joreilly/Confetti/pull/1217
🌟 1
s
Perfect, I see it. Will start looking into it now. So will a deep link now look something like https://confetti-app.dev/conference/kotlinconf2024 For example? Scheme will be
https
The host should be
<http://confetti-app.dev|confetti-app.dev>
Then from then on we are free to do whatever, so in this case the
conference
I feel like makes sense, wdyt?
m
LGTM
s
Okay, will try to implement it this way then and will tell you how it looks 😊
👍 1
y
Just to confirm, the link will work on web as well as on mobile, correct?
s
Optimally yes to avoid exactly the issue that Martin highlights here https://kotlinlang.slack.com/archives/C051P2HUVKP/p1711723050657469?thread_ts=1711657801.535509&amp;cid=C051P2HUVKP Worst case scenario, if the app is not installed, the link should redirect them to https://confetti-app.dev/ so that they can get the app. Would that be reasonable?
y
Short term of course.
long term it depends if the web is a viable client
m
Good incentive to build a web client
If not, we need the feature formerly known as dynamic links I guess?
s
Yeah the biggest use case I had in mind is the upcoming kotlinconf which is quite soon. I would love for the deep link support to be shipped by then so that we can just share https://confetti-app.dev/conference/kotlinconf2024 and it will automatically work for everyone. Given that time-frame and the fact that I don’t know how to create websites we might have to just do the short term solution for that 😄 Yeah in a world without firebase deep links, they even have a little section in their docs which explains some alternatives. Even at work we still use firebase for this and I just know soon we need to do something about it, since they’re sunsetting it in 2025 😄
So a little update, despite the fact that the right keystore is used from
Copy code
getByName("debug") {
  signingConfig = signingConfigs.getByName("confetti")
and that the right SHA is added to the .well-known, so far even after a clean re-install of the app and after adding
<intent-filter android:autoVerify="true">
The app does not seem to automatically pick up that it should handle those links. If I go in the app settings in “Open by default” and I select the link manually the deep link seems to work though with this PR in its current state. https://github.com/joreilly/Confetti/pull/1214
The known problems are definitely the colors, as I mentioned. I also would probably like to get some input from Arkadii as far as Decompose goes and if there will be a problem if there is a deep link which we try to handle while Decompose will at the same time try to restore a previously known state after a process death perhaps? Just something that crossed my mind, not sure if it’s likely to happen or not. And I did nothing for iOS. If we land this for Android I can try and go into unknown lands to see what that would need to support it 🍎
🙌 1
Any deep link experts who might know any of the reasons why this is not automatically picked up on my phone? 👀 I feel like doing all these should be enough: • Adding the right SHA in https://confetti-app.dev/.well-known/assetlinks.json along with the right
dev.johnoreilly.confetti
package name • Adding the right keystore with the aforementioned SHA, which we do here for the debug build which I run locally, which is specified here. I have verified this all with what Martin mentioned here, but with the debug keystoer • Adding autoVerify here https://github.com/joreilly/Confetti/blob/ea69b1a14c3476f2fd9f3cd12e4e96639f2280fa/androidApp/src/main/AndroidManifest.xml#L78 I’ve checked in our Hedvig production/staging/dev app and we’re doing the exact same things too actually as far as I can tell. I will try to run the release version locally as well maybe that changes something Actually don’t think I can do that myself without the right keystore locally etc. We might be able to test this better from internal testing path in play store or something like that instead.
This is what I mean which is not auto-selected
m
You might be able to get some debug data from
adb shell dumpsys
something?
Looks like it's missing the JSON content-type, I'll dig
s
Ah! The file’s content is fine, but it’s not serving it correctly somehow? I tries to do it using
application/octet-stream
instead of
application/json
? Is this a problem with how GitHub is serving this page? Because GitHub pages are used for this afaiu right? It is true btw that when I try to go to the URL for our app, I get the JSON in Chrome and I see the json content there. When I try to do the same with the Confetti url chrome automatically downloads the file instead. edit: And yup, the response for https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://hedvigdevelop.page.link for example looks fine in comparison.
m
It's a Google Cloud Storage thing (the static site is hosted in GCP), I just changed the metadata and invalidated the cache, now need to wait a few minutes
👍 1
Screenshot 2024-03-29 at 19.17.52.png
Should probably put this in code somewhere as well
s
Aha that’s how the website is served, okay. Again I am really clueless about this stuff so sometimes I may be completely off-target with what I assume 😅
m
The static site is here. The contents gets copied to GCP on every merge to main.
thank you color 1
s
https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://confetti-app.dev Seems to return the right things now! Installed the app again (after uninstalling) and the deep link worked! Great work Martin, thanks for taking the initiative and fixing all the right things for this! Btw to get the right content for assetlinks.json file, what documentation did you go through? I will probably need it in the next ~6 months sometime for work, so it’s good if I got the right resources lined up 😄
🎉 2
j
I can publish new version to play store once changes are in
💙 1
m
Nice! Thanks for the nudge!
what documentation did you go through?
There's a doc here but I mainly copy/pasted an example I found somewhere and already lost 😄
😅 1
thank you color 1
Ah, that section here, I just changed the package name and sha256 there
thank you color 1
s
Just writing down things to keep in mind with this release • The colors don’t being a bit off due to the aforementioned problems • Not being 100% sure about the restoration situation as mentioned here for Decompose • If someone deep links to https://confetti-app.dev/conference/notarealconference they get generic errors in all screens, and the only real thing they can do is try to switch conference, but we do not tell them anything about them being in a wrong state in the first place. • The website fall-back not being there right now if the app is not installed None are necessarily a blocker I would say, since it changes nothing if nobody clicks on the link yet if we don’t share any yet 😄
m
I'll add a 404 page, it's highly due
🌟 1
s
Should the 404 have links to the two stores perhaps too? Or is that too weird?
m
I was planning to make it ugly and ask for help 😄
blob think smart 1
s
Who knows how to make websites here? Who made the https://confetti-app.dev page? 😄
m
Copy code
Oh no! This page does not exist or is not supported on the web 😞

Want to help build awesome Kotlin apps? Join us at [link to Github issue]

Just want to see the schedule? Download our [android] and [ios] apps.
1
s
I only see your name in the git blame, so congrats, you are the designated website builder from now on 🌟 😅
😂 1
m
I think I used a generator somewhere
j
@mbonnin are you guys hoping to including Wasm support in Apollo Kotin?
m
It's there already 🤓
Not Wasi but WasmJs is mostly there. I think for what we're doing in Confetti the missing bits are not too important? (websockets are probably missing and a few other things)
j
ah, sorry....thought it had just been in a dev build
m
Latest betas have the target published
👍 1
s
For iOS: I got into the docs here https://developer.apple.com/documentation/xcode/supporting-associated-domains#Add-the-associated-domain-file-to-your-website And looked into how this looks like from firebase for the Hedvig app https://hedvig.page.link/.well-known/apple-app-site-association Then the article here mentions that the identified before the app’s package name is the teamID. So for “appID” it should be “$teamID.$bundleID”. Not 100% confident this is correct, but when I opened the Xcode project, for the team it said “Unknown name (NT77748GS8)” so I assume either “NT77748GS8" is the right name, or something that only exists on my machine for some reason. This we need to ensure before moving forward. From some forum they say that it should be visible under https://developer.apple.com/account/#/membership and then “This will get you to your Membership Details, just scroll down to Team ID”, so I guess John is the only one who can see this to confirm. My biggest issue here is that I do not know if I can test any of this in iOS before the part in /.well-known is on the website. On Android I could just go and do it manuallt from the settings, but I do not see the same anywhere in the simulator settings 👀
So not sure if the only way to properly test this (besides having someone who know what they’re doing in iOS already) is to merge the site changes so that the .well-known part is there and then we can continue our tests. I tried to make the other changes do nothing if the links aren’t setup so I suppose merging won’t be the end of the world? I could make a PR just with that file though if you think that’d be better
m
I'm good to merge . Whichever is easiest
👍 1
s
I did this PR on top of the other android PR, but that’s not merged in either yet. We can merge both to fix this. I am not sure if someone else would like to review that original PR as well before merge. It might stall for a while if people are busy which wouldn’t be ideal 😄
a
Wow, you are so fast!
if there will be a problem if there is a deep link which we try to handle while Decompose will at the same time try to restore a previously known state after a process death perhaps?
This part is explicitly covered in the docs: https://arkivanov.github.io/Decompose/navigation/stack/deeplinking/ I recommend updating Decompose to the latest 3.x alpha, as that "state restoration" problem was already addressed. In this case you can just follow the "Handling deep links since v3.0.0-alpha01" section.
Below that version we would require some workarounds.
s
Since it seems we are using 2.2.2 now, are those workarounds part of the docs somewhere? If not, do you think you can find some time soon to help with this? I can keep this PR on hold till you find some time, I would love to get this right because as I said I want it optimally to work well for kotlinconf 😊 Also are those workarounds in 2.x big enough that it’s perhaps worth it going over to 3.x first? Have you considered doing that in Confetti yet?
a
Can we wait for the first beta release of Decompose? Should be out by the end of next week.
s
Oh 1 week is very soon. I would be happy to wait till then. Are you planning to migrate Confetti soon after that?
a
Yep, could do that.
s
Sounds like a plan. I will play with learning how to do the iOS deep links till then 😅 It might work, I might give up, who knows 😄
🎉 2
What can I say, once you get the ball rolling, it’s easy to just keep going 😄 This PR https://github.com/joreilly/Confetti/pull/1222 now contains the code necessary to have what the attached video shows. The same rules apply here, that it’d be nice to get to Confetti 3.x to treat treat restoration well. Along with the extra caveat for iOS that we do not have the URL at startup time, so it can not be passed to the constructor of the AppComponent, but now I have added a new function to accept the deep link. Again by looking at what the Decompose docs suggest here.
j
Amazing work.....think there's definitely a blog article needed next :)
☝️ 1
a
Quick update: Decompose 3.0.0-beta01 is out, I'm going to make a PR with Decompose update soon.
decompose 2
👍 2
s
Amazing, looking forward to it. Ping back here when it's up 😊
a
s
Oh, that was fast 😅
K 2
Will try to build the deep linking stuff on top of this then, along with the process restoration stuff as the docs show for 3.x
👍 2
a
The update has been merged, thanks @John O'Reilly! It should be now possible to rebase and use the new API.
s
https://github.com/joreilly/Confetti/pull/1214 contains discarding the state on deep link for Android For iOS I don’t see how I can do that actually. The URL we get on Android onCreate before we have the DefaultComponentContext initialized and all. On iOS in comparison, we get the deep link in a “modifier” on the SwiftUI view, that is after the component was created in the first place. This PR https://github.com/joreilly/Confetti/pull/1222/files shows a bit of how this is done. Is this something you’ve tried before and have a better alternative? One option is to just let it be like this, so a deep link would be on top of whatever stack you had before for iOS, until someone comes up with a better idea/approach. So that we do not only ship deep links for one platform. The other is to only merge Android for now and then hope that someone knows how to do this better on iOS?
a
Yeah, it would be nice to recreate the root component somehow when a link is received.
s
Aha, okay let me look into that.
j
@Stylianos Gakis are you happy to have PR merged is right now (and potentially could follow up with iOS changes)?
I can publish update to play store then (internal testing channel initially)
s
I’ve been trying to get this scenario working on Android which doesn’t seem to be handled atm with the provided snippet over here https://arkivanov.github.io/Decompose/navigation/stack/deeplinking/#handling-deep-links-since-v300-alpha01 So if you: • Have the app closed • Open the app with a deep link to kotlinConf2024 for example • While In the app, navigate to another conference • Go to home, keeping the app running in the background • Use AS to kill the app’s process • Go to recents and open the app again. Then the intent for kotlinConf is delivered to the app again, and isntead of restoring to whatever conference you were at before, it clears that state and goes to kotlinconf again. Doing
Copy code
if (initialItemId != null) {
  intent = Intent(intent).setData(null) // The deep link has been handled, clear the Intent data
}
As the docs suggest dos not seem to be enough. I think there might be something I can do by looking at the intent flags.
a
Hmm, I would expect the intent data to be cleared regardless. What if you launch second time via home icon?
You can check if the app was launched from the history by checking the intent flag: Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
s
Doing it directly after process death seems to still keep the FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY flag not set. I could be doing something wrong though, I am actively trying to resolve this atm
a
Looking at https://stackoverflow.com/questions/4116110/clearing-intent/41381757 Maybe just call intent.setData(null)?
Assuming that you are using intent data to parse the deep link
s
Indeed if I instead open the app from HOME after the process death then the deep link is not delivered to the app again, as you suspected.
Maybe just call intent.setData(null)?
WIll try this too
Nope, this exact flow still receives the deep link, even with
intent.setData(null)
. And at that same “after process death” scenario, this
Log.d("Stelios", "Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY was ${intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY}")
prints “Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY was 0”, so I do not get that flag either to help me distinguish this scenario
a
Can I see the code?
s
The way androidx.navigation https://slack-chats.kotlinlang.org/t/507756/i-have-an-app-using-compose-navigation-and-it-is-handling-a-#6e4a4649-db78-4d2e-a1cf-ea6e686bd872 seems to be doing this is by themselves manually setting a boolean to a place which is persisted across process death, some code here https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:navigati[…]ime/src/main/java/androidx/navigation/NavController.kt;l=2568 for this. They do not rely just on these flags
a
Good idea. This might be changed in the recent versions of Android. As I remember clearing the intent worked some time ago.
s
a
I will update the docs once we know all the details.
👍 1
Thanks, the code looks exactly how I would do it. Happy to update the docs later.
Let's try ALSO saving a flag?
👍 1
s
Yeah will try this too, gotta figure out how to do it. For now I will just write here the scenario and the logs that come along with it just to make it make sense 😄
So the logs kinda go: Start the app normally:
Copy code
Intent.FLAG_ACTIVITY_NEW_TASK was 268435456
Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY was 0
initialConferenceId:null
Then kill the app from recents. Then open the app through a deep link:
Copy code
Intent.FLAG_ACTIVITY_NEW_TASK was 268435456
Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY was 0
initialConferenceId:androidmakers2024
Then go to some other conference in the app, like SHEDEV Warsaw. Then go to home Then kill the process in AS Then open the app from recents:
Copy code
Intent.FLAG_ACTIVITY_NEW_TASK was 268435456
Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY was 0
initialConferenceId:androidmakers2024
So the initial id comes again as androidmakers2024, and this overrides the process restoration, so you end up in androidmakers2024 again, despite just having left the app from SHEDEV. 👍
a
Maybe something like this?
s
Sorry for the delay. I can confirm this works! Wow I am so happy, will try to untangle my commits a bit now and push them to the right PRs since I was working on the iOS thing at the same time, gimme a few minutes. After we merge and we’re happy with this you can probably take this logic and put it in the docs of decompose too!
🎉 1
a
Yay! Thanks!
s
https://github.com/joreilly/Confetti/pull/1214 is ready to be merged IMO. I mean I even tested process death and rare scenarios like that. At this point if there are bugs I think I am blind to them, someone else (internal testing as you mentioned John 👀) would have to test the app instead 😄 For iOS https://github.com/joreilly/Confetti/pull/1222 I feel like with this the SwiftUI gods will come down to strike me and revoke my license to write SwiftUI code. So apparently, with my current knowledge I could not find a way to just do something like we do with
remember { mutableStateOf(whatever here) }
. So I could not put the AppComponent in a way to make it observable so that when it changes the whole app will “recompose” so that it will use the new AppComponent which I am setting when the deep link comes. Instead I did this hack where I trigger the “recomposition” with something that can in fact be observer, so then the new
AppComponent
is picked up. I would really appreciate some help here from someone with more SwiftUI experience on how to not make this big hack
👍 1
j
Publishing new version to play store now with those changes
@Stylianos Gakis v1.0.233 in internal testing channel in play store now...and works great!
I'll do a bit of sanity testing but if we're happy with this I can promote to production
a
Re iOS: I think we need to also destroy the previous component's Lifecycle, which is not currently possible since ApplicationLifecycle doesn't have such an API. I will think about adding a destroy method to it. Also as an idea, I think there should be a way to make the root component properly observable. I don't remember the exact way, but there definitely is.
Create a holder class that confirms to ObaervableObject, with a mutable Published property holding the component.
Just an idea, not sure if it would work, the way might be actually different.
s
Yeah I really feel like there should be a way too, I just did not manage to get it to work. Definitely my inexperience with SwiftUI playing the biggest role there. I tried once to do exactly what you say with an ObservableObject wrapper, but I just didn’t get it to work. I probably did it wrong tbh, I will look more into it. Regarding killing the old lifecycle, is that smth that Decompose would need to expose in some way, or something we can do already? In any case, turned that PR back into a draft for now.
a
Destroying ApplicationLifecycle is not currently possible, I will try adding this feature. We could do it manually by using LifecycleRegistry and calling it's events, but I think it's just better to wait for an update from my side.
s
Yeah I would be happy to do exactly that then, wait for that update for the iOS PR. Also super glad to discover a new use case here hehe. Just in time for Decompose 3.x 😄
👍 1
j
Update is live in Play Store now (production)
K 2
a
The Decompose update with ApplicationLifecycle improvements should be out today or tomorrow.
🥳 1
s
Btw the deep link works exactly as it should when coming from an app like Tusky (Mastodon) Doing it from the twitter website from the Chrome browser, that also works perfectly fine. When doing the same from the Twitter Android app however, it somehow, not sure what kind of flags it sets or whatever but if the app was already open it will open this deep link on top of that, so going back will take you to wherever you were at before in the Confetti app you had open. It’s kinda like having 2 Tasks of Confetti on top of each other. I have no idea what Twitter does to break this btw 😅 But the link seems to work 100% of the time, no problem with that, just that the backstack then has that old version of the app running “behind” it 😄 So: Open the Confetti app normally and go to some conference Then go to Twitter android app and click the deep link to some OTHER conference from the one you had open before Now do back gesture, and you’ll notice instead of going back to Twitter as you should, you go back to whatever other screen you were in. And that one had it’s own task completely, so it’s own decompose backstack and so on. (tested that by doing Switch conference first before going back, which should replace the entire backstack, but still going back takes you back to that OTHER task of Confetti) I’m just gonna blame twitter app for this one tbh 😅
Ok and I tried to do the same in LinkedIn https://www.linkedin.com/posts/stylianos-gakis_confetti-apps-on-google-play-activity-7183138418611167232-AOUw and there it does not work at all, it opens a chrome web view in the app in some way and it just defaults to going to the confetti website, I just removed the link from this post now 🤷‍♂️
a
Maybe we need to specify some intent flags in AndroidManifest?
So that there is only one instance of activity, and the new intent is delivered via onIntent instead.
s
I was going off of this documentation basically https://developer.android.com/guide/navigation/design/deep-link#handle where they strongly suggest to use the default launchMode in the app in order to let Android do its own thing. And FWIW I just tested doing the same with the Hedvig app (from Twitter again, which is the problematic one) which also does use the default launch mode https://github.com/HedvigInsurance/android/blob/a72279543f5811216b539ff0844ff7db2ae4133e/app/app/src/main/AndroidManifest.xml#L34-L39 and it does not experience the same behavior. If the app was open before, the app opens and navigates to that place. And going back just does the normal app navigation and exits the app. It does not also have a second instance of the Hedvig app running behind itself. (For LinkedIn it's the same experience, fallback to the website, they're doing something super odd there) So the verdict must be that androidx.navigation is doing more that just what we added here to support even when apps like Twitter are passing in whatever flags that they are passing, right?
In my endeavor to understand this more, apparently the LinkedIn app has a switch which unfortunately is in the "wrong" state by default, but once you flip it yourself you again get the right experience, like in Tusky for example. Damn, android deep links really are complicated huh 😅
a
and you’ll notice instead of going back to Twitter as you should, you go back to whatever other screen you were in
What exactly do you mean by "other screen"? Maybe you could share a video?
I think if without any intent flags, when you open Confetti app normally, and then open it again via a deep link, then there is a second activity task created. I don't think this is something that could be handled by a navigation library.
> It does not also have a second instance of the Hedvig app running behind itself. I believe there must be an intent flag preventing the new activity task from being created, and reusing the existing one instead. Though, I don't see it in the manifest. Maybe there is something else there.
s
screen-20240408-193919.mp4
Maybe this is the way how that app handles the case? https://github.com/HedvigInsurance/android/blob/a72279543f5811216b539ff0844ff7db2ae4133e/app/app/src/main/kotlin/com/hedvig/app/feature/loggedin/ui/LoggedInActivity.kt#L280
No that one is only used for the login flow, it's a leftover from never picking up the work to bring the login flow into one activity. This is never called in deep link handling
a
Thanks for the video! As far as I can see, there is a second activity instance being created. I'm not aware of any way how we could have only one instance without activity flags.
s
Yes, a separate task is normally created, and in all other cases except for Twitter, that task is still in the app you came from. Hence if you go to recents you will still see that app's logo while you are inside the app you were deep linked into. Then Twitter does something different, not sure what. But androidx.navigation probably there picks up this scenario and does something with that old app task. Perhaps it kills it? In any case, here's the video of the Hedvig app doing the same order of events, but not keeping the old task there.
All this is based on https://developer.android.com/guide/navigation/principles#the_up_button_never_exits_your_app which the Twitter app somehow breaks for themselves for some reason 😬
a
> But androidx.navigation probably there picks up this scenario and does something with that old app task. I would love to know how is it possible to touch another activity task.
s
Yupp, I was also looking at the same place. It's where I found this trick with the savedStateHandle in the first place tbh. I guess we can (sorta) figure this out if we open a Twitter link to our debuggable confetti app and see if they actually try to open the app with these two flags
Copy code
Intent.FLAG_ACTIVITY_NEW_TASK
Intent.FLAG_ACTIVITY_CLEAR_TASK
And then we can be more sure about it. Give me a bit of time and I'll be back on the computer to check this out
a
Just FYI, the NavController checks:
Copy code
flags and Intent.FLAG_ACTIVITY_NEW_TASK != 0 &&
            flags and Intent.FLAG_ACTIVITY_CLEAR_TASK == 0
thank you color 1
Ok, looking at the Hedvig video, when pressing the back button - the app is closed and the home screen is shown, not Twitter. Also the Hedvig screen shows the "old" screen for a second, then shows the deeplink. We can achieve the same behaviour if we want with the following patch.
s
> the app is closed and the home screen is shown > Also the Hedvig screen shows the “old” screen for a second Yes this is what happens with Twitter in particular because they’re sending the weird flags. Through a normal app which does not mess up things this way this is the behavior instead:
👍 1
Arkadii I got some time now to test the snippet you suggested above and it does exactly what we wanted. I tried to test as much as possible and I am really happy with it now! https://github.com/joreilly/Confetti/pull/1273 Thanks for your help with this!
a
Yay! Glad it helped! So now we only need to finish the iOS side? We still need to merge https://github.com/joreilly/Confetti/pull/1249 first. Cc: @John O'Reilly
j
just merged
🥳 2
(both of them)
is https://github.com/joreilly/Confetti/pull/1222 ready to be merged as well (once build passes)?
s
Renovate had already taken care of bumping to essenty beta02 so I had just started looking into it. Added 2 commits here https://github.com/joreilly/Confetti/pull/1222 and I managed to make it work with an
ObservableObject
too and no re-render hacks like before! Arkadii could you take a look at those too perhaps? I tried to look into this commit https://github.com/arkivanov/Essenty/commit/19072367b9fd4cde486ed7133f244ff7db6f27ba to check if I am using the
.destroy()
API correctly, but I can’t say I am 100% confident with it without an OK from your side too
So if Arkadii approves the way I am using this new Essenty API I think we are good to go John 😊
👍 1
a
I will take a look today or tomorrow 👍
s
Thank you! Here’s a quick link to jump to the place I wanted your input on whenever you find the time, no rush on my end 😊 https://github.com/joreilly/Confetti/blob/c79600a8f2d0f992d2756bcca8466909c5a8b9a0/iosApp/iosApp/AppDelegate.swift#L14-L35
a
Looks good! I've left one comment.
s
Arkadii, thanks so much again for all the feedback, especially on the iOS parts which I was really clueless about 😅 CI seems to be passing now, Arkadii has approved the 1222 PR, so I think we can merge this and start testing it on real iOS devices 🥳 Btw does Confetti have any sort of Testflight setup, or do we release to Play Store when we want to test new builds?
K 1
j
Just submitted to App Store for review
It would have also been submitted to TestFlight but haven't really been using that so far
If anyone wants to give me their email address I can add them as testers
Screenshot_20240416-124050.png
🥳 2
It's faster than play store these days 😃
kodee sad 1
😀 1
💯 1
s
Of course the link does not work from Twitter, why would anything just work for once? bored party parrot The good news is that the link does in practice work, as seen in this video when clicked from the Notes app! And in this case here I am not sure if it’s Twitter who’s doing weird things, as it was doing for Android as well, or if it’s some expected iOS behavior that I am not familiar with ☠️
FWIW it also fails on iOS when trying to open the link from the official Mastodon iOS app. Is it that both apps do something weird, or that it’s hard to support that properly the way that notes does for iOS? Not quite sure, but it is what it is.
m
Mmm the CSS is somehow wrong on that page 👀
👀 1
s
Btw it also does not work from inside the Mastodon app But it does work from Safari! So the link looks to be perfectly usable from our end. I suspect the problem is with what Twitter and Mastodon iOS apps do to handle the URL. Could be wrong, but unless someone knows a lot more about this, then I will consider this mini-project a success and done on our end.
Deep links to specific conferences on Confetti are here and working for both platforms in their latest releases, it is officially done 🥳
🎉 3
👏 1
🔗 1
a
@Stylianos Gakis I'm thinking about extracting some code for deep link handling on Android to Decompose, so that it could be reused. I created a draft
withDeepLink
function, which in theory could be moved to Decompose. Wondering what's your opinion on this approach?
@Stylianos Gakis I'm still looking for your feedback, if you can 🙂
s
Hey sorry about the delay, I know you're waiting for me, I wanted to look into it more soon but I got a serious case of elbow pain out of the blue this week and I decided to give it a rest, since typing on my keyboard is painful 😣 Good thing the keyboard on Android with swiping gestures exist, so I can write this with one hand here at least 😅 I'll probably be fine by tomorrow
a
Oh, no rush! Take your time and get well soon!
thank you color 1
s
Really like the change you did by using the
savedStateRegistry
, it was interesting. I had some comments around there, some out of curiosity and one because I was not sure I was following the new flow properly, so I am not 100% sure if it’s a real problem or if I am misunderstanding it. But all in all this is looking great, perhaps it is also going to make moving these functions to the decompose docs much easier. And leave the clients then do the
extractConferenceIdOrNull
part themselves, for whatever deep links they got.
a
@Stylianos Gakis Thank you for your comments! I've answered all of them. Also I have already added the new
withDeepLink
function to Decompose, and I'm going to release the new version soon. We could then update Confetti as well and see how it works. I've checked it manually already, seems to work fine, but I might be missing some corner cases. See: https://github.com/arkivanov/Decompose/pull/701
Btw, @Stylianos Gakis I'm wondering if we actually need that logic with saving whether we handled the deep link previously or not. We are saving that flag because you can open the app via a deep link, then navigate somewhere else, then put the app in background, then the app is killed, then you can open it again. And we can again receive the deep link in the intent. And so we tried to remember the fact that we already handled the deep link. Now I'm thinking there might be an issue. If we open the app a second time via the same deep link, we want to handle the deep link. But it might be ignored because of the saved flag?
How both scenarios work in Hedvig?
s
I think the scenario where you open the app again with a new deep link, you will either be in a separate task (inside the app you came from) so in there you won’t have any saved state afaik. And the other scenario is when they open it with those specific flags where the activity is recreated anyway. Is there a third scenario other than those two here that I am missing you think?
a
Perhaps that's all. I will try it anyway.
👍 1
@Stylianos Gakis Do you use Telegram? Could you please check the following use case with Hedvig for me? Force stop the app. Open https://confetti-app.dev/conference/kotlinconf2024 from a Telegram message (e.g. post the link in your Saved Messages and click on it) Navigate somewhere else. Minimize the Confetti app. Click on the link in Telegram again. Does it handle the deep link the second time? Or it just opens Confetti on whatever screen it was left?
s
I don’t actually have/use telegram 👀 Does that do something special over for example opening the link from Google Keep for example? Like Twitter does something special too?
a
Yes. Keep opens Confetti in its own Activity stack. Whereas Telegram opens in a separate stack.
s
But also does not do it the way Twitter does, which is to set those two flags in that way so we reset the activity completely? If yes I will download telegram just to test Hedvig from it too 😅
a
Ah yes, you are right. Twitter has the same behaviour. So it's ok that the deep link is not handled on the second click? In the case I described right above
s
So despite doing this whole activity recreation dance, if you’ve opened the app once with a deep link this way, and then navigated somewhere else. If you then go to twitter (without closing the app) and click that link again, then you just go back to the app without navigating to the deep link again?
a
Yep! And I'm wondering how other apps with official navigation and without activity flags (as recommended in the doc) work.
E.g. Hedvig. I assume it should work the same.
yes black 1
s
Heh, would you look at that. This is in fact true. Repro is exactly what you said (tested with Hedvig production app) • Force close the app • Click on deep link from Twitter • Inside the app, do any navigation to somewhere else • Switch to Twitter (keep app open) and click on the deep link again • Notice that the app comes in the foreground again, however you are not redirected to the deep link again, you just stay where you left off last time. This might be worth a bug report tbh, to see if this is expected behavior or not, which I doubt it is.
a
Yeah! I checked with Confetti. None of onCreate and onNewIntent are called. The app is just brought to foreground.
Then I think there is nothing we can do in this case. I will release a new version of Decompose soon. And update Confetti accordingly. Will ping you for review.
🌟 1
Here we go. Updated Decompose to 3.0.0 and used the new handleDeepLink API. https://github.com/joreilly/Confetti/pull/1316
🎉 2
decompose 1