mirror of
https://github.com/bitwarden/android.git
synced 2026-03-22 06:11:38 -05:00
[PM-14303] Update Bitwarden SDK and load bitwarden_uniffi on older Android versions (#4793)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
/**
|
||||
* Manager for loading native libraries.
|
||||
*/
|
||||
interface NativeLibraryManager {
|
||||
|
||||
/**
|
||||
* Loads a native library with the given [libraryName].
|
||||
*/
|
||||
fun loadLibrary(libraryName: String): Result<Unit>
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Primary implementation of [NativeLibraryManager].
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
class NativeLibraryManagerImpl : NativeLibraryManager {
|
||||
override fun loadLibrary(libraryName: String): Result<Unit> {
|
||||
return try {
|
||||
System.loadLibrary(libraryName)
|
||||
Result.success(Unit)
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
Timber.e(e, "Failed to load native library $libraryName.")
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import android.os.Build
|
||||
import com.bitwarden.sdk.Client
|
||||
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
|
||||
|
||||
/**
|
||||
* Primary implementation of [SdkClientManager].
|
||||
*/
|
||||
class SdkClientManagerImpl(
|
||||
private val featureFlagManager: FeatureFlagManager,
|
||||
nativeLibraryManager: NativeLibraryManager,
|
||||
private val clientProvider: suspend () -> Client = {
|
||||
Client(settings = null).apply {
|
||||
platform().loadFlags(featureFlagManager.sdkFeatureFlags)
|
||||
@@ -15,6 +18,15 @@ class SdkClientManagerImpl(
|
||||
) : SdkClientManager {
|
||||
private val userIdToClientMap = mutableMapOf<String?, Client>()
|
||||
|
||||
init {
|
||||
// The SDK requires access to Android APIs that were not made public until API 31. In order
|
||||
// to work around this limitation the SDK must be manually loaded prior to initializing any
|
||||
// [Client] instance.
|
||||
if (isBuildVersionBelow(Build.VERSION_CODES.S)) {
|
||||
nativeLibraryManager.loadLibrary("bitwarden_uniffi")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getOrCreateClient(
|
||||
userId: String?,
|
||||
): Client = userIdToClientMap.getOrPut(key = userId) { clientProvider() }
|
||||
|
||||
@@ -34,6 +34,8 @@ import com.x8bit.bitwarden.data.platform.manager.KeyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.KeyManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.LogsManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.LogsManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.NativeLibraryManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.NativeLibraryManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.PolicyManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
@@ -193,12 +195,18 @@ object PlatformManagerModule {
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideNativeLibraryManager(): NativeLibraryManager = NativeLibraryManagerImpl()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSdkClientManager(
|
||||
featureFlagManager: FeatureFlagManager,
|
||||
nativeLibraryManager: NativeLibraryManager,
|
||||
): SdkClientManager = SdkClientManagerImpl(
|
||||
featureFlagManager = featureFlagManager,
|
||||
nativeLibraryManager = nativeLibraryManager,
|
||||
)
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -1,23 +1,55 @@
|
||||
package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkStatic
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class SdkClientManagerTest {
|
||||
|
||||
private val sdkClientManager = SdkClientManagerImpl(
|
||||
clientProvider = { mockk(relaxed = true) },
|
||||
featureFlagManager = mockk(),
|
||||
)
|
||||
private val mockNativeLibraryManager = mockk<NativeLibraryManager> {
|
||||
every { loadLibrary(any()) } returns Result.success(Unit)
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockkStatic(::isBuildVersionBelow)
|
||||
every { isBuildVersionBelow(any()) } returns false
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkStatic(::isBuildVersionBelow)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `init should load the bitwarden_uniffi library when build version is below 31`() = runTest {
|
||||
every { isBuildVersionBelow(31) } returns true
|
||||
createSdkClientManager()
|
||||
verify { mockNativeLibraryManager.loadLibrary("bitwarden_uniffi") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `init should not load the bitwarden_uniffi library when build version is 31 or above`() =
|
||||
runTest {
|
||||
every { isBuildVersionBelow(31) } returns false
|
||||
createSdkClientManager()
|
||||
verify(exactly = 0) { mockNativeLibraryManager.loadLibrary("bitwarden_uniffi") }
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `getOrCreateClient should create a new client for each userId and return a cached client for subsequent calls`() =
|
||||
runTest {
|
||||
val sdkClientManager = createSdkClientManager()
|
||||
val userId = "userId"
|
||||
val firstClient = sdkClientManager.getOrCreateClient(userId = userId)
|
||||
|
||||
@@ -33,6 +65,7 @@ class SdkClientManagerTest {
|
||||
|
||||
@Test
|
||||
fun `destroyClient should call close on the Client and remove it from the cache`() = runTest {
|
||||
val sdkClientManager = createSdkClientManager()
|
||||
val userId = "userId"
|
||||
val firstClient = sdkClientManager.getOrCreateClient(userId = userId)
|
||||
|
||||
@@ -44,4 +77,10 @@ class SdkClientManagerTest {
|
||||
val secondClient = sdkClientManager.getOrCreateClient(userId = userId)
|
||||
assertNotEquals(firstClient, secondClient)
|
||||
}
|
||||
|
||||
private fun createSdkClientManager(): SdkClientManagerImpl = SdkClientManagerImpl(
|
||||
clientProvider = { mockk(relaxed = true) },
|
||||
nativeLibraryManager = mockNativeLibraryManager,
|
||||
featureFlagManager = mockk(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ androidxTestRules = "1.6.1"
|
||||
androidXAppCompat = "1.7.0"
|
||||
androdixAutofill = "1.1.0"
|
||||
androidxWork = "2.10.0"
|
||||
bitwardenSdk = "1.0.0-20250213.181812-113"
|
||||
bitwardenSdk = "1.0.0-20250225.125021-120"
|
||||
crashlytics = "3.0.3"
|
||||
detekt = "1.23.7"
|
||||
firebaseBom = "33.9.0"
|
||||
|
||||
Reference in New Issue
Block a user