Skip to content

Commit 7c9f2d2

Browse files
Release 1.10.0 (#48)
* Update features for 258 release * Update to 1.10.0
1 parent 8217ef7 commit 7c9f2d2

File tree

14 files changed

+490
-168
lines changed

14 files changed

+490
-168
lines changed

gradle/libs.versions.toml

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
[versions]
2-
gradlePlugin = "8.9.2"
3-
kotlin = "2.0.21"
4-
coreKtx = "1.16.0"
2+
gradlePlugin = "8.13.0"
3+
kotlin = "2.2.20"
4+
coreKtx = "1.17.0"
55
junit = "4.13.2"
6-
junitVersion = "1.2.1"
7-
espressoCore = "3.6.1"
8-
lifecycleRuntimeKtx = "2.9.0"
9-
activityCompose = "1.10.1"
10-
composeBom = "2025.05.00"
11-
appcompat = "1.7.0"
12-
material = "1.12.0"
13-
coil = "3.0.3"
14-
salesforceMessaging = "1.9.2"
6+
junitVersion = "1.3.0"
7+
espressoCore = "3.7.0"
8+
lifecycleRuntimeKtx = "2.9.4"
9+
activityCompose = "1.11.0"
10+
composeBom = "2025.10.00"
11+
appcompat = "1.7.1"
12+
material = "1.13.0"
13+
coil = "3.3.0"
14+
salesforceMessaging = "1.10.0"
15+
salesforceMobileSDK = "13.1.0"
1516

1617
[libraries]
1718
salesforce-messaging = { group = "com.salesforce.service", name = "messaging-inapp-ui", version.ref = "salesforceMessaging" }
@@ -23,6 +24,7 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
2324
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" }
2425
androidx-compose-ui-text = { group = "androidx.compose.ui", name = "ui-text" }
2526
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
27+
androidx-compose-iconsext = { group = "androidx.compose.material", name = "material-icons-extended" }
2628

2729
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
2830
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
@@ -43,6 +45,9 @@ test-androidx-espresso-core = { group = "androidx.test.espresso", name = "espres
4345
test-androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
4446
test-androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
4547

48+
# Only needed if using Salesforce Auth
49+
salesforce-mobile-sdk = { group = "com.salesforce.mobilesdk", name = "SalesforceSDK", version.ref = "salesforceMobileSDK" }
50+
4651
[plugins]
4752
android-application = { id = "com.android.application", version.ref = "gradlePlugin" }
4853
android-library = { id = "com.android.library", version.ref = "gradlePlugin" }

sample-app/build.gradle.kts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ plugins {
66

77
android {
88
namespace = "com.salesforce.android.smi.sampleapp"
9-
compileSdk = 35
9+
compileSdk = 36
1010

1111
defaultConfig {
1212
applicationId = "com.salesforce.android.smi.sampleapp"
1313
minSdk = 23
14-
targetSdk = 35
14+
targetSdk = 36
1515
versionCode = 1
1616
versionName = "1.0"
1717

@@ -63,8 +63,9 @@ dependencies {
6363
implementation(libs.androidx.compose.ui)
6464
implementation(libs.androidx.compose.ui.tooling.preview)
6565
implementation(libs.kotlin.stdlib)
66-
6766
implementation(libs.androidx.compose.material3)
67+
implementation(libs.androidx.compose.iconsext)
68+
6869
testImplementation(libs.test.junit)
6970
androidTestImplementation(libs.test.androidx.junit)
7071
androidTestImplementation(libs.test.androidx.espresso.core)

sample-app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:tools="http://schemas.android.com/tools">
44

5+
<!-- Salesforce Mobile SDK sets the minSDK version higher than the MIAW SDK -->
6+
<uses-sdk tools:overrideLibrary="com.salesforce.androidsdk, com.salesforce.androidsdk.analytics"/>
7+
58
<application
69
android:allowBackup="true"
710
android:dataExtractionRules="@xml/data_extraction_rules"
@@ -25,4 +28,4 @@
2528
</activity>
2629
</application>
2730

28-
</manifest>
31+
</manifest>

sample-messaging/build.gradle.kts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66

77
android {
88
namespace = "com.salesforce.android.smi.messaging"
9-
compileSdk = 35
9+
compileSdk = 36
1010

1111
defaultConfig {
1212
minSdk = 23
@@ -56,12 +56,16 @@ dependencies {
5656
implementation(libs.androidx.compose.foundation)
5757
implementation(libs.androidx.compose.ui)
5858
implementation(libs.androidx.compose.ui.text)
59+
implementation(libs.androidx.navigation.compose)
60+
implementation(libs.androidx.compose.iconsext)
5961

6062
implementation(libs.coil)
6163
implementation(libs.coil.gif)
6264
implementation(libs.coil.compose)
6365
implementation(libs.coil.okhttp)
6466

67+
api(libs.salesforce.mobile.sdk)
68+
6569
testImplementation(libs.test.junit)
6670
androidTestImplementation(libs.test.androidx.junit)
6771
androidTestImplementation(libs.test.androidx.espresso.core)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-keep class com.salesforce.android.smi.messaging.** { *; }

sample-messaging/proguard-rules.pro

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,4 @@
1919
# If you keep the line number information, uncomment this to
2020
# hide the original source file name.
2121
#-renamesourcefileattribute SourceFile
22-
-keep class com.salesforce.android.smi.messaging.SalesforceMessaging { *; }
23-
-keep class com.salesforce.android.smi.messaging.features.ui.PopulatePreChat { *; }
24-
-keep class com.salesforce.android.smi.messaging.features.ui.replacement.OverridableUI { *; }
22+
-keep class com.salesforce.android.smi.messaging.** { *; }

sample-messaging/src/main/java/com/salesforce/android/smi/messaging/SalesforceMessaging.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@ class SalesforceMessaging(
5252
}
5353

5454
override val conversationClient: ConversationClient = coreClient.conversationClient(conversationId).apply {
55-
uiClient.viewComponents = overridableUI.CustomViewComponents(this)
55+
uiClient.viewComponents = overridableUI.CustomViewComponents(this@SalesforceMessaging)
5656
}
5757
}

sample-messaging/src/main/java/com/salesforce/android/smi/messaging/features/core/UserVerification.kt

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ package com.salesforce.android.smi.messaging.features.core
33
import com.salesforce.android.smi.core.ChallengeReason
44
import com.salesforce.android.smi.core.UserVerificationProvider
55
import com.salesforce.android.smi.core.UserVerificationToken
6-
import com.salesforce.android.smi.core.UserVerificationType
76
import kotlinx.coroutines.delay
87

98
open class UserVerification : UserVerificationProvider {
10-
override suspend fun userVerificationChallenge(reason: ChallengeReason): UserVerificationToken {
11-
val token: String = when (reason) {
9+
override suspend fun userVerificationChallenge(reason: ChallengeReason): UserVerificationToken =
10+
when (reason) {
1211
ChallengeReason.INITIAL -> authenticate()
1312
ChallengeReason.RENEW -> renewAuthentication()
1413
ChallengeReason.EXPIRED -> renewAuthentication()
@@ -18,16 +17,7 @@ open class UserVerification : UserVerificationProvider {
1817
}
1918
}
2019

21-
return UserVerificationToken(UserVerificationType.JWT, token)
22-
}
20+
open suspend fun authenticate(): UserVerificationToken = delay(1000).let { UserVerificationToken.externalToken("fakeToken") }
2321

24-
open suspend fun authenticate(): String {
25-
delay(1000)
26-
return "fakeToken"
27-
}
28-
29-
open suspend fun renewAuthentication(): String {
30-
delay(1000)
31-
return "renewedToken"
32-
}
22+
open suspend fun renewAuthentication(): UserVerificationToken = delay(1000).let { UserVerificationToken.externalToken("renewedToken") }
3323
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.salesforce.android.smi.messaging.features.core.salesforceAuthentication
2+
3+
import com.salesforce.android.smi.core.UserVerificationToken
4+
import com.salesforce.android.smi.messaging.features.core.UserVerification
5+
6+
class PassthroughUserVerification(private val sampleSalesforceSDKManager: SampleSalesforceSDKManager) : UserVerification() {
7+
override suspend fun authenticate(): UserVerificationToken = sampleSalesforceSDKManager.fetchMessagingToken()
8+
9+
override suspend fun renewAuthentication(): UserVerificationToken = authenticate()
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.salesforce.android.smi.messaging.features.core.salesforceAuthentication
2+
3+
import android.app.Activity
4+
import android.os.Build
5+
import android.widget.Toast
6+
import com.salesforce.android.smi.common.api.Result
7+
import com.salesforce.android.smi.common.api.data
8+
import com.salesforce.android.smi.core.CoreClient
9+
import com.salesforce.android.smi.core.UserVerificationToken
10+
import com.salesforce.android.smi.messaging.features.core.UserVerification
11+
import com.salesforce.androidsdk.app.SalesforceSDKManager
12+
import com.salesforce.androidsdk.rest.RestClient
13+
import com.salesforce.androidsdk.rest.RestRequest
14+
import com.salesforce.androidsdk.rest.RestRequest.RestMethod
15+
import com.salesforce.androidsdk.rest.RestResponse
16+
import com.salesforce.androidsdk.ui.LoginActivity
17+
import java.util.logging.Level
18+
import java.util.logging.Logger
19+
import kotlin.coroutines.resume
20+
import kotlin.coroutines.suspendCoroutine
21+
22+
class SampleSalesforceSDKManager(
23+
private val activityProvider: () -> Activity,
24+
private val coreClient: CoreClient,
25+
loginActivity: Class<out Activity?> = LoginActivity::class.java
26+
) : SalesforceSDKManager(activityProvider().applicationContext, activityProvider()::class.java, loginActivity) {
27+
private val logger = Logger.getLogger(TAG)
28+
29+
init {
30+
customTabBrowser = null
31+
}
32+
33+
private val messagingTokenPath: String = coreClient.salesforceAuthenticationRequestPath
34+
35+
fun login() = gateToAPI28 { restClient() }
36+
37+
fun logout() = gateToAPI28 { logout(activityProvider(), false) }
38+
39+
suspend fun fetchVersions() = makeRequest(RestRequest.getRequestForVersions())
40+
41+
suspend fun fetchResources() = makeRequest(RestRequest.getRequestForResources(API_VERSION))
42+
43+
suspend fun fetchMessagingToken(): UserVerificationToken =
44+
makeRequest(RestRequest(RestMethod.GET, messagingTokenPath)).data?.asJSONObject()?.getJSONObject("data")?.let { json ->
45+
UserVerificationToken.passthroughToken(json.getString("accessToken"), json.getString("lastEventId"))
46+
} ?: throw Exception("Failed to fetch messaging token.")
47+
48+
private suspend fun makeRequest(request: RestRequest): Result<RestResponse?> =
49+
gateToAPI28<Result<RestResponse?>> {
50+
restClient()?.let { restClient ->
51+
suspendCoroutine { continuation ->
52+
val callback = object : RestClient.AsyncRequestCallback {
53+
override fun onSuccess(
54+
request: RestRequest?,
55+
response: RestResponse?
56+
) {
57+
response?.consume()
58+
continuation.resume(Result.Success(response))
59+
}
60+
61+
override fun onError(exception: Exception?) {
62+
continuation.resume(Result.Error(exception ?: REST_UNKNOWN_ERROR))
63+
}
64+
}
65+
66+
restClient.sendAsync(request, callback)
67+
}
68+
} ?: Result.Error(REST_UNAVAILABLE_ERROR)
69+
} ?: Result.Error(API_28_ERROR)
70+
71+
private fun restClient(): RestClient? {
72+
var restClient: RestClient? = null
73+
clientManager.getRestClient(activityProvider()) {
74+
restClient = it
75+
}
76+
77+
return restClient
78+
}
79+
80+
private inline fun <T> gateToAPI28(block: () -> T): T? =
81+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
82+
block()
83+
} else {
84+
logger.log(Level.WARNING, API_28_ERROR.message)
85+
Toast.makeText(activityProvider(), API_28_ERROR.message, Toast.LENGTH_SHORT).show()
86+
null
87+
}
88+
89+
companion object {
90+
fun getInstance(
91+
coreClient: CoreClient,
92+
activityProvider: () -> Activity
93+
): SampleSalesforceSDKManager {
94+
if (!hasInstance() || activityProvider()::class.java != getInstance().mainActivityClass) {
95+
setInstance(SampleSalesforceSDKManager(activityProvider, coreClient))
96+
}
97+
initInternal(activityProvider().applicationContext)
98+
return SalesforceSDKManager.Companion.getInstance() as SampleSalesforceSDKManager
99+
}
100+
101+
private val REST_UNAVAILABLE_ERROR = Exception("Rest client not yet available.")
102+
private val REST_UNKNOWN_ERROR = Exception("Rest client not yet available.")
103+
private val API_28_ERROR = Exception("API 28+ only")
104+
private const val TAG = "SampleSalesforceSDKManager"
105+
private const val API_VERSION = "v65.0"
106+
}
107+
}

0 commit comments

Comments
 (0)