diff --git a/app/build.gradle.kts b/app/build.gradle.kts index be38991..d78a505 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -58,7 +58,6 @@ dependencies { implementation(libs.androidx.constraintlayout) implementation(libs.androidx.navigation.fragment.ktx) implementation(libs.androidx.navigation.ui.ktx) - implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.android) implementation(libs.androidx.browser) implementation(libs.androidx.lifecycle.runtime.ktx) diff --git a/build.gradle.kts b/build.gradle.kts index 88d4221..f0ff2dc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,15 +3,15 @@ import io.gitlab.arturbosch.detekt.report.ReportMergeTask // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "9.1.1" apply false - id("org.jetbrains.kotlin.android") version "2.2.21" apply false - id("com.android.library") version "9.1.1" apply false + id("com.android.application") version "9.2.1" apply false + id("org.jetbrains.kotlin.android") version "2.3.21" apply false + id("com.android.library") version "9.2.1" apply false id("io.gitlab.arturbosch.detekt") version "1.23.8" - id("org.jetbrains.dokka") version "2.1.0" + id("org.jetbrains.dokka") version "2.2.0" id("io.github.gradle-nexus.publish-plugin") version "2.0.0" - kotlin("jvm") version "2.2.21" - kotlin("plugin.serialization") version "2.2.21" + kotlin("jvm") version "2.3.21" + kotlin("plugin.serialization") version "2.3.21" } val detektReportMergeSarif by tasks.registering(ReportMergeTask::class) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8f0ca25..ce719cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,24 +1,32 @@ [versions] +androidbrowserhelper = "2.7.1" +appauth = "0.11.1" appcompat = "1.7.1" browser = "1.10.0" constraintlayout = "2.2.1" coreKtx = "1.18.0" +datastorePreferences = "1.2.1" espresso = "3.7.0" junit = "1.3.0" junitVersion = "4.13.2" -kotlinx = "1.10.2" +kotlinx = "1.11.0" lifecycleRuntimeKtx = "2.10.0" -material = "1.13.0" -navigation = "2.9.7" +material = "1.14.0" +mockitoCore = "5.23.0" +mockitoKotlin = "6.3.0" +navigation = "2.9.8" roomCompiler = "2.8.4" +securityCryptoKtx = "1.1.0" test = "1.7.0" uiautomator = "2.3.0" [libraries] +androidbrowserhelper = { module = "com.google.androidbrowserhelper:androidbrowserhelper", version.ref = "androidbrowserhelper" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "browser" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" } androidx-espresso-contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "espresso" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" } androidx-espresso-intents = { group = "androidx.test.espresso", name = "espresso-intents", version.ref = "espresso" } @@ -29,8 +37,15 @@ androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "roomCompiler" } androidx-rules = { group = "androidx.test", name = "rules", version.ref = "test" } androidx-runner = { group = "androidx.test", name = "runner", version.ref = "test" } +androidx-security-crypto-ktx = { module = "androidx.security:security-crypto-ktx", version.ref = "securityCryptoKtx" } androidx-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" } +appauth = { module = "net.openid:appauth", version.ref = "appauth" } junit = { group = "junit", name = "junit", version.ref = "junitVersion" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx" } +kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx" } +kotlinx-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-cbor", version.ref = "kotlinx" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockitoCore" } +mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockitoKotlin" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9..b1b8ef5 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c61a118..df6a6ad 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index f3b75f3..b9bb139 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -205,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019..aa5f10b 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -23,8 +23,8 @@ @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,30 +65,18 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 5e031b8..4dc051d 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -151,20 +151,20 @@ signing { dependencies { - implementation("androidx.core:core-ktx:1.18.0") - implementation("androidx.appcompat:appcompat:1.7.1") - implementation("com.google.androidbrowserhelper:androidbrowserhelper:2.6.2") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.10.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0") - implementation("net.openid:appauth:0.11.1") - implementation("androidx.security:security-crypto-ktx:1.1.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") - implementation("androidx.datastore:datastore-preferences:1.2.1") - testImplementation("junit:junit:4.13.2") - testImplementation("org.mockito:mockito-core:5.23.0") - testImplementation("org.mockito.kotlin:mockito-kotlin:6.2.3") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2") - androidTestImplementation("androidx.test.ext:junit:1.3.0") - androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0") + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.androidbrowserhelper) + implementation(libs.kotlinx.serialization.cbor) + implementation(libs.kotlinx.serialization.json) + implementation(libs.appauth) + implementation(libs.androidx.security.crypto.ktx) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.coroutines.android) + implementation(libs.androidx.datastore.preferences) + testImplementation(libs.junit) + testImplementation(libs.mockito.core) + testImplementation(libs.mockito.kotlin) + testImplementation(libs.kotlinx.coroutines.test) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) } diff --git a/library/src/main/java/io/fusionauth/mobilesdk/oauth/OAuthAuthorizationService.kt b/library/src/main/java/io/fusionauth/mobilesdk/oauth/OAuthAuthorizationService.kt index 23ef4db..d77d399 100644 --- a/library/src/main/java/io/fusionauth/mobilesdk/oauth/OAuthAuthorizationService.kt +++ b/library/src/main/java/io/fusionauth/mobilesdk/oauth/OAuthAuthorizationService.kt @@ -37,7 +37,6 @@ import java.net.HttpURLConnection import java.util.concurrent.atomic.AtomicReference import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine import androidx.core.net.toUri import kotlinx.coroutines.suspendCancellableCoroutine @@ -345,6 +344,7 @@ class OAuthAuthorizationService internal constructor( * @param ex The authorization exception received from the authorization process, or null if no exception occurred. * @return The token response from the authorization service. */ + @Suppress("RedundantSuspendModifier") private suspend fun performTokenRequest( response: AuthorizationResponse, ex: net.openid.appauth.AuthorizationException? @@ -406,6 +406,7 @@ class OAuthAuthorizationService internal constructor( * * @return The [AuthorizationServiceConfiguration] object. */ + @Suppress("RedundantSuspendModifier") private suspend fun fetchConfiguration(): AuthorizationServiceConfiguration { val uriBuilder = fusionAuthUrl.toUri().buildUpon() @@ -488,7 +489,7 @@ class OAuthAuthorizationService internal constructor( val refreshToken = authState.refreshToken ?: throw AuthorizationException("No refresh token available") - val response = suspendCoroutine { continuation -> + val response = suspendCancellableCoroutine { continuation -> authService.performTokenRequest( TokenRequest.Builder(config, clientId) .setGrantType(GrantTypeValues.REFRESH_TOKEN) @@ -500,7 +501,7 @@ class OAuthAuthorizationService internal constructor( if (response != null) { continuation.resume(response) } else { - continuation.resumeWithException(exception?.let { AuthorizationException(it) } + continuation.resumeWithException(exception?.let { AuthorizationException(it) } ?: AuthorizationException("Unknown error")) } }