实现首次通话
适用于 Android 的 CallPlus 可在您的应用程序中为用户之间的一对一和多人通信提供语音和视频通话能力。
CallPlus 支持 一对一通话 和 多人通话。按照下面的指南使用 Java 或 Kotlin 从头开始实现一对一通话和多人通话。
环境要求
适用于 Android 的 CallPlus SDK 的最低要求是:
Android 5 (API level 21) or higher
Java 8 or higher
前置条件
-
注册开发者账号。注册成功后,控制台会默认自动创建您的首个应用,默认生成开发环境下的 App Key,使用国内数据中心。
-
获取开发环境的应用 App Key。如不使用默认应用,请参考 如何创建应用,并获取对应环境 App Key 和 App Secret。
注意
每个应用具有两个不同的 App Key,分别对应开发环境与生产环境,两个环境之间数据隔离。在您的应用正式上线前,可切换到使用生产环境的 App Key,以便上线前进行测试和最终发布。
-
完成开通音视频服务。您需要开通音视频通话服务。
Demo 项目
融云提供了一个 Android 端 Demo 项目,集中演示了通话、会议、直播场景下的功能。
https://github.com/rongcloud/rtc-quickdemo-android
快速上手
您可以通过安装 CallPlus for Android 进行一对一通话,或多人通话。
步骤 1 创建项目
首先,打开 Android Studio 并在 Project 窗口中创建一个新项目,如下所示:
- 在 Welcome to Android Studio 窗口中点击 Start a new Android Studio project。
- 选择 Empty Activity,接着点击 Next。
- 在 Name 字段中输入您的项目名称。
- 从语言下拉菜单中选择您的语言 Java or Kotlin。
- 选择最低 API 级别为 21 或更高。
步骤 2 导入 SDK
Gradle
使用 Gradle,添加融云音视频通话能力库 CallPlus 为远程依赖项。请注意使用 融 云的 Maven 仓库。
-
打开根目录下的
build.gradle
(Project 视图下),声明融云的 Maven 代码库。allprojects {
repositories {
...
//融云 maven 仓库地址
maven {url "https://maven.rongcloud.cn/repository/maven-releases/"}
}
} -
在应用的
build.gradle
中,添加对 IMLibCore 和 CallPlus 的远程依赖项。融云 CallPlus 业务依赖 IM 通道,所以必须同时集成 IMLibCore SDK(最低使用 5.6.3 版本)。dependencies {
// x.y.z,请填写具体的 SDK 版本号,新集成用户建议使用最新版。
implementation 'cn.rongcloud.sdk:im_libcore:x.y.z' // 即时通讯基础能 力库。
implementation 'cn.rongcloud.sdk:callplus_lib:x.y.z'// 音视频呼叫能力库
implementation 'cn.rongcloud.sdk:rtc_lib:x.y.z' // 音视频通话基础能力库
}
注意
各个 SDK 的最新版本号可能不相同,还可能是 x.y.z.h,可前往 融云官网 SDK 下载页面 或 融云的 Maven 代码库 查询。 自 2.1.1 版本起,callplus_lib 内不再包含 rtc_lib。在使用 callplus_lib 的同时,还需要引入 rtc_lib。
Android 本地库模块 (Module)
在导入 SDK 前,您需要前往融云官网 SDK 下载页面,将音视频通话能力-CallPlusLib及其依赖的即时通讯能力库-IMLib 和 音视频基础能力-RTCLib 下载到本地。
-
将
rong_callplus_x.y.z.aar
文件复制到 Android Studio 项目的 libs 目录下,在应用的build.gradle
中,添加*.aar
依赖。 -
依次点击 File > New > Import Module,将
imlib
和rtclib
的 Module 组件导入。dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation project(path: ':imlib')
implementation project(path: ':rtclib')
}
步骤 3 权限配置
-
在 AndroidManifest.xml 中声明 SDK 需要的所有权限。
<!-- 允许程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许程序获取网络信息状态,如当前的网络连接是否有效 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 允许程序获取当前WiFi接入的状态以及WLAN热点的信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许程序访问摄像头进行拍照 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 允许程序录制声音通过手机或耳机的麦克 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 允许程序修改声音设置信息 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!--允许程序访问电话状态,如通话中收到来自SIM卡的来电时,会将SIM卡通话状态通知给远端用户,所以需要该权限-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> -
如果您的应用需要支持 Android 6.0(API 级别 23)或更高版本的设备,您还需要在 App 用户使用对应功能时(例如发起呼叫、接听)请求摄像头(
CAMERA
)、麦克风(RECORD_AUDIO
)权限。详见 Android 开发者官方文档运行时权限与请求权限的工作流。
步骤 4 代码混淆
当您使用 minifyEnabled true
构建 APK 时,将以下行添加到模块的 ProGuard
规则文件中。
-keepattributes Exceptions,InnerClasses
-keepattributes Signature
# imlib
-keep class io.rong.** {*;}
-keep class cn.rongcloud.** {*;}
-keep class * implements io.rong.imlib.model.MessageContent {*;}
-dontwarn io.rong.push.**
-dontnote com.xiaomi.**
-dontnote com.google.android.gms.gcm.**
-dontnote io.rong.**
#rtclib
-keep public class cn.rongcloud.rtc.** {*;}
-keep public class cn.rongcloud.rtclib.** {*;}
#callpluslib
-keep public class cn.rongcloud.calllib.** {*;}
-keep public class cn.rongcloud.callplus.** {*;}
-ignorewarnings
步骤 5 使用 App Key 初始化
CallPlus for Android 是依赖融云即时通讯客户端 SDK 提供信令通道。要在您的应用程序中集成和运行,您需要先对 IMLibCore
进行初始化。
融云即时通讯客户端 SDK 核心类为 RongCoreClient
和 RongIMClient
。在 Application 的 onCreate()
方法中,调用 RongCoreClient
的初始化方法,传入生产或开发环境的 App Key。
String appKey = "Your_AppKey"; // example: bos9p5rlcm2ba
InitOption initOption = new InitOption.Builder().build();
RongCoreClient.init(getApplicationContext(), appKey, initOption);
初始化配置(InitOption
)中封装了区域码(AreaCode),导航服务地址(naviServer
)、文件服务地址(fileServer
)、数据统计服务地址(statisticServer
)配置,以及是否开启推送的开关(enablePush
)和主进程开关(isMainProcess
)。您可以传 null
,表示全部使用默认配置。SDK 默认连接北京数据中心。
如果 App Key 不属于中国(北京)数据中心,则必须传入有效的初始化配置。
步骤 6 添加通话所需监听
使用 setCallPlusEventListener 方法添加通话事件监听 IRCCallPlusEventListener。该监听提供来电事件、通话状态、通话记录等事件相关回调。通过 setCallPlusEventListener(null);
可移除监听器。
注意
如果未注册
IRCCallPlusEventListener
监听器,则用户无法接收onReceivedCall
回调事件。请务必在下一步与融云服务器建立连接(connect
)之前使用setCallPlusEventListener
注册监听,否则用户在未连接的情况下无法通过离线推送接收来电通知。
RCCallPlusClient.getInstance().setCallPlusEventListener(new IRCCallPlusEventListener() {
/**
* 本端用户通过该回调接收到通话呼叫
*
* @param callSession 通话实体信息
*/
@Override
public void onReceivedCall(RCCallPlusSession callSession, String extra) {
RCCallPlusSession currentCallSession = RCCallPlusClient.getInstance().getCurrentCallSession();
if (currentCallSession != null && !TextUtils.equals(callSession.getCallId(), currentCallSession.getCallId())) {
//可以使用该方法判断出,有正在进行中的通话,又有第二通通话呼入的情况
//todo 第二通通话可以直接调用 RCCallPlusClient.getInstance().accept 方法接听,SDK内部会将第一通通话挂断
}
//todo SDK 的回调均为子线程调用
// showDialog() 方法中存在UI操作,所以切换到主线程执行
// showDialog() 方法实现可参考附录
runOnUiThread(new Runnable() {
@Override
public void run() {
//todo 打开摄像头采集,请提前完成摄像头、麦克风权限的动态申请
RCCallPlusClient.getInstance().startCamera();
RCCallPlusClient.getInstance().enableMicrophone(true);
setLocalVideoView();//复用发起通话逻辑中的 设置本地视频渲染视图 方法
showDialog(CallPlusActivity.this, "收到通话,是否接听?", "接听", new OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
acceptCall(callSession);
}
}, "挂断", new OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
RCCallPlusClient.getInstance().hangup();
}
});
}
});
}
@Override
public void onCallEnded(RCCallPlusSession session, RCCallPlusReason reason) {
IRCCallPlusEventListener.super.onCallEnded(session, reason);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(CallPlusActivity.this,"通话结束,callId: "+session.getCallId() +" 通话结束原因:"+ reason.getValue(), Toast.LENGTH_SHORT).show();
}
});
}
/**
* 远端用户状态改变监听
*
* @param callId 通话Id
* @param userId 用户Id
* @param status 该用户当前状态
* @param reason 该用户当前状态原因
*/
@Override
public void onRemoteUserStateChanged(String callId, String userId, RCCallPlusUserSessionStatus status, RCCallPlusReason reason) {
IRCCallPlusEventListener.super.onRemoteUserStateChanged(callId, userId, status, reason);
runOnUiThread(new Runnable() {
@Override
public void run() {
StringBuilder stringBuilder = new StringBuilder("通话 ");
stringBuilder.append(callId).append(" 中的远端用户 ").append(userId).append(" 当前状态为 ");
switch (status) {
case IDLE:
stringBuilder.append("空闲");
break;
case CALLING:
stringBuilder.append("呼叫中");
break;
case INVITED:
stringBuilder.append("被邀请中");
break;
case RINGING:
stringBuilder.append("响铃中");
break;
case BUSY_LINE_RINGING:
stringBuilder.append("忙线(响铃中)");
break;
case BUSY_LINE_WAIT:
stringBuilder.append("忙线(通话中)");
break;
case CONNECTING:
stringBuilder.append("已接听,连接中");
break;
case ON_CALL:
stringBuilder.append("通话中");
break;
case ENDED:
stringBuilder.append("通话已结束");
break;
case NO_ANSWER:
stringBuilder.append("未应答");
break;
case MISSED:
stringBuilder.append("未接听");
break;
case CANCELED:
stringBuilder.append("已取消");
break;
case DECLINED:
stringBuilder.append("已拒 绝");
break;
case ERROR:
stringBuilder.append("错误");
break;
}
Toast.makeText(CallPlusActivity.this, stringBuilder.toString(), Toast.LENGTH_SHORT).show();
}
});
}
});
使用 setCallPlusResultListener 方法添加通话 API 异步结果回调监听 IRCCallPlusResultListener。该监听可以接收 startCall
、accept
、hangup
等方法的结果回调。通过 setCallPlusResultListener(null);
可移除监听器。
RCCallPlusClient.getInstance().setCallPlusResultListener(new IRCCallPlusResultListener() {
/**
* 发起通话方法结果回调
*
* @param code 方法请求结果
* @param callId 通话Id
* @param busyUserList 呼叫成功后,返回被邀请人列表中的忙线用户列表
*/
@Override
public void onStartCall(RCCallPlusCode code, String callId, List<RCCallPlusUser> busyUserList) {
IRCCallPlusResultListener.super.onStartCall(code, callId, busyUserList);
}
/**
* 接听通话结果回调
*
* @param code 方法请求结果
* @param callId 通话Id
*/
@Override
public void onAccept(RCCallPlusCode code, String callId) {
IRCCallPlusResultListener.super.onAccept(code, callId);
}
/**
* 挂断指定通话结果回调
*
* @param code 方法请求结果
* @param callId 通话Id
*/
@Override
public void onHangup(RCCallPlusCode code, String callId) {
IRCCallPlusResultListener.super.onHangup(code, callId);
}
});