Update UnifiedPush library (#4358)

* Upgrade `com.github.UnifiedPush:android-connector` from 2.4.0 to 3.0.4

* Do not use jitpack to get the unified push library

* implementation is ok

* Exclude com.google.crypto.tink to fix a compilation issue

* Fix tests.

* Update log.

* Revert "Exclude com.google.crypto.tink to fix a compilation issue"

This reverts commit f431ebe3b78a06282e0ee74c9f428702d463df45.

* Fix compilation issue after rebase.

* Exclude com.google.crypto.tink again.

* Try version 3.0.8

* Use latest version 3.0.9

* Replace tink exclusion with dependency resolution

---------

Co-authored-by: Jorge Martín <jorgem@element.io>
This commit is contained in:
Benoit Marty 2025-05-26 14:56:54 +02:00 committed by GitHub
parent df77dc873a
commit 819d9c7da0
8 changed files with 52 additions and 22 deletions

View file

@ -354,3 +354,12 @@ fun Project.configureLicensesTasks(reportingExtension: ReportingExtension) {
} }
} }
} }
configurations.all {
resolutionStrategy {
dependencySubstitution {
val tink = libs.google.tink.get()
substitute(module("com.google.crypto.tink:tink")).using(module("${tink.group}:${tink.name}:${tink.version}"))
}
}
}

View file

@ -177,7 +177,7 @@ sqldelight-driver-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.
sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" } sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
sqlcipher = "net.zetetic:android-database-sqlcipher:4.5.4" sqlcipher = "net.zetetic:android-database-sqlcipher:4.5.4"
sqlite = "androidx.sqlite:sqlite-ktx:2.5.1" sqlite = "androidx.sqlite:sqlite-ktx:2.5.1"
unifiedpush = "com.github.UnifiedPush:android-connector:2.4.0" unifiedpush = "org.unifiedpush.android:connector:3.0.9"
otaliastudios_transcoder = "com.otaliastudios:transcoder:0.11.2" otaliastudios_transcoder = "com.otaliastudios:transcoder:0.11.2"
vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0" vanniktech_blurhash = "com.vanniktech:blurhash:0.3.0"
telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" } telephoto_zoomableimage = { module = "me.saket.telephoto:zoomable-image-coil", version.ref = "telephoto" }

View file

@ -42,8 +42,7 @@ dependencies {
implementation(libs.serialization.json) implementation(libs.serialization.json)
// UnifiedPush library // UnifiedPush library
api(libs.unifiedpush) implementation(libs.unifiedpush)
testImplementation(libs.coroutines.test) testImplementation(libs.coroutines.test)
testImplementation(libs.test.junit) testImplementation(libs.test.junit)
testImplementation(libs.test.robolectric) testImplementation(libs.test.robolectric)

View file

@ -33,7 +33,7 @@ class DefaultRegisterUnifiedPushUseCase @Inject constructor(
UnifiedPush.saveDistributor(context, distributor.value) UnifiedPush.saveDistributor(context, distributor.value)
// This will trigger the callback // This will trigger the callback
// VectorUnifiedPushMessagingReceiver.onNewEndpoint // VectorUnifiedPushMessagingReceiver.onNewEndpoint
UnifiedPush.registerApp(context = context, instance = clientSecret) UnifiedPush.register(context = context, instance = clientSecret)
// Wait for VectorUnifiedPushMessagingReceiver.onNewEndpoint to proceed // Wait for VectorUnifiedPushMessagingReceiver.onNewEndpoint to proceed
return runCatching { return runCatching {
withTimeout(30.seconds) { withTimeout(30.seconds) {

View file

@ -53,6 +53,6 @@ class DefaultUnregisterUnifiedPushUseCase @Inject constructor(
override fun cleanup(clientSecret: String) { override fun cleanup(clientSecret: String) {
unifiedPushStore.storeUpEndpoint(clientSecret, null) unifiedPushStore.storeUpEndpoint(clientSecret, null)
unifiedPushStore.storePushGateway(clientSecret, null) unifiedPushStore.storePushGateway(clientSecret, null)
UnifiedPush.unregisterApp(context, clientSecret) UnifiedPush.unregister(context, clientSecret)
} }
} }

View file

@ -16,7 +16,10 @@ import io.element.android.libraries.pushproviders.unifiedpush.registration.Endpo
import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.unifiedpush.android.connector.FailedReason
import org.unifiedpush.android.connector.MessagingReceiver import org.unifiedpush.android.connector.MessagingReceiver
import org.unifiedpush.android.connector.data.PushEndpoint
import org.unifiedpush.android.connector.data.PushMessage
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -45,15 +48,15 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
* @param message the message * @param message the message
* @param instance connection, for multi-account * @param instance connection, for multi-account
*/ */
override fun onMessage(context: Context, message: ByteArray, instance: String) { override fun onMessage(context: Context, message: PushMessage, instance: String) {
Timber.tag(loggerTag.value).w("New message") Timber.tag(loggerTag.value).d("New message, decrypted: ${message.decrypted}")
coroutineScope.launch { coroutineScope.launch {
val pushData = pushParser.parse(message, instance) val pushData = pushParser.parse(message.content, instance)
if (pushData == null) { if (pushData == null) {
Timber.tag(loggerTag.value).w("Invalid data received from UnifiedPush") Timber.tag(loggerTag.value).w("Invalid data received from UnifiedPush")
pushHandler.handleInvalid( pushHandler.handleInvalid(
providerInfo = "${UnifiedPushConfig.NAME} - $instance", providerInfo = "${UnifiedPushConfig.NAME} - $instance",
data = String(message), data = String(message.content),
) )
} else { } else {
pushHandler.handle( pushHandler.handle(
@ -68,20 +71,20 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
* Called when a new endpoint is to be used for sending push messages. * Called when a new endpoint is to be used for sending push messages.
* You should send the endpoint to your application server and sync for missing notifications. * You should send the endpoint to your application server and sync for missing notifications.
*/ */
override fun onNewEndpoint(context: Context, endpoint: String, instance: String) { override fun onNewEndpoint(context: Context, endpoint: PushEndpoint, instance: String) {
Timber.tag(loggerTag.value).w("onNewEndpoint: $endpoint") Timber.tag(loggerTag.value).w("onNewEndpoint: $endpoint")
coroutineScope.launch { coroutineScope.launch {
val gateway = unifiedPushGatewayResolver.getGateway(endpoint) val gateway = unifiedPushGatewayResolver.getGateway(endpoint.url)
.let { gatewayResult -> .let { gatewayResult ->
unifiedPushGatewayUrlResolver.resolve(gatewayResult, instance) unifiedPushGatewayUrlResolver.resolve(gatewayResult, instance)
} }
unifiedPushStore.storePushGateway(instance, gateway) unifiedPushStore.storePushGateway(instance, gateway)
val result = newGatewayHandler.handle(endpoint, gateway, instance) val result = newGatewayHandler.handle(endpoint.url, gateway, instance)
.onFailure { .onFailure {
Timber.tag(loggerTag.value).e(it, "Failed to handle new gateway") Timber.tag(loggerTag.value).e(it, "Failed to handle new gateway")
} }
.onSuccess { .onSuccess {
unifiedPushStore.storeUpEndpoint(instance, endpoint) unifiedPushStore.storeUpEndpoint(instance, endpoint.url)
} }
endpointRegistrationHandler.registrationDone( endpointRegistrationHandler.registrationDone(
RegistrationResult( RegistrationResult(
@ -96,8 +99,8 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
/** /**
* Called when the registration is not possible, eg. no network. * Called when the registration is not possible, eg. no network.
*/ */
override fun onRegistrationFailed(context: Context, instance: String) { override fun onRegistrationFailed(context: Context, reason: FailedReason, instance: String) {
Timber.tag(loggerTag.value).e("onRegistrationFailed for $instance") Timber.tag(loggerTag.value).e("onRegistrationFailed for $instance, reason: $reason")
/* /*
Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show()
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
@ -110,7 +113,7 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
* Called when this application is unregistered from receiving push messages. * Called when this application is unregistered from receiving push messages.
*/ */
override fun onUnregistered(context: Context, instance: String) { override fun onUnregistered(context: Context, instance: String) {
Timber.tag(loggerTag.value).w("Unifiedpush: Unregistered") Timber.tag(loggerTag.value).w("UnifiedPush: Unregistered")
/* /*
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
pushDataStore.setFdroidSyncBackgroundMode(mode) pushDataStore.setFdroidSyncBackgroundMode(mode)

View file

@ -32,6 +32,10 @@ import org.junit.Assert.assertThrows
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner import org.robolectric.RobolectricTestRunner
import org.unifiedpush.android.connector.FailedReason
import org.unifiedpush.android.connector.data.PublicKeySet
import org.unifiedpush.android.connector.data.PushEndpoint
import org.unifiedpush.android.connector.data.PushMessage
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
class VectorUnifiedPushMessagingReceiverTest { class VectorUnifiedPushMessagingReceiverTest {
@ -56,7 +60,7 @@ class VectorUnifiedPushMessagingReceiverTest {
fun `onRegistrationFailed does nothing`() = runTest { fun `onRegistrationFailed does nothing`() = runTest {
val context = InstrumentationRegistry.getInstrumentation().context val context = InstrumentationRegistry.getInstrumentation().context
val vectorUnifiedPushMessagingReceiver = createVectorUnifiedPushMessagingReceiver() val vectorUnifiedPushMessagingReceiver = createVectorUnifiedPushMessagingReceiver()
vectorUnifiedPushMessagingReceiver.onRegistrationFailed(context, A_SECRET) vectorUnifiedPushMessagingReceiver.onRegistrationFailed(context, FailedReason.NETWORK, A_SECRET)
} }
@Test @Test
@ -68,7 +72,7 @@ class VectorUnifiedPushMessagingReceiverTest {
handleResult = pushHandlerResult handleResult = pushHandlerResult
), ),
) )
vectorUnifiedPushMessagingReceiver.onMessage(context, UnifiedPushParserTest.UNIFIED_PUSH_DATA.toByteArray(), A_SECRET) vectorUnifiedPushMessagingReceiver.onMessage(context, aPushMessage(), A_SECRET)
advanceUntilIdle() advanceUntilIdle()
pushHandlerResult.assertions() pushHandlerResult.assertions()
.isCalledOnce() .isCalledOnce()
@ -96,7 +100,7 @@ class VectorUnifiedPushMessagingReceiverTest {
handleInvalidResult = handleInvalidResult, handleInvalidResult = handleInvalidResult,
), ),
) )
vectorUnifiedPushMessagingReceiver.onMessage(context, "".toByteArray(), A_SECRET) vectorUnifiedPushMessagingReceiver.onMessage(context, aPushMessage(""), A_SECRET)
advanceUntilIdle() advanceUntilIdle()
handleInvalidResult.assertions().isCalledOnce() handleInvalidResult.assertions().isCalledOnce()
} }
@ -127,7 +131,7 @@ class VectorUnifiedPushMessagingReceiverTest {
unifiedPushNewGatewayHandler = unifiedPushNewGatewayHandler, unifiedPushNewGatewayHandler = unifiedPushNewGatewayHandler,
) )
endpointRegistrationHandler.state.test { endpointRegistrationHandler.state.test {
vectorUnifiedPushMessagingReceiver.onNewEndpoint(context, "anEndpoint", A_SECRET) vectorUnifiedPushMessagingReceiver.onNewEndpoint(context, aPushEndpoint("anEndpoint"), A_SECRET)
advanceUntilIdle() advanceUntilIdle()
assertThat(awaitItem()).isEqualTo( assertThat(awaitItem()).isEqualTo(
RegistrationResult( RegistrationResult(
@ -170,7 +174,7 @@ class VectorUnifiedPushMessagingReceiverTest {
unifiedPushNewGatewayHandler = unifiedPushNewGatewayHandler, unifiedPushNewGatewayHandler = unifiedPushNewGatewayHandler,
) )
endpointRegistrationHandler.state.test { endpointRegistrationHandler.state.test {
vectorUnifiedPushMessagingReceiver.onNewEndpoint(context, "anEndpoint", A_SECRET) vectorUnifiedPushMessagingReceiver.onNewEndpoint(context, aPushEndpoint(), A_SECRET)
advanceUntilIdle() advanceUntilIdle()
assertThat(awaitItem()).isEqualTo( assertThat(awaitItem()).isEqualTo(
RegistrationResult( RegistrationResult(
@ -207,3 +211,19 @@ class VectorUnifiedPushMessagingReceiverTest {
} }
} }
} }
private fun aPushMessage(
data: String = UnifiedPushParserTest.UNIFIED_PUSH_DATA,
decrypted: Boolean = true,
) = PushMessage(
content = data.toByteArray(),
decrypted = decrypted,
)
private fun aPushEndpoint(
url: String = "anEndpoint",
pubKeySet: PublicKeySet? = null,
) = PushEndpoint(
url = url,
pubKeySet = pubKeySet,
)

View file

@ -39,7 +39,6 @@ dependencyResolutionManagement {
maven { maven {
url = URI("https://www.jitpack.io") url = URI("https://www.jitpack.io")
content { content {
includeModule("com.github.UnifiedPush", "android-connector")
includeModule("com.github.matrix-org", "matrix-analytics-events") includeModule("com.github.matrix-org", "matrix-analytics-events")
} }
} }