Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ jobs:
- name: Run Android unit tests with coverage
run: |
cd android
./gradlew clean testDebugUnitTest jacocoTestReport --stacktrace --no-daemon
./gradlew clean testGmsDebugUnitTest testFossDebugUnitTest jacocoTestReport --stacktrace --no-daemon

- name: Upload coverage to Codecov
if: ${{ github.actor != 'dependabot[bot]' }}
Expand Down Expand Up @@ -183,7 +183,7 @@ jobs:
profile: pixel_6
disable-animations: true
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
script: cd android && ./gradlew clean connectedDebugAndroidTest --stacktrace --no-daemon
script: cd android && ./gradlew clean connectedGmsDebugAndroidTest --stacktrace --no-daemon

- name: Upload instrumented test results
uses: actions/upload-artifact@v7
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,20 @@ Listens for notification action performed events.

### Android Setup

The plugin ships `gms` and `foss` flavours, so every consuming app must pick one
in `gen/android/app/build.gradle.kts`:

```kotlin
android {
defaultConfig {
missingDimensionStrategy("push", "gms") // or "foss"
}
}
```

`foss` drops Firebase Cloud Messaging and the embedded FCM distributor, for
builds shipped through F-Droid or IzzyOnDroid; push then uses UnifiedPush only.

1. The plugin automatically includes required permissions
2. For custom sounds:
- Place sound files in `res/raw/` folder
Expand Down
13 changes: 7 additions & 6 deletions android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ android {
buildConfigField("boolean", "ENABLE_PUSH_NOTIFICATIONS", "$enablePush")
}

// FCM pulls proprietary Google libraries that FOSS repos reject. The foss
// flavour drops them, leaving UnifiedPush as the only transport.
// FCM pulls proprietary Google libraries that FOSS repos reject.
flavorDimensions += "push"
productFlavors {
create("gms")
Expand Down Expand Up @@ -109,8 +108,9 @@ dependencies {
implementation(project(":tauri-android"))
}

// gms only: aggregating both flavours gives Jacoco two FcmBridge classes at one FQN.
tasks.register<JacocoReport>("jacocoTestReport") {
dependsOn("testDebugUnitTest")
dependsOn("testGmsDebugUnitTest")

reports {
xml.required.set(true)
Expand All @@ -127,18 +127,19 @@ tasks.register<JacocoReport>("jacocoTestReport") {
"android/**/*.*"
)

val debugTree = fileTree("${layout.buildDirectory.get().asFile}/tmp/kotlin-classes/debug") {
val debugTree = fileTree("${layout.buildDirectory.get().asFile}/tmp/kotlin-classes/gmsDebug") {
exclude(fileFilter)
}

val mainSrc = "${project.projectDir}/src"

sourceDirectories.setFrom(files(listOf(
"$mainSrc/main/java",
"$mainSrc/main/kotlin"
"$mainSrc/main/kotlin",
"$mainSrc/gms/java"
)))
classDirectories.setFrom(files(debugTree))
executionData.setFrom(fileTree(layout.buildDirectory.get().asFile) {
include("outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec")
include("outputs/unit_test_code_coverage/gmsDebugUnitTest/testGmsDebugUnitTest.exec")
})
}
6 changes: 3 additions & 3 deletions android/src/main/java/app/tauri/notification/FcmResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ package app.tauri.notification
sealed class FcmTokenResult {
data class Success(val token: String) : FcmTokenResult()

/** The request ran and failed. Unlike [Unavailable], this triggers `push-error`. */
/** Ran and failed. Unlike [Unavailable], triggers `push-error`. */
data class Failed(val message: String) : FcmTokenResult()

/** Firebase is absent or threw before the request ran. */
/** Firebase absent, or threw before the request ran. */
data class Unavailable(val message: String) : FcmTokenResult()
}

sealed class FcmDeleteResult {
object Deleted : FcmDeleteResult()
data class Failed(val message: String) : FcmDeleteResult()

/** No default FirebaseApp, so there was nothing to delete. */
/** No default FirebaseApp: nothing to delete. */
object NotConfigured : FcmDeleteResult()
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ class UnifiedPushNotifierTest {
val posted = shadowNotificationManager().getNotification(null, canonicalId("!enc:example.org"))!!
assertTrue(posted.extras.getString(Notification.EXTRA_TEXT)!!.contains("decrypted"))
assertEquals("Room 1", posted.extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE))
// The repost must not alert again.
assertTrue(posted.flags and Notification.FLAG_ONLY_ALERT_ONCE != 0)
} finally {
unmockkObject(PushPayloadDecryptor)
}
Expand Down Expand Up @@ -318,7 +320,8 @@ class UnifiedPushNotifierTest {
// A tagged lookup for the same id must find nothing: warm
// enrichment/clear uses the untagged key (null, id).
assertNull(shadowNotificationManager().getNotification("!r1:example.org", id))
assertTrue(posted!!.flags and Notification.FLAG_ONLY_ALERT_ONCE != 0)
// A first cold push must alert; only the silent repost sets ONLY_ALERT_ONCE.
assertTrue(posted!!.flags and Notification.FLAG_ONLY_ALERT_ONCE == 0)
assertTrue(posted.flags and Notification.FLAG_AUTO_CANCEL != 0)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ android {
targetSdk = 36
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
// The plugin has a gms/foss flavour dimension; consumers must pick one.
missingDimensionStrategy("push", "gms")
}
buildTypes {
getByName("debug") {
Expand Down
4 changes: 2 additions & 2 deletions src/desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,11 @@ impl<R: Runtime> Notifications<R> {
}

#[allow(clippy::unused_self)]
pub fn is_ignoring_battery_optimizations(&self) -> crate::Result<bool> {
pub const fn is_ignoring_battery_optimizations(&self) -> crate::Result<bool> {
Ok(true)
}

pub fn request_ignore_battery_optimizations(&self) -> crate::Result<()> {
pub const fn request_ignore_battery_optimizations(&self) -> crate::Result<()> {
Ok(())
}

Expand Down
3 changes: 3 additions & 0 deletions src/mobile.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Async on every target for a uniform API; some platform branches never await.
#![allow(clippy::unused_async)]

use serde::de::DeserializeOwned;
use tauri::{
AppHandle, Runtime,
Expand Down
Loading