Getting started with Sinch In-app Calling for Android SDK
This guide shows you how to get started integrating your Android application with the In-app Calling SDK. Because this is just a getting started guide, we only covers basic steps how to sign in to the In-app Calling SDK and how to make and receive audio calls.
Notes:
This guide is meant to be used side by side with our samples available in the SDK
Code snippets shown in the guide are part of 'sinch-rtc-sample-push' sample available on our download page inside the SDK archive.
Please follow along with the samples open in your IDE.
For more complex examples and documentation, check inside the SDK package file or look at our tutorials.
Prerequisites
- Android Studio and Android SDK tools available here.
- In-app Calling SDK for Android.
- For convenience 2 physical Android devices (however 1 physical and 1 emulator is enough for testing purposes)
Create Android Studio project
Create a new Android Studio project using the 'Empty activity' template.
Notes:
- You can use Kotlin as your development language in both Java and Kotlin versions of the SDK.
- The name of your application doesn't need to correspond to the one provided in the Sinch Dashboard.
Add Sinch Voice and Video SDK to your Android application
- In your web browser, go to Sinch SDKs Download page.
- Find the Android SDK for Java, download the zip file and extract it.
- Along with the library itself, the package also contains documentation and sample applications. For the purpose of this tutorial only the aar file is needed. Locate it inside the 'libs' folder and copy it to your clipboard.
- Paste it to
<your android application name>/app/libs
directory. - Edit your app's build.gradle file located under
app/build.gradle
to include the following: app/build.gradle
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation(name:'sinch-android-rtc', version:'+', ext:'aar')
///
}
You should see a message that gradle files have changed. Click Sync now and wait for Android Studio to adopt your changes.
Interacting with Voice and Video SDK
TheSinchClient
object is the main SDK entry point. Once created it's used to provide various SDKs features such as video, audio or PTSN calls. We recommend to initiate SinchClient
once and retain its instance during the whole lifetime of the running application. That's why instead of placing it inside Activity or Fragment classes we recommend to put it inside a Service component.- Create a new Kotlin class that extends Service component (don't forget to define the service in your AndroidManifest.xml file).
- Add
SinchClient
instance as a member variable. - Create a function that builds the client.
The result of these steps is demonstrated below:
class SinchService : Service() {
companion object {
private const val APP_KEY = "enter-application-key"
private const val APP_SECRET = "enter-application-secret"
private const val ENVIRONMENT = "ocra.api.sinch.com"
}
private var sinchClient: SinchClient? = null
private fun createClient(username: String) {
sinchClient = SinchClient.builder().context(applicationContext)
.userId(username)
.applicationKey(APP_KEY)
.environmentHost(ENVIRONMENT)
.pushConfiguration(
PushConfiguration.fcmPushConfigurationBuilder()
.senderID(APP_FCM_SENDER_ID)
.registrationToken(getFcmRegistrationToken(this).orEmpty()).build()
)
.pushNotificationDisplayName("User $username")
.build()
sinchClient?.addSinchClientListener(MySinchClientListener())
sinchClient?.callController?.addCallControllerListener(SinchCallControllerListener())
}
///
}
To make this example work for you, you need to update some values:
Parameter | Your value |
---|---|
APP_KEY | You can find your key on your dashboard. |
APP_SECRET | You can find your secret on your dashboard. Your secret is only available to view right after creating your key, so make sure you copy it somewhere safe. |
pushConfiguration | FCM or HMS push configuration needed by the SDK to send push messages notifying about incoming calls. See push notifications section for more information. |
There are a few other elements to notice:
- The
environmentHost
parameter is the endpoint of the REST API the SDK is targeting. - The
UserId
parameter is the user identifier to register within your application (the specific value will be provided after clicking Login button in the Android application).
onCredentialsRequired
method executes. Inside this callback you must provide a signed (with your application secret) JWT token. In a production application the token should be generated on your backend infrastructure. Most importantly you shouldn't put your app secret value into your Android application source code. More information on that topic can be found in Authentication & Authorization and Authorizing the Client sections.Just for this step-by-step guide purpose we will mimic a backend authentication server behaviour with a helper JWT
class that creates the token based on userId and your application credentials locally and then passes it back to Sinch SDK: override fun onCredentialsRequired(clientRegistration: ClientRegistration) {
clientRegistration.register(create(APP_KEY, APP_SECRET, settings.username))
}
Implementation of the JWT class can be found in any of samples provided with the SDK package.
(For example, check outsamples/sinch-rtc-sample-push/src/com/sinch/android/rtc/sample/push/JWT.kt
)Communication between views and service
To communicate between your application view layer (activities and fragments) and the Sinch client that lives inside the Service instance, we implement a bound service pattern. Information about what's a bound service and how it works can be found on the official Android SDK documentation website.
- Inside
SinchService
create an inner class that extendsBinder
. - Add basic functionality that allows the application to start Sinch client for a given username and provide a way to be notified about the initialization result:
private var listener: StartFailedListener? = null interface StartFailedListener { fun onFailed(error: SinchError) fun onStarted() } inner class SinchServiceInterface : Binder() { fun startClient() { // The username is fetched from settings. start() } fun setStartListener(listener: StartFailedListener?) { this@SinchService.listener = listener } }
- Override
onBind
method to returnSinchServiceBinder
private val sinchServiceInterface: SinchServiceInterface = SinchServiceInterface() override fun onBind(intent: Intent): IBinder { ... return sinchServiceInterface }
Logging into the application
When the user starts the application, usually they must enter a username that will be passed asuserId
and used to create a Sinch client. The username they choose will then be used as a callee identifier for making the actual audio call.- Rename
MainActivity
andactivity_main.xml
files inside AndroidStudio (that were initially created after setting up the project) toLoginActivity
andlogin.xml
. Right click on the filename and chooseRefactor -> Rename
. - Create a simple layout containg EditText (for entering the username) and login button.
<LinearLayout android:id="@+id/userNameInput" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical" android:paddingLeft="@dimen/margin_big" android:paddingRight="@dimen/margin_big"> <com.google.android.material.textfield.TextInputLayout style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/input_layout_bottom" android:layout_marginTop="@dimen/margin_big" android:hint="@string/enter_your_id" app:startIconDrawable="@drawable/ic_baseline_person_24_black" app:startIconTint="@color/colorPrimaryDark"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/loginName" android:inputType="text" android:imeOptions="actionDone" android:layout_width="match_parent" android:layout_height="wrap_content" /> </com.google.android.material.textfield.TextInputLayout> </LinearLayout> <com.google.android.material.button.MaterialButton android:id="@+id/loginButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_gravity="center_horizontal" android:layout_marginStart="@dimen/margin_average" android:layout_marginEnd="@dimen/margin_average" android:layout_marginBottom="@dimen/margin_average" android:padding="@dimen/margin_base_plus" android:text="@string/login" android:textColor="@color/white" app:backgroundTint="@color/sinch_green" />
- Inside the
LoginActivity
file first bind to the Sinch client service by callingNote that as a second argumentprivate fun bindService() { val serviceIntent = Intent(this, SinchService::class.java) applicationContext.bindService(serviceIntent, this, BIND_AUTO_CREATE) }
LoginActivity
is passed, meaning it has to implement the Service Connection interface. - Inside
onServiceConnected
in BaseActivity callback assign provided binder to a local variable for later usage for communicating with the service and assignLoginActivity
as a listener to get notifications about success or failure when starting Sinch client.BaseActivity
protected var sinchServiceInterface: SinchService.SinchServiceInterface? = null private set override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) { if (SinchService::class.java.name == componentName.className) { sinchServiceInterface = iBinder as SinchService.SinchServiceInterface onServiceConnected() } } protected open fun onServiceConnected() { // for subclasses }
LoginActivity
override fun onServiceConnected() { if (sinchServiceInterface?.isStarted == true) { openPlaceCallActivity() } else { sinchServiceInterface?.setStartListener(this) } }
- Finally assign the login button a click listener that initiates and starts the Sinch client:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // loginButton.apply { setOnClickListener { loginClicked() } } } private fun loginClicked() { val username = loginNameEditText.text.toString() sinchServiceInterface?.username = username startClientAndOpenPlaceCallActivity() }
- Return to SinchService implementation. Inside
onClientStarted
andonClientFailed
callbacks ofSinchClientListener
simply pass the result to thesinchClientInitializationListener
.override fun onClientFailed(client: SinchClient, error: SinchError) { listener?.onFailed(error) ... } override fun onClientStarted(client: SinchClient) { listener?.onStarted() }
- Before launching the application declare 2 permissions inside your
AndroidManifest.xml
file that are required to start the SinchClient:<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
- Run the application, enter a username of your choice and verify your logcat output. You should see that the client was started successfully.
Next steps
Now that your application is created, you can configure that application to make a call.