Moxtra Chat SDK for Android

Use the Moxtra Chat SDK module to add rich collaboration to your app.

What features you will get with the SDK:

  • Ability to do one-on-one and/or group chats
  • Share files
  • Layer visual & voice annotations on top of files
  • Conduct real-time meetings

Let's get started by using a sample app "Moxie Chat". In this tutorial, you will learn how to integrate the Moxtra Chat SDK in your app.

The diagram below explains how the sample app "Moxie Chat" will interact with Moxtra.

App Architecture

Setup

Asynchronous programming

You should have some basic knowledge of asynchronous programming. This type of programming involves calling an API with a XXXListener parameter and then waiting for the listener callback before continuing with next steps.

Register

Before proceeding further, ensure you have registered your app with Moxtra.

Clone the sample project from github

Please clone the sample project MoxieChat from here:

git clone https://github.com/Moxtra/moxtra-chat-android-sample MoxieChat

  • If you don't have git installed, you can download and install git from http://git-scm.com.

  • To compare the differences in code for two tags, use the "git diff" command as shown in the example below:

    git diff step-07..step-08

    or use the github website diff tool:

    https://github.com/Moxtra/moxtra-chat-android-sample/compare/step-08...step-09

Step 0: Create an empty project in Android Studio

This tutorial uses Android Studio to create the sample app 'Moxie Chat'. Ensure you have installed Android Studio and the Android SDK (launch the SDK Manager in Android Studio and follow the setup wizard to install) before proceeding further.

You can start by creating an empty project using Android Studio.

OR, Create an empty project using our sample code from github:

git checkout -f step-00

Step 1: Add the Moxtra Chat SDK dependency

After creating the MoxieChat empty project, it's time to add the Moxtra Chat SDK dependency to it.

First, we need to add the Moxtra Maven Repo URL to let gradle knowns where do download the dependencies.

Edit the build.gradle under the MoxieChat and add the following code snippet:

maven() {
    url "http://maven.moxtra.com:8081/nexus/content/groups/public"
}

And add the following config to the build.gradle file in the app folder (in the android block):

enforceUniquePackageName = false
packagingOptions {
    exclude 'META-INF/maven/com.belerweb/pinyin4j/pom.properties'
    exclude 'META-INF/maven/com.belerweb/pinyin4j/pom.xml'
}
dexOptions {
    javaMaxHeapSize "2g"
}

Then let's add the following dependency to the build.gradle file in the app folder:

compile "com.moxtra:chat-sdk:${CHAT_SDK_VERSION}"

You can now sync the project with gradle files:

Tools -> Android -> Sync Project with Gradle Files

Make sure you do not have any compile errors before proceeding further.

Optionally you can checkout step 1 from github:

git checkout -f step-01

Step 2: Update AndroidManifest.xml

From Moxtra Chat SDK 3.0, no update required for the AndroidManifest.xml file.

You can checkout step 2 from github:

git checkout -f step-02

Step 3: Build scaffold and adding test data

In this step you will build the scaffold for your app and add some user data for testing.

The Moxtra Chat SDK has NO user management feature and it's up to you to define it. In this tutorial, you can use some test data.

You can checkout step 3 from github.

git checkout -f step-03

Step 4: Implement the login and logout functionality

This tutorial covers only the login/setup user flow related to Moxtra Chat SDK shown below.

The login flow looks like this:

Login Flow

You should initialize MXAccountManager when starting your app. For the purpose of this tutorial, you can initialize it in the MoxieChatApplication, and this class must be the subclass of MultiDexApplication as shown in the code snippet below:

@Override
public void onCreate() {
    super.onCreate();
    try {
        MXAccountManager.createInstance(this, "irej6RlLOBo", "uiwE8ZzymRs", true);
    } catch (MXSDKException.InvalidParameter invalidParameter) {
        Log.e(TAG, "Error when creating MXAccountManager instance.", invalidParameter);
    }
}

We pass clientId and clientSecret (2nd and 3rd paramters, you should replace it with your clientId and clientSecret when building your app) when create the MXAccountManager instnace. And by now, the isSandBox (the 4th parameter) was set to true for development. When you are ready to move into production, contact us.

The clientSecret should be confidential and you'd better to store it on your server side. It has two advantages:

  • Relatively secure and hard to hack in.
  • You can change the secret later and it will not impact your current distributted app client.

Next, setup the user in Moxtra. Add the following code snippet in the LoginActivity. It should be called when user successfully login to the app.

// Login success and then setup user on Moxtra
try {
    User user = PreferenceUtil.getUser(this);
    Bitmap avatar = BitmapFactory.decodeStream(this.getAssets().open(user.avatarPath));
    final MXSDKConfig.MXUserInfo mxUserInfo = new MXSDKConfig.MXUserInfo(user.email, MXSDKConfig.MXUserIdentityType.IdentityUniqueId);
    final MXSDKConfig.MXProfileInfo mxProfileInfo = new MXSDKConfig.MXProfileInfo(user.firstName, user.lastName, avatar);
    MXAccountManager.getInstance().setupUser(mxUserInfo, mxProfileInfo, null, null, this);
} catch (IOException e) {
    Log.e(TAG, "Can't decode avatar.", e);
}

The setupUser is an asynchronous operation and requires to pass a callback to it. The callback interface can be implemented as shown below:

@Override
public void onLinkAccountDone(boolean success) {
    if (success) {
        Log.i(TAG, "Linked to moxtra account successfully.");
        startChatListActivity();
    } else {
        Toast.makeText(this, "Failed to setup moxtra user.", Toast.LENGTH_LONG).show();
        Log.e(TAG, "Failed to setup moxtra user.");
        showProgress(false);
    }
}

After the user has successfully logged out from your app, unlink the Moxtra account. In MoxieChat (or in this tutorial, it is implemented in the BaseActivity Action Toolbar so the user can logout from any activity that extends BaseActivity).

MXAccountManager.getInstance().unlinkAccount(this);

You can checkout step 4 from github:

git checkout -f step-04

Step 5: Show the chat list

Two scenarios need to be considered when showing the chat list:

  • Initializing the chat list when a user opens your app
  • Updating the user of any updates to the chats when the user is inside the chat list UI of your app.

Now let's build the chat list using the MXChatManager API (used for all chat related calls). To get a singleton instance of the MXChatManager, you can use the following code snippet.

MXChatManager.getInstance()

When a user opens the chat list UI, you can call the following API to get all the chats:

List<MXGroupChatSession> sessions = MXChatManager.getInstance().getGroupChatSessions();

Note: MXGroupChatSession has two types of API calls. MXChatManager.openChat() is to open a Chat and MXChatManager.joinMeet(). is to join a Meet.

After getting a list of all chat sessions, you have to listen for changes so the UI can be updated automatically.

MXChatCustomizer.setOnMeetEndListener(new OnEndMeetListener() {
    @Override
    public void onMeetEnded(String meetId) {
        adapter.refreshData();
    }

    @Override
    public void onMeetEndFailed(int errorCode, String errorMessage) {
        Log.e(TAG, "onMeetEndFailed() called with: " + "errorCode = [" + errorCode + "], errorMessage = [" + errorMessage + "]");
    }
});

MXChatManager.getInstance().setGroupChatSessionCallback(new MXGroupChatSessionCallback() {
    @Override
    public void onGroupChatSessionCreated(MXGroupChatSession session) {
        adapter.refreshData();
    }

    @Override
    public void onGroupChatSessionUpdated(MXGroupChatSession session) {
        adapter.refreshData();
    }

    @Override
    public void onGroupChatSessionDeleted(MXGroupChatSession session) {
        adapter.refreshData();
    }
});

You can checkout the code for step 5 from github:

git checkout -f step-05

Step 6: Start a new chat

In the sample app, you now have an empty chat list.

You have to build the UI to select another user to chat by calling the following API:

MXChatManager.getInstance().createChat(topic, who, onCreateChatListener);

As you may have noticed from the last parameter in the API call, the onCreateChatListener is an asynchronous operation.

In the Moxtra Chat SDK, all operations with a Listener are asynchronous operations. The result of this asynchronous operation is not known until a callback is fired.

Use the code snippet below to implement the callback interface.

@Override
public void onCreateChatSuccess(String binderId) {
    Log.i(TAG, "Create Chat Success. The binderId = " + binderId);
}

@Override
public void onCreateChatFailed(int i, String s) {
    Log.e(TAG, "Failed to create chat with code: " + i + ", msg: " + s);
    Toast.makeText(this, "Failed to create chat: " + s, Toast.LENGTH_LONG).show();
}

Once the chat is created successfully, it will be open automatically.

You can checkout the code for step 6 from github:

git checkout -f step-06

Step 7: Open an existing chat

To open an existing chat from the chat list UI by calling the following API:

MXChatManager.getInstance().openChat(binderId, onOpenChatListener);

Use the code snippet below to implement the callback interface.

@Override
public void onOpenChatSuccess() {
    Log.i(TAG, "Open chat success.");
}

@Override
public void onOpenChatFailed(int i, String s) {
    Log.e(TAG, "Failed to open chat with code: " + i + ", msg: " + s);
    Toast.makeText(this, "Failed to open chat: " + s, Toast.LENGTH_LONG).show();
}

You can checkout the full code for step 7 from github.

git checkout -f step-07

Step 8: Start a meet

With Moxtra Chat SDK, you can easily start an audio/video meeting with a few lines of code. You can aslo share your screen and annotate documents inside the meeting.

This step is required only if you implement the start meet functionality outside the chat UI.

To start a meeting outside the Chat UI, use the following code snippet:

try {
    MXChatManager.getInstance().startMeet(currentLoginUser.firstName + "'s meet", null,
            arrayList, new MXChatManager.OnStartMeetListener() {
                @Override
                public void onStartMeetDone(String meetId, String meetUrl) {
                    Log.d(TAG, "Meet started: " + meetId);
                }

                @Override
                public void onStartMeetFailed(int i, String s) {
                    Log.e(TAG, "onStartMeetFailed: " + s);
                }
            });
} catch (MXSDKException.Unauthorized unauthorized) {
    Log.e(TAG, "Error when start meet", unauthorized);
} catch (MXSDKException.MeetIsInProgress meetIsInProgress) {
    Log.e(TAG, "Error when start meet", meetIsInProgress);
}

Please implement the callback interface to determine if the meeting was started successfully.

You can checkout the full code for step 8 from github.

git checkout -f step-08

Step 9: Join a meet

Invited users should be able to join a meeting. Use this code snippet to implement the join meeting functionality.

try {
    MXChatManager.getInstance().joinMeet(session.getMeetID(), currentLoginUser.firstName,
            new MXChatManager.OnJoinMeetListener() {
                @Override
                public void onJoinMeetDone(String meetId, String meetUrl) {
                    Log.d(TAG, "Joined meet: " + meetId);
                }

                @Override
                public void onJoinMeetFailed() {
                    Log.e(TAG, "Unable to join meet.");
                }
            });
} catch (MXSDKException.MeetIsInProgress meetIsInProgress) {
    Log.e(TAG, "Error when join meet", meetIsInProgress);
}

You can checkout the full code of step 9 from github:

git checkout -f step-09

Step 10: Delete Chat

Every chat that is created is a persistent chat. Chat messages are saved over time, so new and old chat members can see all the chat history at any time.

If you have a chat that is no longer required, then it can be deleted. Use this code snippet to implement the Delete Chat functionality.

MXChatManager.getInstance().deleteChat(binderId);

You can checkout the code for step 10 from github.

git checkout -f step-10

Step 11: Enable notifications

Notification is an essential feature for a real-time communication app. For this example you will use GCM (Google Cloud Messaging) based solution for notifications. You can also use long-connection if for some reason GCM cannot be used, for details on using long-connection please click here.

Get API Key from Google Developer Console:

  • Go to https://console.developers.google.com/project
  • Click on Create Project or use an existing project
  • Go to the project overview page and note down the Project Number.
  • Click APIs under APIs & auth section and then click Cloud Messaging for Android to make sure the API is enabled. If not, please enable now.
  • Click Credentials under APIs & auth section and get the API Key. If you don't have any API Key, please click Create new Key and select Server key to create.

Now, you need to set the API key in the Moxtra developer console so that the GCM server will not refuse the notification.

  • Go to My Apps
  • Find your app and click Edit application
  • Scroll to the bottom of the page and you will find the section "For Android devices".
  • Set the API Key and click Update to save the key to your app configuration.

Next, you need to write code to register the device when a user logs in successfully. Please check Integrate Google Cloud Messaging for more details. Note that the project number is the GCM sender ID.

On successful user login and registration of the device, get the register id (regid) from the GCM server. Use the regid in the Setup User call as shown in the code snippet below:

try {
    User user = PreferenceUtil.getUser(this);
    Bitmap avatar = BitmapFactory.decodeStream(this.getAssets().open(user.avatarPath));
    MXSDKConfig.MXUserInfo mxUserInfo = new MXSDKConfig.MXUserInfo(user.email, MXSDKConfig.MXUserIdentityType.IdentityUniqueId);
    MXSDKConfig.MXProfileInfo mxProfileInfo = new MXSDKConfig.MXProfileInfo(user.firstName, user.lastName, avatar);
    MXAccountManager.getInstance().setupUser(mxUserInfo, mxProfileInfo, null, regid, this);
} catch (IOException e) {
    Log.e(TAG, "Can't decode avatar.", e);
}

The Moxtra server can now send notification to the device if registered. In order to show the notifications, please refer to Integrate Google Cloud Messaging. In this tutorial the Moxtra related code is highlighted the Moxtra related part here.

After getting a notification, call MXNotificationManager.preProcessMXNotification to preprocess it and check if it is a Moxtra message.

boolean handled = MXNotificationManager.preProcessMXNotification(getApplicationContext(), intent);
if (handled) {
    // This is a moxtra message and it will be handled by moxtra
    if (intent.getBooleanExtra(MXNotificationManager.MOXTRA_MESSAGE_SHOW_NOTIFICATION, false)) {
        String title = intent.getStringExtra(MXNotificationManager.MOXTRA_MESSAGE_TITLE_TEXT);
        if (intent.hasExtra(MXNotificationManager.MOXTRA_MESSAGE_ALERT_SOUND)) {
            String soundUrl = intent.getStringExtra(MXNotificationManager.MOXTRA_MESSAGE_ALERT_SOUND);
            Log.d(TAG, "soundUrl = " + soundUrl);
            Uri uri = Uri.parse(soundUrl);
            sendMoxtraNotification(title, uri, intent);
        } else {
            sendMoxtraNotification(title, intent);
        }
    }
} else {
    // Not a moxtra message and app should handle it.
    Log.i(TAG, "App should handle it.");
}

If it is a moxtra message, process and send the notification as shown in the code snippet below:

// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendMoxtraNotification(String msg, Intent intent) {
    sendMoxtraNotification(msg, null, intent);
}

private void sendMoxtraNotification(String msg, Uri uri, Intent intent) {
    Log.d(TAG, "Got notification: msg = " + msg + ", uri = " + uri);
    mNotificationManager = (NotificationManager)
            this.getSystemService(Context.NOTIFICATION_SERVICE);

    PendingIntent contentIntent = MXNotificationManager.getMXNotificationIntent(this, intent, 0);

    NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle(getString(getApplicationInfo().labelRes))
                    .setStyle(new NotificationCompat.BigTextStyle()
                            .bigText(msg))
                    .setContentText(msg)
                    .setAutoCancel(true)
                    .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE);

    if (uri != null) {
        mBuilder.setSound(uri);
    }

    mBuilder.setContentIntent(contentIntent);
    mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}

You can checkout the code for step 11 from github:

git checkout -f step-11

Step 12: Prepare for release

In order to prepare your app for release, you should set up the signing configuration. If you decide to set minifyEnabled to true, don't forget to update the proguard rules.

You can checkout the proguard rules used in this tutorial from github.

git checkout -f step-12

Download/Install Chat SDK

To build your own implementation add the Moxtra Android Chat SDK into your project as mentioned in Step 1: Add Moxtra SDK and compile using the following version.

compile "com.moxtra:chat-sdk:3.4.6"

Current Version

V 3.4.6 (December 15th 2016)

API Reference

This tutorial covers only a few APIs. For a full list of APIs, please refer to our Android Chat SDK: API Reference Guide.