SDK quickstart
Use Signaling SDK to add low-latency, high-concurrency signaling and synchronization capabilities for real-time systems to your app. Signaling also helps you enhance the user experience in Video Calling, Voice Calling, Interactive Live Streaming, and Broadcast Streaming applications.
This page shows you how to use the Signaling SDK to rapidly build a simple application that sends and receives messages. It shows you how to integrate the Signaling SDK in your project and implement pub/sub messaging through Message channels. To get started with stream channels, follow this guide to create a basic Signaling app and then refer to the Stream channels guide.
Understand the tech
To use Signaling features in your app, you initialize a Signaling client instance and add event listeners. To connect to Signaling, you login using an authentication token. Each token is bound to a single user ID. To send a message to a message channel, you publish the message. Signaling creates a channel when a user subscribes to it. To receive messages other users publish to a channel, your app listens for events.
To create a pub/sub session for Signaling, implement the following steps in your app:
Prerequisites
To implement the code presented on this page you need to have:
- An Agora account and project.
- Enabled Signaling in Agora Console
- Android Studio 4.1 or higher.
- Android SDK API Level 24 or higher.
- A mobile device that runs Android 4.1 or higher.
-
A computer with Internet access.
Ensure that no firewall is blocking your network communication.
Project setup
Create a project
-
Create a new project.
- Open Android Studio and select File > New > New Project....
- Select Phone and Tablet > Empty Activity and click Next.
- Set the project name and storage path.
- Select Java as the language, and click Finish to create the project.
NoteAfter you create a project, Android Studio automatically starts gradle sync. Ensure that the synchronization is successful before proceeding to the next step. -
Add network permissions
Open the
/app/src/main/AndroidManifest.xml
file and add the following permissions before<application>
: -
Prevent code obfuscation
Open the
/app/proguard-rules.pro
file and add the following line to prevent code obfuscation:
Integrate the SDK
Use either of the following methods to integrate Signaling SDK into your project.
- Using CDN
- Using Maven Central
-
Download the latest version of Signaling SDK.
-
Copy all files in the
sdk
folder of the package to the/app/libs
folder of the project. -
To add the SDK reference, open the project file
/Gradle Scripts/build.gradle(Module: <projectname>.app)
and add the following code:-
Add a
ndk
node under the defaultConfig
node, to specify the supported architectures:Config { // ... ndk{ abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } }
infoSupporting all architectures increases the app size. Best practice is to only add essential architectures based on your targets. For most scenarios,
armeabi-v7a
andarm64-v8a
architectures are sufficient when releasing the Android app. -
Add a
sourceSets
node under theandroid
node to include the jni libraries copied to thelibs
folder:android { // ... sourceSets { main { jniLibs.srcDirs = ['libs'] } } }
-
To include all
jar
files in thelibs
folder as dependencies, add the following under thedependencies
node:dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // ... }
-
-
To ensure that the build script and all projects within the Gradle build have access to dependencies hosted on Maven Central, add the following code to
/Gradle Scripts/build.gradle(Project: <projectname>)
:buildscript { repositories { // ... mavenCentral() } // ... } allprojects { repositories { // ... mavenCentral() } }
infoIf your Android project uses
dependencyResolutionManagement
, there may be differences in how you add Maven Central dependencies. -
Add the following code to the
/Gradle Scripts/build.gradle(Module: <projectname>.app)
file to integrate the SDK into your Android project:dependencies { // ... implementation 'io.agora:agora-rtm:x.y.z' }
Replace
x.y.z
with the specific SDK version number, such as 2.1.10. To get the latest version number, check the Release notes.
To integrate Signaling SDK version 2.2.0 or above, and Video SDK version 4.3.0 or above at the same time, refer to handle integration issues.
Create a user interface
This section helps you create a simple user interface to explore the basic features of Signaling. Modify it according to your specific needs.
The demo interface consists of the following UI elements:
- Input boxes for user ID, channel name, and message
- Buttons to log in and log out of Signaling
- Buttons to subscribe and unsubscribe from a channel
- A button to publish a message
Sample code to create the user interface
Open the /app/res/layout/activity_main.xml
file, and replace the contents with the following:
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" tools:context=".MainActivity"> <EditText android:id="@+id/uid" android:layout_width="150dp" android:layout_height="40dp" android:layout_marginStart="36dp" android:layout_marginTop="48dp" android:autofillHints="" android:hint="@string/uid" android:inputType="text" android:lines="1" android:padding="5dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/logout_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="11dp" android:layout_marginTop="48dp" android:layout_marginEnd="28dp" android:onClick="onClickLogout" android:text="@string/logout_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toEndOf="@+id/login_button" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/login_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" android:layout_marginTop="48dp" android:layout_marginEnd="132dp" android:onClick="onClickLogin" android:text="@string/login_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toEndOf="@+id/uid" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/channel_name" android:layout_width="155dp" android:layout_height="41dp" android:layout_marginStart="36dp" android:layout_marginTop="124dp" android:layout_marginBottom="41dp" android:autofillHints="" android:ems="10" android:hint="@string/channel_name" android:inputType="text" app:layout_constraintTop_toBottomOf="@+id/uid" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/subscribe_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" android:layout_marginTop="28dp" android:layout_marginEnd="132dp" android:onClick="onClickSubscribe" android:text="@string/subscribe_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toEndOf="@+id/channel_name" app:layout_constraintTop_toBottomOf="@+id/login_button" /> <Button android:id="@+id/unsubscribe_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="11dp" android:layout_marginTop="27dp" android:layout_marginEnd="28dp" android:onClick="onClickUnsubscribe" android:text="@string/unsubscribe_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toEndOf="@+id/subscribe_button" app:layout_constraintTop_toBottomOf="@+id/logout_button" /> <EditText android:id="@+id/msg_box" android:layout_width="190dp" android:layout_height="57dp" android:layout_marginStart="37dp" android:layout_marginTop="195dp" android:layout_marginBottom="26dp" android:autofillHints="" android:ems="10" android:hint="@string/msg" android:inputType="textPersonName" android:singleLine="false" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/channel_name" /> <Button android:id="@+id/send_channel_msg_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="40dp" android:layout_marginEnd="40dp" android:onClick="onClickSendChannelMsg" android:text="@string/send_channel_msg_button" app:layout_constraintStart_toEndOf="@+id/msg_box" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/unsubscribe_button" /> <TextView android:id="@+id/message_history" android:layout_width="412dp" android:layout_height="339dp" android:layout_marginTop="392dp" android:background="#AEA8A8" android:freezesText="false" android:isScrollContainer="false" android:scrollbars="vertical" android:textColor="#2196F3" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.491" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.352" /></androidx.constraintlayout.widget.ConstraintLayout>
Open the app/res/values/strings.xml
file and add following string resources:
<resources> <string name="app_name">Signaling Quickstart</string> <string name="login_button">Login</string> <string name="logout_button">Logout</string> <string name="subscribe_button">Subscribe</string> <string name="unsubscribe_button">Unsubscribe</string> <string name="send_channel_msg_button">Publish message</string> <string name="uid">User ID</string> <string name="msg">Message content</string> <string name="channel_name">Channel name</string> <string name="app_id">your_appid</string> <string name="token">your_token</string></resources>
Replace your_appid
and your_token
values in the project resources
with your project's app ID and token. To quickly verify the basic functionality during the testing phase, set the authentication mode to debug mode when creating an Agora project, and then replace both your_appid
and your_token
values with your project's app ID.
Implement Signaling
A complete code sample that implements the basic features of Signaling is presented here for your reference. To use the sample code, copy the following lines into the /app/src/main/java/com/example/<projectname>/MainActivity.java
file and replace <projectname>
in package com.example.<projectname>
with the name of your project.
Complete sample code for Signalling
package com.example.<projectname>;import android.content.pm.ActivityInfo;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import io.agora.rtm.ErrorInfo;import io.agora.rtm.LockEvent;import io.agora.rtm.MessageEvent;import io.agora.rtm.PresenceEvent;import io.agora.rtm.PublishOptions;import io.agora.rtm.ResultCallback;import io.agora.rtm.RtmClient;import io.agora.rtm.RtmConfig;import io.agora.rtm.RtmConstants;import io.agora.rtm.RtmEventListener;import io.agora.rtm.RtmMessage;import io.agora.rtm.StorageEvent;import io.agora.rtm.SubscribeOptions;import io.agora.rtm.TopicEvent;public class MainActivity extends AppCompatActivity { private EditText etUserId; private EditText etChannelName; private EditText etMessageContent; // The user ID of the publisher private String mUserId; // The channel name of the message channel private String mChannelName; // The RTM client instance private RtmClient mRtmClient; // The TextView to show the messages that you send private TextView mMessageHistory; // Add the event listener private RtmEventListener eventListener = new RtmEventListener() { @Override public void onMessageEvent(MessageEvent event) { String text = "Message received from " + event.getPublisherId() + " Message: " + event.getMessage().getData() + "\n"; writeToMessageHistory(text); } @Override public void onPresenceEvent(PresenceEvent event) { String text = "receive presence event, user: " + event.getPublisherId() + " event: " + event.getEventType() + "\n"; writeToMessageHistory(text); } @Override public void onConnectionStateChanged(String mChannelName, RtmConstants.RtmConnectionState state, RtmConstants.RtmConnectionChangeReason reason) { String text = "Connection state changed to " + state + ", Reason: " + reason + "\n"; writeToMessageHistory(text); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { super.onDestroy(); } public void onClickLogin(View v) { try { etUserId = (EditText) findViewById(R.id.uid); mUserId = etUserId.getText().toString(); if (mUserId == null || mUserId.isEmpty()) { showToast("invalid userId"); return; } RtmConfig config = new RtmConfig.Builder(getBaseContext().getString(R.string.app_id), mUserId) .eventListener(eventListener) .build(); mRtmClient = RtmClient.create(config); } catch (Exception e) { showToast("create rtm client is null"); } if (mRtmClient == null) { showToast("rtm client is null"); return; } // Log in the RTM server String token =getBaseContext().getString(R.string.token); mRtmClient.login(token, new ResultCallback<Void>() { @Override public void onSuccess(Void responseInfo) { writeToMessageHistory("Successfully logged in to Signaling!\n"); } @Override public void onFailure(ErrorInfo errorInfo) { CharSequence text = "User: " + mUserId + " Failed to log in to Signaling!" + errorInfo.toString(); int duration = Toast.LENGTH_SHORT; runOnUiThread(new Runnable() { public void run() { Toast toast = Toast.makeText(getApplicationContext(), text, duration); toast.show(); } }); } }); } public void onClickSubscribe(View v) { if (mRtmClient == null) { showToast("rtm client is null"); return; } // Subscribe to a channel etChannelName = (EditText) findViewById(R.id.channel_name); mChannelName = etChannelName.getText().toString(); SubscribeOptions options = new SubscribeOptions(); options.setWithMessage(true); mRtmClient.subscribe(mChannelName, options, new ResultCallback<Void>() { @Override public void onSuccess(Void responseInfo) { writeToMessageHistory("Successfully subscribe to the channel!\n"); } @Override public void onFailure(ErrorInfo errorInfo) { writeToMessageHistory("Fail to subscribe to the channel!\n"); } }); } public void onClickLogout(View v) { if (mRtmClient == null) { showToast("rtm client is null"); } // Log out from the RTM server mRtmClient.logout(new ResultCallback<Void>() { @Override public void onSuccess(Void responseInfo) { writeToMessageHistory("Successfully log out from the channel!\n"); } @Override public void onFailure(ErrorInfo errorInfo) { writeToMessageHistory("Fail to log out from the channel!\n"); } }); } public void onClickUnsubscribe(View v) { if (mRtmClient == null) { showToast("rtm client is null"); return; } // Unsubscribe from a channel etChannelName = (EditText) findViewById(R.id.channel_name); mChannelName = etChannelName.getText().toString(); mRtmClient.unsubscribe(mChannelName, new ResultCallback<Void>() { @Override public void onSuccess(Void responseInfo) { writeToMessageHistory("Successfully unsubscribe from the channel!\n"); } @Override public void onFailure(ErrorInfo errorInfo) { writeToMessageHistory("Fail to unsubscribe from the channel!\n"); } }); } public void onClickSendChannelMsg(View v) { etMessageContent = findViewById(R.id.msg_box); String message = etMessageContent.getText().toString(); // Publish a message etChannelName = (EditText) findViewById(R.id.channel_name); mChannelName = etChannelName.getText().toString(); PublishOptions options = new PublishOptions(); options.setCustomType(""); mRtmClient.publish(mChannelName, message, options, new ResultCallback<Void>() { @Override public void onSuccess(Void responseInfo) { String text = "Message sent to channel " + mChannelName + " : " + message + "\n"; writeToMessageHistory(text); } @Override public void onFailure(ErrorInfo errorInfo) { String text = "Message fails to send to channel " + mChannelName + " Error: " + errorInfo + "\n"; writeToMessageHistory(text); } }); } // Write message history to TextView public void writeToMessageHistory(String record) { mMessageHistory = findViewById(R.id.message_history); mMessageHistory.append(record); } private void showToast(String text) { Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); }}
Follow the implementation steps to understand the core API calls in the sample code or use the snippets in your own code.
Import Agora classes
To use Signaling APIs in your project, import the relevant Agora classes and interfaces:
Initialize the Signaling engine
Before calling any other Signaling SDK API, initialize an RtmClient
object instance.
Add an event listener
The event listener enables you to implement the processing logic in response to Signaling events. Use the following code to handle event notifications or display received messages:
Log in to Signaling
To connect to Signaling and access Signaling network resources, such as sending messages, and subscribing to channels, call login
.
During a login operation, the client attempts to establish a connection with Signaling. Once the connection is established, the client transmits heartbeat information to the Signaling server at fixed intervals to keep the client active until the client actively logs out or is disconnected. The connection is interrupted when timeout occurs. During this period, users may freely access the Signaling network resources subject to their own permissions and usage restrictions.
Use the login
return value, or listen to the onConnectionStateChanged
event notification to confirm that login is successful or obtain the error code and cause of login failure. When performing a login operation, the client's network connection state is CONNECTING
. After a successful login, the state is updated to CONNECTED
.
To continuously monitor the network connection state of the client, best practice is to continue to listen for onConnectionStateChanged
event notifications throughout the life cycle of the application. For further details, see Event Listeners.
After a user successfully logs into Signaling, the application's PCU increases, which affects your billing data.
Send a message
To distribute a message to all subscribers of a message channel, call publish
. The following code sends a string type message.
Before calling publish
to send a message, serialize the message payload as a string. See Message payload serialization.
Subscribe and unsubscribe
To receive messages sent to a channel, call subscribe
to subscribe to channel messages:
When you no longer need to receive messages from a channel, call unsubscribe
to unsubscribe from the channel:
For more information about subscribing and sending messages, see Message channels and Stream channels.
Log out of Signaling
When a user no longer needs to use Signaling, call logout
. Logging out means closing the connection between the client and Signaling. The user is automatically logged out or unsubscribed from all message and stream channels. Other users in the channel receive an onPresenceEvent
notification of the user leaving the channel.
Test Signaling
Take the following steps to test the sample code:
-
In
strings.xml
, replace the values forapp_id
andtoken
with your App ID and token from Agora Console. -
Enable developer options on your Android test device. Turn on USB debugging, connect the Android device to your development machine through a USB cable, and check that your device appears in the Android device options.
-
In Android Studio, click Sync Project with Gradle Files to resolve project dependencies and update the configuration.
-
After synchronization is successful, click ▶️. Android Studio starts compilation. After a few moments, the app is installed and launched on your Android device.
-
Use the device as the receiving end and perform the following operations:
- Enter your User ID and click Login.
- Enter the Channel name and click Subscribe .
-
On a second Android device, repeat the previous steps to install and launch the app. Use this device as the sending end.
- Enter a different User ID and click Login.
- Enter the same Channel name.
- Type a message and click Publish message.
-
Swap the sending and receiving device roles and repeat the previous steps.
Congratulations! You have successfully integrated Signaling into your project.
Reference
This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.
Token authentication
In this guide you retrieve a temporary token from a Token Generator. To understand how to create an authentication server for development purposes, see Secure authentication with tokens.