Implementing Deferred Login With the Salesforce Mobile SDK for Android

If you've built a Mobile SDK project with forcedroid, then later decide to move the Salesforce login to a point after launch, this example can help.

When you use forcedroid to create Salesforce Mobile SDK for Android apps, forcedroid bases your project on a template app. The template app 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 launch.

As the example below shows, you can defer authentication easily and still keep the template app’s built-in functionality. Just be sure to follow these guidelines:

  • Change the launcher activity setting (which references MainActivity in the template app) to point to an activity that does not extend any of the following Mobile SDK classes:
    • SalesforceActivity
    • SalesforceListActivity
    • SalesforceExpandableListActivity

    This rule also applies to any other activities that run before you authenticate with Salesforce.

  • Do not call ClientManager.peekRestClient() or ClientManager.getRestClient() from your launcher activity or from any other pre-authentication activities.
  • Do not change the initNative() method in the TemplateApp class. This method must point to the first activity class that launches after Salesforce authentication, which is MainActivity in the template app.
  • When you’re ready to authenticate with Salesforce, launch the MainActivity class.

The following example shows how to insert a non-Salesforce launcher activity ahead of Salesforce authentication. You can of course embellish this example with additional pre-authentication activities, following the guidelines and caveats discussed above.

1. Create an XML layout for the pre-authentication landing page of your application. The following layout file,
launcher.xml, is a bare-bones example that contains a single login button.

Here’s the launcher.xml listing:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/white"
android:id="@+id/root">
<Button android:id="@+id/login_button"
android:layout_width="80dp"
android:layout_height="60dp"
android:text="@string/login"
android:textColor="@android:color/black"
android:textStyle="bold"
android:gravity="center"
android:layout_gravity="center"
android:textSize="18sp"
android:onClick="onLoginClicked" />
</LinearLayout>

Note This layout uses a string resource, @string/login, that is defined in the res/strings.xml file as follows:

<string name="login">Log in</string>

2. Create a landing screen activity to launch the app. For example, here’s one 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.

package com.salesforce.samples.smartsyncexplorer.ui;
import com.salesforce.samples.smartsyncexplorer.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class LauncherActivity extends Activity {
	@Override
	public void onCreate(Bundle savedInstance) {
		super.onCreate(savedInstance);
		setContentView(R.layout.launcher);
	}

	/**
	* Callback received when the 'Delete' button is clicked.
	*
	*@param v View that was clicked.
	*/
	public void onLoginClicked(View v) {
		/*
		* TODO: Add logic here to determine if we are already logged in,
		* and skip this screen by calling 'finish()', if that is the case.
                * MainActivity calls LoginActivity, so we don't need to call 
                * LoginActivity directly here.
		*/
		final Intent mainIntent = new Intent(this, MainActivity.class);
		mainIntent.addCategory(Intent.CATEGORY_DEFAULT);
		startActivity(mainIntent);
		finish();
	}
}

3. Modify AndroidManifest.xml to specify LauncherActivity as the activity to be launched when the app first
starts. Also, change the category of the MainActivity class to android.intent.category.DEFAULT.

<!-- Launcher screen -->
<activity android:name="com.salesforce.samples.smartsyncexplorer.ui.LauncherActivity"
          android:label="@string/app_name"
          android:theme="@style/SalesforceSDK.ActionBarTheme">
 <intent-filter>
   <action android:name="android.intent.action.MAIN" />
   <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
</activity>

<!-- Main screen -->
<activity android:name="com.salesforce.samples.smartsyncexplorer.ui.MainActivity"
          android:label="@string/app_name"
          android:theme="@style/SalesforceSDK.ActionBarTheme">
 <intent-filter>
   <category android:name="android.intent.category.DEFAULT" />
 </intent-filter>
</activity>

When you start the application. the LauncherActivity screen appears. Click the login button to initiate the Salesforce authentication flow. After authentication completes, the app launches MainActivity.

Published
March 27, 2015

Leave your comments...

Implementing Deferred Login With the Salesforce Mobile SDK for Android