## Android Kotlin quickstart This guide is a walkthrough on how to integrate Frontegg’s authentication magic into your app using the Frontegg Android Kotlin SDK. Whether you need to add secure sign-ups, logins, multi-factor authentication, or even social logins, this guide has you covered with simple, step-by-step instructions to get things rolling in no time. br Check out the sample package on GitHub br Prerequisites Frontegg Hosted Login is required, and setting a [custom domain](/ciam/guides/env-settings/custom-domain) is highly recommended. Android ≥ 26 Java ≥ 8 br **Android SDK 26+** Set defaultConfig's minSDK to 26+ in build.gradle: ``` android { defaultConfig { minSdk 26 } } ``` ``` android { defaultConfig { minSdk = 26 } } ``` br **Java 8+** Set target java 8 byte code for Android and Kotlin plugins respectively `build.gradle`: ``` android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } ``` ``` android { compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } } ``` ### Setup for Gradle8+ Enable `buildconfig` feature: 1. Add the below line to your gradle.properties: `android.defaults.buildfeatures.buildconfig=true` 1. Add the below lines to your app/build.gradle: ``` android { ... buildFeatures { buildConfig = true } ... } ``` ``` android { ... buildFeatures { buildConfig = true } ... } ``` ### Proguard setup (optional) If `minifyEnabled` and `shrinkResources` is `true`, follow the instruction below: ``` # Gson relies on generic type information stored in class files when working with fields. # ProGuard removes this information by default, so we need to retain it. -keepattributes Signature # according to https://stackoverflow.com/a/76224937 # This is also required for R8 in compatibility mode, as several optimizations # (such as class merging and argument removal) may remove the generic signature. # For more information, see: # https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#troubleshooting-gson-gson -keep class com.google.gson.reflect.TypeToken { *; } -keep class * extends com.google.gson.reflect.TypeToken # Retain GSON @Expose annotation attributes -keepattributes AnnotationDefault,RuntimeVisibleAnnotations -keep class com.google.gson.reflect.TypeToken { ; } -keepclassmembers class **$TypeAdapterFactory { ; } # Keep Frontegg classes -keep class com.frontegg.android.utils.JWT { *; } -keep class com.frontegg.android.models.** { *; } # Retain Tink classes used for shared preferences encryption -keep class com.google.crypto.tink.** { *; } ``` ### Prepare Frontegg workspace Navigate to [Frontegg Portal Settings](https://portal.frontegg.com/development/settings), If you don't have application follow integration steps after signing up. Copy `FronteggDomain` for future steps from [Frontegg Portal Domain](https://portal.frontegg.com/development/settings/domains) br ![frontegg-domain](/assets/new-frontegg-domain.60f517108b4c93feb0326bd54894cfac97dcc0d10d29d12eb2cf4ef068816e5f.14341b2b.png) ### Setup hosted login - Navigate to [Login Method Settings](https://portal.frontegg.com/development/authentication/hosted) - Toggle on Hosted login method - Add `{{ANDROID_PACKAGE_NAME}}://{{FRONTEGG_BASE_URL}}/android/oauth/callback` **(for custom scheme)** - Add `https://{{FRONTEGG_BASE_URL}}/oauth/account/redirect/android/{{ANDROID_PACKAGE_NAME}}` **(for assetlinks)** - Replace `ANDROID_PACKAGE_NAME` with your application identifier - Replace `FRONTEGG_BASE_URL` with your Frontegg base url, without **https**, i.e `FronteggDomain`. ### Add Frontegg package to the project - Open you project - Find your app's build.gradle file - Add the following to your dependencies section: ``` dependencies { // Add the Frontegg Android Kotlin SDK implementation 'com.frontegg.sdk:android:1.+' // Add Frontegg observables dependency implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1' } ``` ``` dependencies { // Add the Frontegg Android Kotlin SDK implementation ("com.frontegg.sdk:android:LATEST_VERSION") // Add Frontegg observables dependency implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1' } ``` ### Configure build config fields To set up your Android application on to communicate with Frontegg, you have to add `buildConfigField` property the gradle `android/app/build.gradle`. This property will store frontegg hostname (without https) and client id from previous step: ``` def fronteggDomain = "FRONTEGG_DOMAIN_HOST.com" // without protocol https:// def fronteggClientId = "FRONTEGG_CLIENT_ID" android { defaultConfig { manifestPlaceholders = [ "package_name" : applicationId, "frontegg_domain" : fronteggDomain, "frontegg_client_id": fronteggClientId ] buildConfigField "String", 'FRONTEGG_DOMAIN', "\"$fronteggDomain\"" buildConfigField "String", 'FRONTEGG_CLIENT_ID', "\"$fronteggClientId\"" } } ``` ``` val fronteggDomain = "FRONTEGG_DOMAIN_HOST.com" // without protocol https:// val fronteggClientId = "FRONTEGG_CLIENT_ID" android { defaultConfig { manifestPlaceholders["package_name"] = applicationId.toString() manifestPlaceholders["frontegg_domain"] = fronteggDomain manifestPlaceholders["frontegg_client_id"] = fronteggClientId buildConfigField("String", "FRONTEGG_DOMAIN", "\"$fronteggDomain\"") buildConfigField("String", "FRONTEGG_CLIENT_ID", "\"$fronteggClientId\"") } } ``` br Add `bundleConfig=true` if not exists inside the android section inside the app gradle `android/app/build.gradle` ``` android { buildFeatures { buildConfig = true } } ``` ``` android { buildFeatures { buildConfig = true } } ``` ### Multi-apps support Prerequisites The use of this feature requires minimum @frontegg/android-kotlin@1.2.19 br This guide outlines the steps to configure your Android application to support multiple applications. 1. Modify the `Build.gradle` file ``` def fronteggApplicationId = "your-application-id-uuid" ... android { ... buildConfigField "String", 'FRONTEGG_APPLICATION_ID', "\"$fronteggApplicationId\"" } ``` ``` val fronteggApplicationId = "your-application-id-uuid" ... android { ... buildConfigField("String", "FRONTEGG_APPLICATION_ID", "\"$fronteggApplicationId\"") } ``` br 1. Modify the `App` file Add `BuildConfig`.`FRONTEGG_APPLICATION_ID` to `FronteggApp`.`init`. Example `App.kt` code: ``` class App : Application() { companion object { lateinit var instance: App } override fun onCreate() { super.onCreate() instance = this FronteggApp.init( BuildConfig.FRONTEGG_DOMAIN, BuildConfig.FRONTEGG_CLIENT_ID, this, BuildConfig.FRONTEGG_APPLICATION_ID, // here ) } } ``` ### Set permissions Add `INTERNET` permission to the app's manifest file. ``` ``` ### Configure Android ssetLinks Configuring your Android `AssetLinks` is required for Magic Link authentication / Reset Password / Activate Account / login with IdPs. To add your `AssetLinks` to your Frontegg application, you will need to update in each of your integrated Frontegg Environments the `AssetLinks` that you would like to use with that Environment. Send a POST request to `https://api.frontegg.com/vendors/resources/associated-domains/v1/android` with the following payload: ``` { "packageName": "YOUR_APPLICATION_PACKAGE_NAME", "sha256CertFingerprints": ["YOUR_KEYSTORE_CERT_FINGERPRINTS"] } ``` br Each Android app has multiple certificate fingerprint, to get your `DEBUG` sha256CertFingerprint you have to run the following command: For **debug mode**, run the following command and copy the `SHA-256` value **NOTE:** make sure to choose the Variant and Config equals to `debug` ``` ./gradlew signingReport ################### # Example Output: ################### # Variant: debug # Config: debug # Store: /Users/davidfrontegg/.android/debug.keystore # Alias: AndroidDebugKey # MD5: 25:F5:99:23:FC:12:CA:10:8C:43:F4:02:7D:AD:DC:B6 # SHA1: FC:3C:88:D6:BF:4E:62:2E:F0:24:1D:DB:D7:15:36:D6:3E:14:84:50 # SHA-256: D9:6B:4A:FD:62:45:81:65:98:4D:5C:8C:A0:68:7B:7B:A5:31:BD:2B:9B:48:D9:CF:20:AE:56:FD:90:C1:C5:EE # Valid until: Tuesday, 18 June 2052 ``` br For Release mode, Extract the SHA256 using keytool from your `Release` keystore file: ``` keytool -list -v -keystore /PATH/file.jks -alias YourAlias -storepass *** -keypass *** ``` ### Multi-region support This guide outlines the steps to configure your Android application to support multiple regions. 1. Remove buildConfigFields from your `build.gradle` file: ``` android { // remove this lines: // buildConfigField "String", 'FRONTEGG_DOMAIN', "\"$fronteggDomain\"" // buildConfigField "String", 'FRONTEGG_CLIENT_ID', "\"$fronteggClientId\"" } ``` ``` android { // remove these lines: // buildConfigField("String", "FRONTEGG_DOMAIN", "\"$fronteggDomain\"") // buildConfigField("String", "FRONTEGG_CLIENT_ID", "\"$fronteggClientId\"") } ``` br 1. Modify the `App` file First, adjust your `App.kt/java` file to handle multiple regions: **Modifications**: - **Remove** the existing `FronteggApp.init` function. - **Add** Call `FronteggApp.initWithRegions` with array of `regions`. This array will hold dictionaries for each region. Example `App.kt` code: br ``` class App : Application() { companion object { lateinit var instance: App } override fun onCreate() { super.onCreate() instance = this FronteggApp.initWithRegions( listOf( RegionConfig( "eu", "auth.davidantoon.me", "b6adfe4c-d695-4c04-b95f-3ec9fd0c6cca" ), RegionConfig( "us", "davidprod.frontegg.com", "d7d07347-2c57-4450-8418-0ec7ee6e096b" ) ), this ) } } ``` br 1. Add `AssetLinks` for each region For each region, configuring your Android `AssetLinks`. This is vital for proper API routing and authentication. Follow [Config Android AssetLinks](#config-android-assetlinks) to add your Android domains to your Frontegg application. 1. Add Intent-Filter in `Manifest.xml` 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` br ``` ``` br 1. Implement region relection UI The final step is to implement a UI for the user to select their region. **This can be done in any way you see fit. The example application uses a simple picker view to allow the user to select their region. **Important Considerations** - **Switching Regions**: To switch regions, update the selection in Shared Preferences. If issues arise, a **re-installation** of the application might be necessary. - **Data Isolation**: Ensure data handling and APIs are region-specific to prevent data leakage between regions. | Select EU Region | Select US Region | | --- | --- | | ![eu-region-example.gif](/assets/eu-region-example.b43215d2a725f9b73d803a3ee90bb3e87c695825f8767a08e4c31e5477dac47c.14341b2b.gif) | ![us-region-example.gif](/assets/us-region-example.ec48d044edc19e458a1bcabe98a0e8cc0e17cbf09a99ea37c0665d648456f715.14341b2b.gif) | br Example Region Selection UI: [example code](https://github.com/frontegg/frontegg-android-kotlin/blob/master/multi-region/src/main/java/com/frontegg/demo/RegionSelectionActivity.kt) ``` package com.frontegg.demo import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.LinearLayout import com.frontegg.android.FronteggApp class RegionSelectionActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_region_selection) } override fun onResume() { super.onResume() val euButton = findViewById(R.id.euButton) val usButton = findViewById(R.id.usButton) euButton.setOnClickListener { FronteggApp.getInstance().initWithRegion("eu") finish() } usButton.setOnClickListener { FronteggApp.getInstance().initWithRegion("us") finish() } } } ``` ### Embedded webview vs custom chrome tab Frontegg SDK supports two authentication methods: - Embedded Webview - Custom Chrome Tab By default Frontegg SDK will use Embedded Webview, to use Custom Chrome Tab you have to set remove embedded activity by adding below code to the application manifest: ``` ``` ### Initialize FronteggApp Create a custom `App` class that extends `android.app.Application` to initialize `FronteggApp`: ``` package com.frontegg.demo import android.app.Application import com.frontegg.android.FronteggApp class App : Application() { override fun onCreate() { super.onCreate() FronteggApp.init( BuildConfig.FRONTEGG_DOMAIN, BuildConfig.FRONTEGG_CLIENT_ID, this, // Application Context ) } } ``` br Register the custom `App` in the app's manifest file **AndroidManifest.xml:** ``` ``` ### Enabling chrome custom tabs for social login To enable social login via Chrome Custom Tabs, set the `useChromeCustomTabs` flag to `true` during the initialization of `FronteggApp`. By default, the SDK uses the Chrome browser for social login. br ``` FronteggApp.init( BuildConfig.FRONTEGG_DOMAIN, BuildConfig.FRONTEGG_CLIENT_ID, this, // Application Context // ... useChromeCustomTabs = true ) ``` br ### Login with Frontegg In order to login with Frontegg, you have to call `FronteggAuth.instance.login` method with `activtity` context. Login method will open Frontegg hosted login page, and will return user data after successful login. ``` import com.frontegg.android.FronteggAuth class FirstFragment : Fragment() { // ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding.loginButton.setOnClickListener { FronteggAuth.instance.login(requireActivity()) } } // ... } ``` ### Logout user In order to logout user, you have to call `FronteggAuth.instance.logout` method. Logout method will clear all user data from the device. ``` import com.frontegg.android.FronteggAuth class FirstFragment : Fragment() { // ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding.logoutButton.setOnClickListener { FronteggAuth.instance.logout() } } // ... } ``` ### Switch user's tenant In order to switch tenant, you have to call `FronteggAuth.instance.switchTenant` method with `activity` context. ``` import com.frontegg.android.FronteggAuth class FirstFragment : Fragment() { // ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tenantIds = FronteggAuth.instance.user.value?.tenantIds ?: listOf() /** * pick one from `tenantIds` list: */ val tenantToSwitchTo = tenantIds[0] binding.switchTenant.setOnClickListener { FronteggAuth.instance.switchTenant(tenantToSwitchTo) } } // ... } ```