Deferring Login in Native Android Apps
When you create Mobile SDK apps using forcedroid, forcedroid bases your project on a template app that gives you lots of free standard functionality. For example, you don’t have to implement authentication—login and passcode handling are built into your launcher activity. This design works well for most apps, and the free code is a big time-saver. However, after you’ve created your forcedroid app you might find reasons for deferring Salesforce authentication until some point after the launcher activity runs.
- Replace the launcher activity (named MainActivity in the template app) with an activity that does
not extend any of the following Mobile SDK activities:
- SalesforceActivity
- SalesforceListActivity
- SalesforceExpandableListActivity
- Do not call the peekRestClient() or the getRestClient() ClientManager method from your launcher activity or from any other pre-authentication activities.
- Do not change the initNative() call in the TemplateApp class. It must point to the activity class that launches after authentication (MainActivity in the template app).
- When you’re ready to authenticate with Salesforce, launch the MainActivity class.
The following example shows how to place a non-Salesforce activity ahead of Salesforce authentication. You can of course expand and embellish this example with additional pre-authentication activities, observing the preceding guidelines and caveats. This example is based on the MobileSyncExplorer sample app.
-
Create an XML layout for the pre-authentication landing page of your
application. For example, the following layout file,
launcher.xml, contains only a button that triggers the
login flow.
1<?xml version="1.0" encoding="utf-8"?> 2 3<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:orientation="vertical" 7 android:background="@android:color/white" 8 android:id="@+id/root"> 9 10 <Button android:id="@+id/login_button" 11 android:layout_width="80dp" 12 android:layout_height="60dp" 13 android:text="@string/login" 14 android:textColor="@android:color/black" 15 android:textStyle="bold" 16 android:gravity="center" 17 android:layout_gravity="center" 18 android:textSize="18sp" 19 android:onClick="onLoginClicked" /> 20</LinearLayout> -
Create a landing screen activity. For example, here’s a landing screen activity
named LauncherActivity. This screen simply
inflates the XML layout defined in launcher.xml. This class
must not extend any of the Salesforce activities
or call peekRestClient() or getRestClient(), since these calls trigger the
authentication flow. When the user taps the login button, the onLoginClicked() button handler launches MainActivity, and login ensues.
- Kotlin
-
1class LauncherActivity : Activity() { 2 public override fun onCreate(savedInstance: Bundle?) { 3 super.onCreate(savedInstance) 4 setContentView(R.layout.launcher) 5 } 6 7 /** 8 * Callback received when the 'Delete' button is clicked. 9 * 10 * @param v View that was clicked. 11 */ 12 fun onLoginClicked(v: View) { 13 /* 14 * TODO: Add logic here to determine if we are already 15 * logged in, and skip this screen by calling 16 * 'finish()', if that is the case. 17 */ 18 val mainIntent = Intent(this, MainActivity::class.java) 19 mainIntent.addCategory(Intent.CATEGORY_DEFAULT) 20 startActivity(mainIntent) 21 finish() 22 } 23} - Java
-
1package com.salesforce.samples.mobilesyncexplorer.ui; 2 3import com.salesforce.samples.mobilesyncexplorer.R; 4 5import android.app.Activity; 6import android.content.Intent; 7import android.os.Bundle; 8import android.view.View; 9 10public class LauncherActivity extends Activity { 11 @Override 12 public void onCreate(Bundle savedInstance) { 13 super.onCreate(savedInstance); 14 setContentView(R.layout.launcher); 15 } 16 17 /** 18 * Callback received when the 'Delete' button is clicked. 19 * 20 * @param v View that was clicked. 21 */ 22 public void onLoginClicked(View v) { 23 /* 24 * TODO: Add logic here to determine if we are already 25 * logged in, and skip this screen by calling 26 * 'finish()', if that is the case. 27 */ 28 final Intent mainIntent = 29 new Intent(this, MainActivity.class); 30 mainIntent.addCategory(Intent.CATEGORY_DEFAULT); 31 startActivity(mainIntent); 32 finish(); 33 } 34}
-
Modify the AndroidManifest.xml to specify LauncherActivity as the activity to be launched
when the app first starts.
1<!-- Launcher screen --> 2<activity android:name= 3"com.salesforce.samples.mobilesyncexplorer.ui.LauncherActivity" 4 android:label="@string/app_name" 5 android:theme="@style/SalesforceSDK.ActionBarTheme"> 6 <intent-filter> 7 <action android:name="android.intent.action.MAIN" /> 8 <category 9 android:name="android.intent.category.LAUNCHER" /> 10 </intent-filter> 11</activity> 12 13<!-- Main screen --> 14<activity android:name= 15"com.salesforce.samples.mobilesyncexplorer.ui.MainActivity" 16 android:label="@string/app_name" 17 android:theme="@style/SalesforceSDK.ActionBarTheme"> 18 <intent-filter> 19 <category android:name= 20 "android.intent.category.DEFAULT" /> 21 </intent-filter> 22</activity>