diff --git a/README.md b/README.md
index 6032e22..e21e592 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,8 @@ from [Frontegg Portal Domain](https://portal.frontegg.com/development/settings/d
- Navigate to [Login Method Settings](https://portal.frontegg.com/development/authentication/hosted)
- Toggle Hosted login method
-- Add `{{ANDROID_PACKAGE_NAME}}://{{FRONTEGG_BASE_URL}}/ios/oauth/callback`
+- Add `{{ANDROID_PACKAGE_NAME}}://{{FRONTEGG_BASE_URL}}/android/oauth/callback` **(without assetlinks)**
+- Add `https://{{FRONTEGG_BASE_URL}}/{{ANDROID_PACKAGE_NAME}}/android/oauth/callback` **(required for assetlinks)**
- Replace `ANDROID_PACKAGE_NAME` with your application identifier
- Replace `FRONTEGG_BASE_URL` with your Frontegg base url
@@ -319,9 +320,11 @@ Follow [Config Android AssetLinks](#config-android-assetlinks) to add your Andro
The first domain will be placed automatically in the `AndroidManifest.xml` file. For each additional region, you will
need to add an `intent-filter`.
+Replace `${FRONTEGG_DOMAIN_2}` with the second domain from the previous step.
NOTE: if you are using `Custom Chrome Tab` you have to use `android:name` `com.frontegg.android.HostedAuthActivity` instead of `com.frontegg.android.EmbeddedAuthActivity`
+
```xml
@@ -334,13 +337,15 @@ NOTE: if you are using `Custom Chrome Tab` you have to use `android:name` `com.f
-
-
-
-
-
-
-
+
+
+
+
+
@@ -352,8 +357,11 @@ NOTE: if you are using `Custom Chrome Tab` you have to use `android:name` `com.f
-
-
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
index 4066b22..bcde5ee 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -7,7 +7,7 @@ plugins {
group 'com.frontegg.android'
-version '1.2.2'
+version '1.2.3'
android {
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 9058bbe..f47a762 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
-
+
@@ -16,12 +17,22 @@
-
-
-
-
-
-
+
+
+
+
+
+
@@ -65,13 +76,17 @@
+
+
-
diff --git a/android/src/main/java/com/frontegg/android/AuthenticationActivity.kt b/android/src/main/java/com/frontegg/android/AuthenticationActivity.kt
index 35a21de..7049522 100644
--- a/android/src/main/java/com/frontegg/android/AuthenticationActivity.kt
+++ b/android/src/main/java/com/frontegg/android/AuthenticationActivity.kt
@@ -59,7 +59,7 @@ class AuthenticationActivity : Activity() {
if (code != null) {
Log.d(TAG, "Got intent with oauth callback")
FronteggAuth.instance.isLoading.value = true
- FronteggAuth.instance.handleHostedLoginCallback(code)
+ FronteggAuth.instance.handleHostedLoginCallback(code, null, this)
setResult(RESULT_OK)
finish()
return
diff --git a/android/src/main/java/com/frontegg/android/FronteggApp.kt b/android/src/main/java/com/frontegg/android/FronteggApp.kt
index 47ffe01..0bc34fc 100644
--- a/android/src/main/java/com/frontegg/android/FronteggApp.kt
+++ b/android/src/main/java/com/frontegg/android/FronteggApp.kt
@@ -7,10 +7,8 @@ import android.content.pm.PackageManager.MATCH_ALL
import android.util.Log
import com.frontegg.android.exceptions.FronteggException
import com.frontegg.android.exceptions.FronteggException.Companion.FRONTEGG_APP_MUST_BE_INITIALIZED
-import com.frontegg.android.exceptions.FronteggException.Companion.FRONTEGG_DOMAIN_MUST_NOT_START_WITH_HTTPS
import com.frontegg.android.regions.RegionConfig
import com.frontegg.android.services.*
-import java.lang.RuntimeException
class FronteggApp private constructor(
val context: Context,
@@ -19,8 +17,9 @@ class FronteggApp private constructor(
val isEmbeddedMode: Boolean = true,
val regions: List = listOf(),
val selectedRegion: RegionConfig? = null,
- val handleLoginWithSocialLogin: Boolean = true,
- val handleLoginWithSSO: Boolean = false
+ var handleLoginWithSocialLogin: Boolean = true,
+ var handleLoginWithSSO: Boolean = false,
+ val useAssetsLinks: Boolean = false,
) {
val credentialManager: CredentialManager = CredentialManager(context)
@@ -45,19 +44,30 @@ class FronteggApp private constructor(
public fun init(
fronteggDomain: String,
clientId: String,
- context: Context
+ context: Context,
+ useAssetsLinks: Boolean = false
) {
val baseUrl: String = if (fronteggDomain.startsWith("https")) {
- throw FronteggException(FRONTEGG_DOMAIN_MUST_NOT_START_WITH_HTTPS)
+ fronteggDomain
} else {
"https://$fronteggDomain"
}
val isEmbeddedMode = isActivityEnabled(context, EmbeddedAuthActivity::class.java.name)
- instance = FronteggApp(context, baseUrl, clientId, isEmbeddedMode)
+ instance = FronteggApp(
+ context,
+ baseUrl,
+ clientId,
+ isEmbeddedMode,
+ useAssetsLinks = useAssetsLinks
+ )
}
- public fun initWithRegions(regions: List, context: Context): FronteggApp {
+ public fun initWithRegions(
+ regions: List,
+ context: Context,
+ useAssetsLinks: Boolean = false
+ ): FronteggApp {
val isEmbeddedMode = isActivityEnabled(context, EmbeddedAuthActivity::class.java.name)
val selectedRegion = CredentialManager(context).getSelectedRegion()
@@ -71,7 +81,8 @@ class FronteggApp private constructor(
regionConfig.clientId,
isEmbeddedMode,
regions,
- regionConfig
+ regionConfig,
+ useAssetsLinks = useAssetsLinks
)
instance = newInstance
return newInstance
diff --git a/android/src/main/java/com/frontegg/android/FronteggAuth.kt b/android/src/main/java/com/frontegg/android/FronteggAuth.kt
index 3f4bf40..806e527 100644
--- a/android/src/main/java/com/frontegg/android/FronteggAuth.kt
+++ b/android/src/main/java/com/frontegg/android/FronteggAuth.kt
@@ -173,7 +173,7 @@ class FronteggAuth(
this.initializing.value = false
}
- fun handleHostedLoginCallback(code: String, webView: WebView? = null): Boolean {
+ fun handleHostedLoginCallback(code: String, webView: WebView? = null, activity: Activity? = null): Boolean {
val codeVerifier = credentialManager.getCodeVerifier()
val redirectUrl = Constants.oauthCallbackUrl(baseUrl)
@@ -194,6 +194,8 @@ class FronteggAuth(
Handler(Looper.getMainLooper()).post {
webView.loadUrl(url.first)
}
+ }else if (activity != null){
+ login(activity)
}
}
diff --git a/android/src/main/java/com/frontegg/android/embedded/FronteggWebClient.kt b/android/src/main/java/com/frontegg/android/embedded/FronteggWebClient.kt
index 1203db8..466f413 100644
--- a/android/src/main/java/com/frontegg/android/embedded/FronteggWebClient.kt
+++ b/android/src/main/java/com/frontegg/android/embedded/FronteggWebClient.kt
@@ -7,8 +7,14 @@ import android.net.Uri
import android.net.UrlQuerySanitizer
import android.os.Handler
import android.os.Looper
+import android.text.Html
+import android.util.Base64
import android.util.Log
-import android.webkit.*
+import android.webkit.WebResourceError
+import android.webkit.WebResourceRequest
+import android.webkit.WebResourceResponse
+import android.webkit.WebView
+import android.webkit.WebViewClient
import com.frontegg.android.FronteggApp
import com.frontegg.android.FronteggAuth
import com.frontegg.android.utils.AuthorizeUrlGenerator
@@ -16,7 +22,7 @@ import com.frontegg.android.utils.Constants
import com.frontegg.android.utils.Constants.Companion.loginRoutes
import com.frontegg.android.utils.Constants.Companion.socialLoginRedirectUrl
import com.frontegg.android.utils.Constants.Companion.successLoginRoutes
-import com.google.gson.Gson
+import com.frontegg.android.utils.generateErrorPage
import com.google.gson.JsonParser
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
@@ -54,10 +60,13 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
FronteggAuth.instance.isLoading.value = true
}
-
+ if (url?.startsWith("data:text/html,") == true) {
+ FronteggAuth.instance.isLoading.value = false
+ return
+ }
val fronteggApp = FronteggApp.getInstance()
- val nativeModuleFunctions = JSONObject()
+ val nativeModuleFunctions = JSONObject()
nativeModuleFunctions.put("loginWithSocialLogin", fronteggApp.handleLoginWithSocialLogin)
nativeModuleFunctions.put("loginWithSSO", fronteggApp.handleLoginWithSSO)
val jsObject = nativeModuleFunctions.toString()
@@ -70,9 +79,60 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
request: WebResourceRequest?,
error: WebResourceError?
) {
+
+ try {
+ val errorMessage = "Check your internet connection and try again."
+ val htmlError = Html.escapeHtml(errorMessage)
+ val errorPage = generateErrorPage(
+ htmlError,
+ error = error?.description?.toString(),
+ url = request?.url?.toString()
+ )
+ val encodedHtml = Base64.encodeToString(errorPage.toByteArray(), Base64.NO_PADDING)
+ Handler(Looper.getMainLooper()).post {
+ view?.loadData(encodedHtml, "text/html", "base64")
+ }
+ } catch (e: Exception) {
+ // ignore error
+ }
+ Log.e(TAG, "onReceivedError: ${error?.description}")
super.onReceivedError(view, request, error)
}
+ private fun checkIfFronteggError(view: WebView?, url: String?, status: Int? = null) {
+ if (view == null || url == null) {
+ return
+ }
+ view.evaluateJavascript("document.body.innerText") { result ->
+ try {
+ var text = result
+ if (text == null) {
+ return@evaluateJavascript
+ }
+ var json = JsonParser.parseString(text)
+ while (!json.isJsonObject) {
+ text = json.asString
+ json = JsonParser.parseString(text)
+ }
+ val error = json.asJsonObject.get("errors").asJsonArray.map {
+ it.asString
+ }.joinToString("\n")
+
+ Log.e(TAG, "Frontegg ERROR: $error")
+
+ val htmlError = Html.escapeHtml(error)
+ val errorPage = generateErrorPage(htmlError, status = status)
+ val encodedHtml = Base64.encodeToString(errorPage.toByteArray(), Base64.NO_PADDING)
+ Handler(Looper.getMainLooper()).post {
+ view.loadData(encodedHtml, "text/html", "base64")
+ }
+
+ } catch (e: Exception) {
+ // ignore error
+ }
+ }
+ }
+
override fun onReceivedHttpError(
view: WebView?,
request: WebResourceRequest?,
@@ -83,6 +143,7 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
} else {
Log.d(TAG, "onReceivedHttpError: HTTP api call, ${request?.url?.path}")
}
+ checkIfFronteggError(view, request?.url.toString(), errorResponse?.statusCode)
super.onReceivedHttpError(view, request, errorResponse)
}
@@ -217,7 +278,10 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
}
@OptIn(DelicateCoroutinesApi::class)
- private fun setSocialLoginRedirectUri(@Suppress("UNUSED_PARAMETER") webView: WebView, uri: Uri): Boolean {
+ private fun setSocialLoginRedirectUri(
+ @Suppress("UNUSED_PARAMETER") webView: WebView,
+ uri: Uri
+ ): Boolean {
Log.d(TAG, "setSocialLoginRedirectUri setting redirect uri for social login")
if (uri.getQueryParameter("redirectUri") != null) {
diff --git a/android/src/main/java/com/frontegg/android/utils/Constants.kt b/android/src/main/java/com/frontegg/android/utils/Constants.kt
index aed0416..15aeddf 100644
--- a/android/src/main/java/com/frontegg/android/utils/Constants.kt
+++ b/android/src/main/java/com/frontegg/android/utils/Constants.kt
@@ -18,7 +18,6 @@ class ApiConstants {
class Constants {
companion object {
-
val successLoginRoutes = listOf(
"/oauth/account/social/success",
)
@@ -29,9 +28,14 @@ class Constants {
fun oauthCallbackUrl(baseUrl: String): String {
val host = baseUrl.substring("https://".length)
- val packageName = FronteggApp.getInstance().packageName
-
- return "${packageName}://${host}/android/oauth/callback"
+ val app = FronteggApp.getInstance();
+ val packageName = app.packageName
+ val useAssetsLinks = app.useAssetsLinks
+ return if (useAssetsLinks) {
+ "https://${host}/${packageName}/android/oauth/callback"
+ } else {
+ "${packageName}://${host}/android/oauth/callback"
+ }
}
fun socialLoginRedirectUrl(baseUrl: String): String {
diff --git a/android/src/main/java/com/frontegg/android/utils/ErrorPages.kt b/android/src/main/java/com/frontegg/android/utils/ErrorPages.kt
new file mode 100644
index 0000000..07239ba
--- /dev/null
+++ b/android/src/main/java/com/frontegg/android/utils/ErrorPages.kt
@@ -0,0 +1,53 @@
+package com.frontegg.android.utils
+
+
+fun generateErrorPage(
+ message: String,
+ status: Int? = null,
+ error: String? = null,
+ url: String? = null
+): String {
+ return """
+
+
+ Fatal Error
+
+
+
+
+ $message
+ ${if (status != null) "Status Code: $status
" else ""}
+ ${if (error != null) "$error
" else ""}
+ ${
+ if (url != null) "" else ""
+ }
+
+
+ """
+}
diff --git a/embedded/src/main/AndroidManifest.xml b/embedded/src/main/AndroidManifest.xml
index 0d16b33..a2b133f 100644
--- a/embedded/src/main/AndroidManifest.xml
+++ b/embedded/src/main/AndroidManifest.xml
@@ -24,6 +24,8 @@
+
+
\ No newline at end of file
diff --git a/embedded/src/main/java/com/frontegg/demo/App.kt b/embedded/src/main/java/com/frontegg/demo/App.kt
index bc312ba..ae93685 100644
--- a/embedded/src/main/java/com/frontegg/demo/App.kt
+++ b/embedded/src/main/java/com/frontegg/demo/App.kt
@@ -15,7 +15,8 @@ class App : Application() {
FronteggApp.init(
BuildConfig.FRONTEGG_DOMAIN,
BuildConfig.FRONTEGG_CLIENT_ID,
- this
+ this,
+ useAssetsLinks = true,
)
}
}
\ No newline at end of file
diff --git a/multi-region/src/main/AndroidManifest.xml b/multi-region/src/main/AndroidManifest.xml
index 1e15bda..12ac938 100644
--- a/multi-region/src/main/AndroidManifest.xml
+++ b/multi-region/src/main/AndroidManifest.xml
@@ -15,8 +15,8 @@
tools:targetApi="31">
+ android:exported="false"
+ android:label="Select Region" />
-
-
-
-
-
-
+
+
+
+
+
+
+