Front-End Web & Mobile

Easy Sign-in and Sign-up UI with the AWS Mobile SDK for Android

Recently, we released v2.6.0 of the AWS Mobile SDK for Android and AWS Mobile SDK for iOS. It includes many improvements. This post focuses on two of these. First, you can integrate a JSON file with the configuration details of your mobile backend. The easiest way to generate this file is with AWS Mobile Hub. You can also generate the file yourself. Using the JSON file means that you don’t need to edit the Info.plist file (for iOS) or create a class of constants (for Android). You can use the same configuration file for both iOS and Android versions of the app.

Second, we integrated two features that were available only on the AWS Mobile Hub custom SDK. IdentityManager is for managing identity. It includes a UI component for each platform. The component makes it easier to develop a sign-in and sign-up screen. TransferManager is for managing file uploads and downloads. As with IdentityManager, it’s designed for integrating into the UI. Since the custom SDK features have been integrated into the standard SDK, we no longer have a custom SDK for AWS Mobile Hub users.

In this post, we walk through adding analytics and authentication to an existing Android app. The example app is a standalone note-taking app, which you can download from GitHub. Start by downloading and compiling the source code. Set up an emulator and run the code to see how it performs. We used the master-detail project so that the application is responsive to tablets and phones. The app was tested in the emulator for a Nexus 5X and a Pixel C on Android 7.1.1 (API level 25).

Set up the mobile backend

The app that you downloaded does not have any AWS libraries in it. So we start from the beginning. First, create an AWS Mobile Hub project and add features to it:

  • Open the AWS Mobile Hub console. If you do not have an AWS account, Sign up for the AWS Free Tier
  • If this is not your first project, click Create a new project.
  • Enter android-notes-app for the name of the Mobile Hub project.
  • Click Create project.
  • Click the User Sign-in tile.
  • Click Email and Password.
  • Scroll to the bottom of the page, and click Create user pool.

Analytics (powered by Amazon Pinpoint) is enabled automatically on all AWS Mobile Hub projects, so all we had to do was add User Sign-in (powered by Amazon Cognito). In this case, we accepted all of the defaults, which means the user can sign up with an email and password and the account is validated via email. The system works with multi-factor authentication as well. You can also include Facebook and Google social identities.

The next step is to generate the AWS configuration file.

  • Click Integrate in the left navigation pane.
  • Click Download in Step 1.

This downloads the awsconfiguration.json file that you need later. If you change your mobile backend later, ensure that you download the new awsconfiguration.json file and add it to your project.

Add the AWS Mobile SDK for Android to your project

To add the AWS Mobile SDK for Android, enable internet access within the manifest, add library dependencies to your build.gradle file, and add the awsconfiguration.json file to your project.

  • Open the project in Android Studio.
  • Click Project on the left side of the project if you cannot see the project browser.
  • Add the INTERNET, ACCESS_NETWORK_STATE, and ACCESS_WIFI_STATE permissions to the AndroidManifest.xml file:
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    
  • Edit the app/build.gradle file.  Add the following lines to the dependencies section:
    compile 'com.amazonaws:aws-android-sdk-core:2.6.0'
    compile 'com.amazonaws:aws-android-sdk-auth-core:2.6.0@aar'
    compile 'com.amazonaws:aws-android-sdk-pinpoint:2.6.0'
    compile 'com.amazonaws:aws-android-sdk-auth-ui:2.6.0@aar'
    compile 'com.amazonaws:aws-android-sdk-auth-userpools:2.6.0@aar'
    compile 'com.amazonaws:aws-android-sdk-cognitoidentityprovider:2.6.0'
    
  • Create a raw resource folder:
    • Expand the app folder.
    • Right-click the res folder.
    • Choose New > Android resource directory.
    • Select Resource type: raw.
    • Click OK.
  • Place the awsconfiguration.json file in the raw directory. If you cannot find the right directory, right-click the raw folder, then select Reveal in Finder. A new window with the location appears.

Many of the client connections, including those to Amazon Pinpoint and Amazon Cognito, require access to the application context and work better as a singleton. You can consolidate these items by creating a new class, called AWSProvider.java, as follows:

  • Expand app > Java
  • Right-click the com.amazonaws.mobile.samples.mynotes package.
  • Select New > Java Class.
  • Enter AWSProvider as the name and select Singleton as the kind.
  • Click OK.

The contents of the AWSProvider.java file are as follows:

package com.amazonaws.mobile.samples.mynotes;

import android.content.Context;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.mobile.auth.core.IdentityManager;
import com.amazonaws.mobile.auth.userpools.CognitoUserPoolsSignInProvider;
import com.amazonaws.mobile.config.AWSConfiguration;
import com.amazonaws.mobileconnectors.pinpoint.PinpointConfiguration;
import com.amazonaws.mobileconnectors.pinpoint.PinpointManager;

public class AWSProvider {
    private static AWSProvider instance = null;
    private Context context;
    private AWSConfiguration awsConfiguration;
    private PinpointManager pinpointManager;

    public static AWSProvider getInstance() {
        return instance;
    }

    public static void initialize(Context context) {
        if (instance == null) {
            instance = new AWSProvider(context);
        }
    }

    private AWSProvider(Context context) {
        this.context = context;
        this.awsConfiguration = new AWSConfiguration(context);

        IdentityManager identityManager = new IdentityManager(context, awsConfiguration);
        IdentityManager.setDefaultIdentityManager(identityManager);
		identityManager.addSignInProvider(CognitoUserPoolsSignInProvider.class);
    }

    public Context getContext() {
        return this.context;
    }

    public AWSConfiguration getConfiguration() {
        return this.awsConfiguration;
    }

    public IdentityManager getIdentityManager() {
        return IdentityManager.getDefaultIdentityManager();
    }

    public PinpointManager getPinpointManager() {
        if (pinpointManager == null) {
            final AWSCredentialsProvider cp = getIdentityManager().getCredentialsProvider();
            PinpointConfiguration config = new PinpointConfiguration(
                    getContext(), cp, getConfiguration());
            pinpointManager = new PinpointManager(config);
        }
        return pinpointManager;
    }
}

If you want to work with Amazon Pinpoint, call AWSProvider.getInstance().getPinpointManager().  You can do this with the IdentityManager as well.  Note that IdentityManager is set up as part of this class.  As you add features to the mobile backend, you likely need to add code to the AWSProvider class.  Initialize the AWSProvider in the Application class, as shown next:

public class Application extends MultiDexApplication {
  @Override
  public void onCreate() {
    super.onCreate();

    // Initialize the AWS Provider
    AWSProvider.initialize(getApplicationContext());

    registerActivityLifecycleCallbacks(new ActivityLifeCycle());
  }
}

Add Analytics to your app

The application includes an ActivityLifeCycle class in the Application.java file. This class provides callbacks that can hook into system events. Most notably, you can hook into the events that occur when the application is started and stopped. This allows you to send events to Amazon Pinpoint to record session duration and user demographics. Alter the onActivityStarted() and onActivityStopped() methods as follows:

  @Override
  public void onActivityStarted(Activity activity) {
    if (depth == 0) {
      Log.d("ActivityLifeCycle", "Application entered foreground");
      AWSProvider.getInstance().getPinpointManager().getSessionClient().startSession();
      AWSProvider.getInstance().getPinpointManager().getAnalyticsClient().submitEvents();
    }
    depth++;
  }

  @Override
  public void onActivityStopped(Activity activity) {
    depth--;
    if (depth == 0) {
      Log.d("ActivityLifeCycle", "Application entered background");
      AWSProvider.getInstance().getPinpointManager().getSessionClient().stopSession();
      AWSProvider.getInstance().getPinpointManager().getAnalyticsClient().submitEvents();
    }
  }

At this point, you can run the project and generate some events. After you run your application a few times, open the Amazon Pinpoint console. Select your Amazon Pinpoint project (the name is based on your Mobile Hub project name), and then click Analytics in the left navigation menu. You can also explore the Demographics charts, although they will not be interesting given the limited set of data you are working with.

Add Authentication to your app

You already configured the Identity Manager to use the Amazon Cognito user pools feature, so the only remaining task is to work on the authentication screen.

  • Right-click the com.amazonaws.mobile.samples.mynotes package.
  • Click New > Activity > Empty Activity.
  • Enter LoginActivity as the Activity Name.
  • Click Finish.
  • Click OK.

Edit the onCreate() method of the LoginActivity.java file as follows:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        final IdentityManager identityManager = AWSProvider.getInstance().getIdentityManager();
        // Set up the callbacks to handle the authentication response
        identityManager.setUpToAuthenticate(this, new DefaultSignInResultHandler() {
            @Override
            public void onSuccess(Activity activity, IdentityProvider identityProvider) {
                Toast.makeText(LoginActivity.this,
                        String.format("Logged in as %s", identityManager.getCachedUserID()),
                        Toast.LENGTH_LONG).show();
                // Go to the main activity
                final Intent intent = new Intent(activity, NoteListActivity.class)
                        .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                activity.startActivity(intent);
                activity.finish();
            }

            @Override
            public boolean onCancel(Activity activity) {
                return false;
            }
        });

        // Start the authentication UI
        AuthUIConfiguration config = new AuthUIConfiguration.Builder()
                .userPools(true)
                .build();
        SignInActivity.startSignInActivity(this, config);
        LoginActivity.this.finish();
    }

The AWS Mobile SDK for Android contains a built-in activity that handles the authentication UI. This activity sets up the authentication UI, and then sets up an activity listener to handle the response. After you get a successful sign-in, transition to NoteListActivity, which is the old front page of the application. You now make LoginActivity the first page that is loaded when the application loads. Adjust the AndroidManifest.xml file as follows:

<activity
    android:name=".LoginActivity"
    android:label="Sign In"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
  <activity
    android:name=".NoteListActivity"
    android:label="@string/app_name"
    android:theme="@style/AppTheme.NoActionBar">
    <!-- Remove the intent-filter from here -->
  </activity>

The LoginActivity activity section is added to the end of the file when you create the activity. Ensure that you do not duplicate the activity because that causes build errors.

Rebuild the project and run in the emulator. You should see a sign-in screen. Click the Create new account button to create a new account. After the information is submitted, you receive a configuration code via email. Enter the confirmation code to complete registration, and then sign in with your new account.

If you do not want to use your own email account as a test account, you can create an Amazon WorkMail service within AWS for test accounts. You can start for free with a 30-day trial for up to 25 accounts.

Next Steps

We hope you enjoyed this short tutorial. We will continue introducing new features of the SDK in this blog, so please check back often. If you have questions, you can reach us on the AWS Forums.