Skip to content

Add the ability to create action types/actions in only Rust; correctly write actions in Android#2805

Open
Innominus wants to merge 1 commit intotauri-apps:v2from
Innominus:notification-fixes
Open

Add the ability to create action types/actions in only Rust; correctly write actions in Android#2805
Innominus wants to merge 1 commit intotauri-apps:v2from
Innominus:notification-fixes

Conversation

@Innominus
Copy link
Copy Markdown

@Innominus Innominus commented Jun 25, 2025

Code formatter has changed the kt code structure for the edited file. If it's not following guidelines/code format standards I'm happy to remove the extra whitespace changes.

Essentially it seems when writing the actions for an action group, it wasn't writing them the same way it was reading them. So it would add the actions but without an ID/title/input so they would show up blank.

Before:
image
After:
image

This is also what the code might look like when using the new builder syntax for ActionType and Action:

    let action_type = ActionType::builder("action-buttons")
        .actions(vec![
            Action::builder("visible-id", "Visible").foreground(true).build(),
            Action::builder("notification-action-id", "Notification Action Titles")
                .foreground(true)
                .build(),
        ])
        .build();

@Innominus Innominus requested a review from a team as a code owner June 25, 2025 07:59
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Jun 25, 2025

Package Changes Through 3d9f99e

There are 15 changes which include dialog-js with minor, dialog with minor, log with minor, log-js with minor, localhost with patch, barcode-scanner with patch, barcode-scanner-js with patch, http with patch, http-js with patch, nfc with patch, nfc-js with patch, updater with minor, updater-js with minor, upload with minor, upload-js with minor

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
api-example 2.0.38 2.0.39
api-example-js 2.0.34 2.0.35
barcode-scanner 2.4.2 2.4.3
barcode-scanner-js 2.4.2 2.4.3
dialog 2.4.2 2.5.0
dialog-js 2.4.2 2.5.0
http 2.5.4 2.5.5
http-js 2.5.4 2.5.5
localhost 2.3.1 2.3.2
log 2.7.1 2.8.0
log-js 2.7.1 2.8.0
nfc 2.3.3 2.3.4
nfc-js 2.3.3 2.3.4
updater 2.9.0 2.10.0
updater-js 2.9.0 2.10.0
upload 2.3.2 2.4.0
upload-js 2.3.2 2.4.0

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector

@FabianLars
Copy link
Copy Markdown
Member

ah merging v2 into this branch was dumb of me, i didn't see that your commit wasn't signed (please set that up for the future), i just made that harder so it'd be okay for me to skip it just this once :P

sorry for the long silence btw, i was waiting for the ci errors to be resolved and totally forgot about the PR in the meantime.

@Innominus
Copy link
Copy Markdown
Author

Innominus commented Nov 24, 2025

@FabianLars hello! I did even worse and left this for 4 months, I'm so sorry haha. I'll give it a google and fix the signing and get this sorted. Does anything else beyond that need fixing?

Edit: ah the CI stuff is legit not just feature gates breaking things? I'll look into it. Cheers.

@ScottMorris
Copy link
Copy Markdown

I was going to open a PR for fixing the Notification Actions on Android but it looks like you've beat me to it and extended it to Rust, @Innominus! I'll leave my change here in case it is useful haha: ScottMorris@ad0a41a

@FabianLars, I can confirm this is still an issue on Android. I'm currently using a Git reference to my fix to work around this issue.

I'm happy to help if any assistance is needed.

@Innominus Innominus force-pushed the notification-fixes branch 2 times, most recently from 09f5a54 to 8b1ca14 Compare February 19, 2026 10:19
can register them; fix Android incorrectly storing actions in an action
group
@Innominus
Copy link
Copy Markdown
Author

@ScottMorris hello! Yes I've been meaning to come back and sort this out. I think I've sorted signing my commit and hopefully fixing the other issues, but I can't seem to get my original example to build anymore. It's all going a tad wonky haha, I'll dig further into it to make sure this all still works.

@Innominus
Copy link
Copy Markdown
Author

Innominus commented Feb 20, 2026

@FabianLars I think I've fixed up the PR and git is saying my commit is signed now, let me know if that's not the case.

I've mobile gated the impl blocks as they weren't previously. Is the way I've done it the most idiomatic way to do it in the Tauri crate? Happy to fix up anything else if needed.

@ScottMorris
Copy link
Copy Markdown

ScottMorris commented Feb 20, 2026

@Innominus, awesome! I was debugging some notification issues last night and have additional changes to support actions via cold boots and improve the typing within the JS side of the plugin. Perhaps I'll build my updates off your work and we'll have a complete Android Notification Action API surface!

@Innominus
Copy link
Copy Markdown
Author

Innominus commented Feb 20, 2026

@ScottMorris that would be great! The reason I found this issue originally is because I was trying to get notification listening working on the Rust side (it was only in JS land at the time, and it might still be). I have some code that allows you to listen to notifications in Rust now but I was trying to work out how to get it to work when the application is closed. I think there's areas you need to check in the iOS/Android code to check if any notifications were pressed to open the application cold start.
Will be good to cover all areas for notifications on mobile as it's such a big part of the platform!

@ScottMorris
Copy link
Copy Markdown

@Innominus, I haven't looked at the iOS side since I don't have any way to build it, but it looks to have a similar issue.

I've worked out a way to add a queue to Kotlin so that the actions get queued up when they come in from the OS via the receiver and when the plugin attaches in Tauri when it boots it passed the messages along to be process and drains the queue. I worked this out for getting Wear OS messages to work within my application and it seems to work for notifications when I ported the idea over last night.

I wonder if it might be a good idea to build off your PR or add these updates to it? They're a bit out of scope of this current PR but I think between your work on Rust, updating the Kotlin side of the plugin, and reshaping the JS/TS API to match we've covered most cases.

I've also tried to make sure that the iOS Swift types and the Android Kotlin types match, so I'll review the Rust implementation here as well.

@Innominus
Copy link
Copy Markdown
Author

Innominus commented Feb 20, 2026

@ScottMorris ahh thank you for that explanation for how it works with notification queues.
I think maybe we get this PR in and continue work on top. If you put up a PR with your cold start notification changes for Android I can attempt to port it to iOS as I use a Macbook for development and I'd assume cold start notification listening is almost a primary usecase and should exist for both platforms.

@ScottMorris
Copy link
Copy Markdown

@Innominus that's a great idea! I'll have more details when I look into it as I clean things up (there's a gazillion debug messages right now to trace the data flow through the layers of the plugin!)

@ScottMorris
Copy link
Copy Markdown

@Innominus, I just resolved some hurdles with the cold start app notifications within my app. My fixes are still being tidied up after a lot of debugging but they work, which is exciting. I'll clean them up this weekend (de-debug log them and sign the commits) and integrate your changes here for Rust.

I've left comments in the Swift code that should help you review and try out the iOS cold boot updates. I'm not sure if they'll be the same as Android but it looks like they are kinda similar after some research.

@FabianLars, I hope you're doing well and are able to checkout our PRs (mine is pending clean up and creation). I was looking into Kotlin testing with the repo but I don't think it exists today. If you see this soon, is there a logging policy within the repository? Is it ok to have debug logs so others can trace their way through the application architecture? I'm happy to clean everything up, but it has been really cool to see where the flow goes 🙂.

@ScottMorris
Copy link
Copy Markdown

ScottMorris commented Feb 22, 2026

I've prepped my branch for a PR and to integrate your work, @Innominus, when it's in. The changes are here.

v2...ScottMorris:tauri-plugins-workspace:notification-actions-fix

I'm not sure the best way to set this up, if I should make a PR now, or wait for more review in this current PR.

ScottMorris added a commit to liminal-hq/liminal-hq.github.io that referenced this pull request Feb 24, 2026
Adds a new blog post documenting the investigation and resolution of
three separate issues in Tauri's Android notification plugin, surfaced
while building Threshold and addressed as upstream contributions to the
plugin.

**Context**

Tauri's notification plugin allows apps to define action buttons on
notifications (dismiss, snooze, etc.). On Android, these actions were
being silently dropped across all apps using the plugin. The work spans
two repositories: `ScottMorris/tauri-plugins-workspace`
(`notification-actions-fix` branch) and `liminal-hq/threshold`.

**Discovery 1: Action-Group Storage Keying**

`NotificationStorage.kt` was writing action groups using the action
type's string ID as a key suffix (e.g. `"idalarm-actions"`) but reading
them back using numeric indices (`"id0"`, `"id1"`). The keys never
matched, so every action group lookup returned nothing and `actionId`
was always empty on delivery, causing the app-side handler to silently
discard the event.

This issue was first surfaced by @Innominus in June 2025
(tauri-apps/plugins-workspace#2805), who also extended the fix to
support registering action types from Rust. The PR sat unreviewed for
eight months. The post documents the collaboration to get it across the
finish line.

**Discovery 2: Payload Shape Mismatch**

When a notification is reconstructed after a channel reset, or when
extras round-trip through `org.json.JSONObject.toString()` and back, a
`nameValuePairs` wrapper leaks into the serialised output. The Tauri
bridge was passing this through verbatim, causing `actionId` to be
`undefined` in JavaScript. A recursive normalisation pass was added to
the guest JS layer to unwrap the artefact and rebuild a clean
`ActionPerformedNotification`.

**Discovery 3: Cold-Start Timing Gap**

Android fires the `BroadcastReceiver` the moment a user taps a
notification action. On a cold boot, Threshold's Rust core takes ~400ms
to initialise before the event bridge is open. Any action tapped in that
window was lost. The fix introduces a listener-ready handshake: the
Kotlin plugin buffers events in a keyed, persistent queue
(`SharedPreferences`) until the JS layer calls
`register_action_listener_ready`, then drains through the registered
callback. Persisted events survive reloads, are TTL-filtered (24h), and
are deduplicated on restore. The new command is wired into Tauri v2's
permission system.

**Threshold Architecture**

Alongside the plugin work, Threshold's notification architecture was
refactored to match the cleaner model the fixed plugin enables. Action
type ownership was moved to context owners via a provider-based model.
`AlarmNotificationService` was extracted to own the full ringing alarm
lifecycle. The plugin fork is vendored as a git submodule with CI
updated to build it before dependency resolution.
@Blue-Pilkinton-Ching
Copy link
Copy Markdown

Bumping this, I'm keen to have it merged asap for my project!

@ScottMorris
Copy link
Copy Markdown

Hi @Blue-Pilkinton-Ching, I'm working on a companion PR to this one with additional updates that handle when action intents arrive when the app closed and has to go through a cold-boot (on Android right now). Keep an eye out for that one as well.

@Blue-Pilkinton-Ching
Copy link
Copy Markdown

Hi @Blue-Pilkinton-Ching, I'm working on a companion PR to this one with additional updates that handle when action intents arrive when the app closed and has to go through a cold-boot (on Android right now). Keep an eye out for that one as well.

Oh that sounds excellent! I also noticed a problem on IOS with the schedule functionality of notifications, have you run into any problems with this as well?

@ScottMorris
Copy link
Copy Markdown

Oh that sounds excellent! I also noticed a problem on IOS with the schedule functionality of notifications, have you run into any problems with this as well?

Unfortunately, @Blue-Pilkinton-Ching, I only have an Android phone and I develop on Linux so I haven't been able to tryout or develop any iOS versions of my app yet, so I haven't run into this. What I've done in my PR is leave behind notes for how the Android one is implemented so anyone who's able to develop with Swift can bring the Actions core up to parity.

What appears to be happening with scheduling? This might be off topic for this PR, but perhaps it is worth opening an issue. I can point you to where I think the scheduling is happening on iOS. If you have a few cycles you might be able to tinker with it and see if you can find the issue you're experiencing.

func handleScheduledNotification(_ schedule: NotificationSchedule) throws

@ScottMorris
Copy link
Copy Markdown

Hey @Innominus, I've opened #3296 with my updates, it builds directly off your PR here and adds in a few additional Android specific fixes. I've added your changes to a .change markdown file so they get prepped for release once my PR is merged.

I've also opened tauri-apps/tauri-docs#3743 and including an example based on your Rust updates here, I hope that's ok. Feel free to review and comment if things don't look right.

@ScottMorris
Copy link
Copy Markdown

@FabianLars I hope you have some time to checkout @Innominus and my twin PRs. I've build mine, #3296, off this one with the exact same commit base. If there is any rebasing required let us know.

@Innominus
Copy link
Copy Markdown
Author

Hello @ScottMorris thank you for making a documents change PR for my changes as well! That's really appreciated.
I've given it a quick look and it looks good. Might give it another look on my PC.
Cheers.

@ScottMorris
Copy link
Copy Markdown

No problem, I noticed the docs needed updated with the slight modification in the shape of the JS API so I threw in your Rust charge as well. I hope you don't mind. Thanks for taking a look, @Innominus.

I've been thinking about the idea you mentioned about a rust equivalent to the JS onAction callback and I believe I have a good solution to it.

My PR currently just enhances the JS side of things as it lives right now. I'm debating if I should enhance it with the changes to support multiple listeners or wait for another PR. Are you planning on using that feature in the very near future?

@Blue-Pilkinton-Ching
Copy link
Copy Markdown

Thanks for your guys contributions! @ScottMorris I'm using your fork in my project and its working great!

@Innominus Are you working on cold start notification listening for IOS? A project I'm working on needs this soon, so if it might take a while I might look at writing my own implementation that fixes this.

I also actually created another fork off it with fixes for a different bug specific to ios. I haven't contributed to open source before, should I create a PR into tauri-apps/plugins-workspace or into your fork @ScottMorris ?

@Innominus
Copy link
Copy Markdown
Author

Hello @Blue-Pilkinton-Ching.
Feel free to start on the iOS coldstart issue. I will not have time to look at it for a while.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[notification] Interaction buttons do not display text by registerActionTypes

4 participants