Sendbird Desk通过实时应用内支持增强客户参与度。 Desk SDK 可让您轻松初始化、配置客户支持相关功能并将其构建到 Android 应用程序中。
Sendbird Desk 是 Sendbird 聊天平台的一个插件,用于管理工单,所有 Desk 事件都通过 Chat SDK 处理。
每张工单都会被分配适当的代理,并将被定向到聊天组频道,该频道使用 Sendbird Chat SDK 在工单上实现实时消息传递。
这些是 Desk SDK 的一些主要组件。
发件人 | 亚型 | |
---|---|---|
用户留言 | 代理或客户 | 丰富的消息 |
管理员留言 | 从 Desk 服务器发送,没有特定发件人 | 通知消息和系统消息 |
注意:丰富消息进一步分为 URL 预览、工单关闭确认请求和反馈请求消息。
在适用于 Android 的 Desk SDK 文档中了解有关适用于 Android 的 Sendbird Desk SDK 的更多信息。如果您对错误和功能请求有任何意见或疑问,请访问 Sendbird 社区。
本部分显示使用适用于 Android 的 Sendbird Desk SDK 需要检查的先决条件。
Android 5.0 (API level 21) or higher
Java 8 or higher
Support androidx only
Android Gradle plugin 4.0.1 or higher
Sendbird Chat SDK for Android 4.0.3 and later
本部分为您提供开始使用适用于 Android 的 Sendbird Desk SDK 所需的信息。
我们的示例应用程序演示了 Sendbird Desk SDK 的核心功能。从我们的 GitHub 存储库下载该应用程序,了解您可以使用实际 SDK 做什么,并开始构建您自己的项目。
Sendbird 应用程序包含聊天服务所需的一切,包括用户、消息和频道。创建应用程序:
无论何种平台,每个应用程序只能集成一个 Sendbird 应用程序;然而,该应用程序支持跨所有 Sendbird 提供的平台进行通信,无需任何额外的设置。
注意:所有数据仅限于单个应用程序的范围,因此不同Sendbird应用程序中的用户无法互相聊天。
如果您熟悉使用外部库或 SDK,那么安装聊天 SDK 会很简单。首先,将以下代码添加到根build.gradle
文件中:
allprojects {
repositories {
.. .
maven { url " https://repo.sendbird.com/public/maven " }
}
}
注意:确保上述代码块未添加到您的模块
bundle.gradle
文件中。
然后,将依赖项添加到项目的顶级build.gradle
文件中。
dependencies {
implementation ' com.sendbird.sdk:sendbird-desk-android-sdk:1.1.4 '
}
注意:Desk SDK 版本
1.0.12
或更低版本可以在 2022 年 2 月 1 日之前从 JCenter 下载。高于1.0.12
的 SDK 版本将在 Sendbird 的远程存储库中提供。
或者,您可以从此存储库下载 Desk SDK。将 Desk SDK 复制到您的libs/
文件夹中,并确保将该库也包含在您的build.gradle
文件中。
安装完成后,可以创建票证以供代理和客户之间的通信。请按照以下分步说明创建您的第一张票证。
首先,启动客户端应用程序时必须初始化“SendBirdDesk”实例。在“Application.onCreate()”上调用“SendbirdChat.init()”和“SendBirdDesk.init()”。 SendbirdChat.init() 应首先通过仪表板中 Sendbird 应用程序的 APP_ID 进行初始化。
public class MyApplication extends Application {
@ Override
public void onCreate () {
super . onCreate ();
final InitParams initParams = new InitParams ( APP_ID , this , false );
SendbirdChat . init ( initParams , new InitResultHandler () {
@ Override
public void onMigrationStarted () {
}
@ Override
public void onInitFailed ( SendbirdException e ) {
// If initializing fails, this method is called.
}
@ Override
public void onInitSucceed () {
// If initializing is successful, this method is called and you can proceed to the next step.
// You can use all Sendbird APIs, including Connect, after init is completed in your app.
SendBirdDesk . init ();
}
});
}
}
注意:Desk 和 Chat SDK 应使用相同的
APP_ID
。如果您使用另一个App_ID
的 Sendbird 实例启动 Sendbird Desk,客户端应用程序中的所有现有数据都将被清除。
您可以在客户端应用程序中仅使用聊天 SDK,也可以同时使用聊天和桌面 SDK,具体取决于您想要提供的聊天服务。
软件开发工具包 | 用于 |
---|---|
聊天软件开发工具包 | 应用内消息程序,客户可以在其中互相聊天。 |
聊天和桌面 SDK | 客户可以与客服人员聊天的门票。 |
public class MyApplication extends Application {
@ Override
public void onCreate () {
super . onCreate ();
final InitParams initParams = new InitParams ( APP_ID , this , false );
SendbirdChat . init ( initParams , new InitResultHandler () {
@ Override
public void onMigrationStarted () {
}
@ Override
public void onInitFailed ( SendbirdException e ) {
// If initializing fails, this method is called.
}
@ Override
public void onInitSucceed () {
// If initializing is successful, this method is called and you can proceed to the next step.
// You can use all Sendbird APIs, including Connect, after init is completed in your app.
SendBirdDesk . init ();
}
});
}
}
客户可以通过各种类型的渠道请求支持:应用内聊天或 Facebook、Instagram 和 Twitter 等社交媒体。要使用 Desk SDK 的这些支持功能, SendBirdDesk
实例应根据请求来自哪个通道与 Sendbird 服务器连接:
authenticate()
方法及其用户ID 进行身份验证。通过身份验证后,客户可以基于 Sendbird Chat 平台与代理进行实时聊天。
SendbirdChat . connect ( userId , accessToken , new ConnectHandler () {
@ Override
public void onConnected ( User user , SendbirdException e ) {
if ( e != null ) { // error.
return ;
}
// Use the same user Id and access token used in the SendbirdChat.connect().
SendBirdDesk . authenticate ( userId , accessToken , new SendBirdDesk . AuthenticateHandler () {
@ Override
public void onResult ( SendbirdException e ) {
if ( e != null ) { //error.
return ;
}
// SendBirdDesk is now initialized, and the customer is authenticated.
}
});
}
});
注: Sendbird Chat 平台的客户是指已经通过 Chat SDK 进行身份验证的用户。如果您同时实施 Chat SDK 和 Desk SDK,请首先使用用户 ID 和访问令牌将用户连接到 Sendbird 服务器。
实现Ticket.create()
方法以在客户发出初始消息之前或之后创建新票证。
Ticket . create ( ticketTitle , userName , new Ticket . CreateHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // error
return ;
}
// The ticket is created. Agents and customers can chat with each other by sending a message through the ticket.getChannel().sendUserMessage() or sendFileMessage().
}
});
在 Sendbird 服务器上成功创建票证后,您可以通过服务器的回调在ticket.getChannel()
中访问该票证及其通道。
在客户发送第一条消息之前,客服人员无法在仪表板中看到工单,并且不会进行工单分配。对话开始时,工单会通过 Desk Dashboard 分配给可用的客服人员,同时通过聊天 SDK 发送和接收消息。
创建工单时您可以使用以下参数。
注意:仅需要定义 Groupkey 和 customFields,并且只能从仪表板访问。
争论 | 类型 | 描述 |
---|---|---|
TICKET_TITLE | 细绳 | 指定票证的标题。 |
USER_NAME | 细绳 | 指定提交或接收票证的用户的名称。 |
组键 | 细绳 | 指定特定团队的标识符。 |
自定义字段 | 嵌套对象 | 指定由键值自定义项组成的工单的附加信息。只有已在仪表板的“设置” > “工单字段”中注册的自定义字段才能用作密钥。 |
优先事项 | 细绳 | 指定票证的优先级值。值越高代表优先级越高。有效值为LOW 、 MEDIUM 、 HIGH和URGENT 。 |
RELATED_CHANNEL_URLS | 大批 | 指定 Sendbird Chat 平台中与此工单相关的群组频道,由频道 URL 和频道名称组成。最多可以添加 3 个相关频道。 |
Map < String , String > customFields = new HashMap <>();
customFields . put ( "product" , "desk" );
customFields . put ( "line" , "14" );
customFields . put ( "select" , "option2" );
Ticket . create ( TICKET_TITLE , USER_NAME ,
"cs-team-1" , // GROUP_KEY
customFields , // CUSTOM_FIELDS
PRIORITY ,
RELATED_CHANNEL_URLS ,
new Ticket . CreateHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// The ticket is created with parameters.
}
}
);
本节详细介绍了从客户端应用程序处理和关闭票证的过程。
使用ticket.setCustomFields()
方法添加有关特定工单的附加信息。
Map < String , String > customFields = new HashMap <>();
customFields . put ( "product" , "Desk" );
customFields . put ( "line" , String . valueOf ( 30 ));
ticket . setCustomFields ( customFields , new Ticket . SetCustomFieldHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// Custom fields for the ticket are set.
// Some fields can be ignored if their keys aren't registered in the dashboard.
}
});
注意:只有在仪表板的“桌面” > “设置” > “工单字段”中注册的自定义字段才能用作密钥。
使用“SendBirdDesk”的setCustomerCustomFields()
方法让您的客户添加有关他们自己的附加信息。
注意:只有在仪表板的“桌面” > “设置” > “客户字段”中注册的自定义字段才能用作密钥。
Map < String , String > customFields = new HashMap <>();
customFields . put ( "gender" , "female" );
customFields . put ( "age" , String . valueOf ( 30 ));
SendBirdDesk . setCustomerCustomFields ( customFields , new SendBirdDesk . SetCustomerCustomFieldsHandler () {
@ Override
public void onResult ( SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// Custom fields for the customer are set.
// Some fields can be ignored if their keys aren't registered in the dashboard.
}
});
使用SendBirdDesk
的setCustomerCustomFields()
方法让您的客户添加有关他们自己的附加信息。
注意:只有在仪表板的“设置” > “客户字段”中注册的自定义字段才能用作键。
Map < String , String > customFields = new HashMap <>();
customFields . put ( "gender" , "female" );
customFields . put ( "age" , String . valueOf ( 30 ));
SendBirdDesk . setCustomerCustomFields ( customFields , new SendBirdDesk . SetCustomerCustomFieldsHandler () {
@ Override
public void onResult ( SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// Custom fields for the customer are set.
// Some fields can be ignored if their keys aren't registered in the dashboard.
}
});
相关频道是指Sendbird Chat平台中与工单相关的群组频道。创建票证时,将相关组频道的channel_url
作为参数传递给Ticket.create()
方法中的relatedChannelUrls
参数。要更新相关频道,请改用ticket.setRelatedChannelUrls()
。回调中的ticket.relatedChannels
属性表示相关频道的组频道对象,它包含频道名称及其URL。
ticket . setRelatedChannelUrls ( RELATED_CHANNEL_URLS , new Ticket . SetRelatedChannelUrlsHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// The ticket.relatedChannels property has been updated.
}
});
注意:每张票最多可以添加 3 个相关频道。
通过 URL 预览,您的应用程序用户可以在对话期间打开链接之前满足他们对将要获得的内容的期望。
要预览 URL,应检查每条短信是否包含 URL。当包含 URL 的文本消息成功发送后,应使用getUrlPreview()
方法提取 URL 并将其传递到 Sendbird 服务器。将从服务器接收到的解析数据设置为JSON
对象,并将该对象字符串化以将其作为参数传递给updateUserMessage()
方法中的参数。然后,带有 URL 预览的更新消息通过通道事件处理程序的onMessageUpdated()
方法传递到客户端应用程序。
ticket . getChannel (). sendUserMessage ( TEXT , new UserMessageHandler () {
@ Override
public void onResult ( UserMessage userMessage , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
List < String > urls = extractUrlsFromMessage ( userMessage . getMessage ());
if ( urls . size () > 0 ) {
String strUrlPreview = toJsonString ( getOGTagsWithUrl ( urls . get ( 0 )));
UserMessageUpdateParams updateParams = new UserMessageUpdateParams ( TEXT );
updateParams . setData ( strUrlPreview );
updateParams . setCustomType ( "SENDBIRD_DESK_RICH_MESSAGE" );
ticket . getChannel (). updateUserMessage ( userMessage . getMessageId (), updateParams , new UserMessageHandler () {
@ Override
public void onResult ( UserMessage userMessage , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
}
});
}
}
});
注意:转到Github页面并参考示例代码中的
updateUserMessageWithUrl()
和UrlPreviewAsyncTask
类。您将了解如何实现上述示例代码中的方法,例如extractUrlsFromMessage()
、getOGTagsWithUrl()
和toJsonString()
,它们不是实际代码,但旨在帮助您了解要使用的整体流程网址预览。
在通道事件处理程序的onMessageUpdated()
方法中,您可以在message.data
属性中找到 URL 预览的数据,如下所示。
{
"type" : " SENDBIRD_DESK_URL_PREVIEW " ,
"body" : {
"url" : " https://sendbird.com/ " ,
"site_name" : " Sendbird " ,
"title" : " Sendbird - A Complete Chat Platform, Messaging and Chat SDK and API " ,
"description" : " Sendbird's chat, voice and video APIs and SDKs connect users through immersive, modern communication solutions that drive better user experiences and engagement. " ,
"image" : " https://6cro14eml0v2yuvyx3v5j11j-wpengine.netdna-ssl.com/wp-content/uploads/sendbird_thumbnail.png "
}
}
管理消息是系统发送的可自定义消息,有 2 种类型的管理消息。通知是发送并显示给客户和代理的消息,例如欢迎消息或延迟消息。系统消息是当工单发生某些更改(例如工单状态和受托人发生更改)时发送并在工单详细信息视图中显示给客服人员的消息。
注意:您可以在仪表板中的“桌面” > “设置” > “触发器”中自定义通知,并在“桌面” > “设置” > “系统消息”中自定义系统消息。
当客户端应用程序通过通道事件处理程序的 'onMessageReceived()' 方法接收消息时,系统消息与通知消息通过message.custom_type
的值进行区分,并且它们的子类型在message.data
中指定,如下所示。
{
"message_id" : 40620745 ,
"type" : " ADMM " ,
"custom_type" : " SENDBIRD_DESK_ADMIN_MESSAGE_CUSTOM_TYPE " ,
"data" : " { " type " : " SYSTEM_MESSAGE_TICKET_ASSIGNED_BY_SYSTEM " , " ticket " : <Ticket Object>} " ,
"message" : " The ticket is automatically assigned to Cindy. "
}
注意:只有当
data
具有SYSTEM_MESSAGE_TICKET_TRANSFERRED_BY_AGENT
时才会出现transfer
。
系统消息仅供代理显示。请参阅以下示例代码以避免向您的客户显示它们。
public static boolean isVisible ( BaseMessage message ) {
if ( message instanceof AdminMessage ) {
String data = message . getData ();
if (! TextUtils . isEmpty ( data )) {
String customType = message . getCustomType ();
boolean isSystemMessage = ADMIN_MESSAGE_CUSTOM_TYPE . equals ( customType );
JsonObject dataObj = new JsonParser (). parse ( data ). getAsJsonObject ();
String type = dataObj . get ( "type" ). getAsString ();
return ! isSystemMessage
&& ! EVENT_TYPE_ASSIGN . equals ( type )
&& ! EVENT_TYPE_TRANSFER . equals ( type )
&& ! EVENT_TYPE_CLOSE . equals ( type );
}
}
return true ;
}
虽然管理员有权直接关闭工单,但客服人员可以像管理员一样关闭工单,也可以询问客户是否关闭工单,具体取决于客服人员权限设置。确认请求消息可以有如下3种状态。
状态 | 描述 |
---|---|
等待 | 当代理发送确认请求消息时设置。 |
确认的 | 当客户同意关闭工单时设置。 (默认值: true ) |
拒绝 | 当客户拒绝关闭工单时设置。 (默认值: false ) |
当客户回复消息时,通过调用Ticket.confirmEndOfChat()
方法,响应 true(同意)或 false(拒绝)将作为CONFIRMED
或DECLINED
发送到 Sendbird 服务器。
ticket . confirmEndOfChat ( USER_MESSAGE , true | false , new Ticket . ConfirmEndOfChatHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// You can update the UI of the message. For example, you can hide YES and No buttons.
}
});
{
"type" : " SENDBIRD_DESK_INQUIRE_TICKET_CLOSURE " ,
"body" : {
"state" : " CONFIRMED "
}
}
您可以在关闭票证后立即向客户发送消息,询问他们对通过票证提供的支持是否满意。当仪表板中的客户满意度评分功能打开时,客户将收到一条消息,要求评分并留下评论作为反馈。该消息可以有以下 2 种状态。
状态 | 描述 |
---|---|
等待 | 设置代理发送客户反馈请求消息的时间。 |
确认的 | 当客户发送响应时设置。 |
当客户回复消息时,他们对工单的分数和评论将通过调用ticket.submitFeedback()
方法发送到 Desk 服务器。然后,确认请求消息的状态变为CONFIRMED
。
ticket . submitFeedback ( USER_MESSAGE , SCORE , COMMENT , net Ticket . SubmitFeedbackHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
}
});
Sendbird Desk 服务器通过通道事件处理程序的onMessageUpdate()
方法向客户的客户端应用程序通知更新。
public void onMessageUpdated ( final BaseChannel channel , final BaseMessage message ) {
Ticket . getByChannelUrl ( channel . getUrl (), new Ticket . GetByChannelUrlHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) return ;
String data = message . getData ();
if (! TextUtils . isEmpty ( data )) {
JsonObject dataObj = new JsonParser (). parse ( data ). getAsJsonObject ();
String type = dataObj . get ( "type" ). getAsString ();
boolean isFeedbackMessage = "SENDBIRD_DESK_CUSTOMER_SATISFACTION" . equals ( type );
if ( isFeedbackMessage ) {
JsonObject feedback = dataObj . get ( "body" ). getAsJsonObject ();
String state = feedback . get ( "state" ). getAsString ();
switch ( state ) {
case "CONFIRMED" :
// TODO: Implement your code for the UI when there is a response from the customer.
break ;
case "WAITING" :
// TODO: Implement your code for the UI when there is no response from the customer.
break ;
}
}
}
}
});
}
注意:您可以在通道事件处理程序的
onMessageUpdate()
方法内的message.data
属性中找到以下字符串化JSON
对象。
{
"type" : " SENDBIRD_DESK_CUSTOMER_SATISFACTION " ,
"body" : {
"state" : " CONFIRMED " ,
"customerSatisfactionScore" : 3 ,
"customerSatisfactionComment" : " It was really helpful :) "
}
}
可以使用Ticket
中的reopen()
方法重新打开已关闭的工单。
ticket . reopen ( new Ticket . ReopenHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
}
});
您可以使用Ticket.getOpenedList()
和Ticket.getClosedList()
检索当前客户的打开和关闭工单列表。
您可以为客户设计未处理票证和已关闭票证历史记录的收件箱活动。零是一个很好的起始值,那么每次调用将按最后一条消息创建时间降序排列最多返回 10 个票证。
注意:每个请求只能检索 10 个票证,按消息创建时间降序排列。
// getOpenedList()
Ticket . getOpenedList ( OFFSET , new Ticket . GetOpenedListHandler () {
@ Override
public void onResult ( List < Ticket > tickets , boolean hasNext , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// offset += tickets.size(); for the next tickets.
// TODO: Implement your code to display the ticket list.
}
});
// getClosedList()
Ticket . getClosedList ( OFFSET , new Ticket . GetClosedListHandler () {
@ Override
public void onResult ( List < Ticket > tickets , boolean hasNext , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// offset += tickets.size(); for the next tickets.
// TODO: Implement your code to display the ticket list.
}
});
对于设置了自定义字段的工单,您可以向getOpenList()
和getClosedList()
添加过滤器,以按自定义字段的键和值对工单进行排序。
Map < String , String > customFieldFilter = new HashMap <>();
customFieldFilter . put ( "subject" , "doggy_doggy" );
Ticket . getOpenedList ( OFFSET , customFieldFilter , new Ticket . GetOpenedListHandler () {
@ Override
public void onResult ( List < Ticket > tickets , boolean hasNext , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
List < Ticket > openedTicket = tickets ;
// offset += tickets.length; for the next tickets.
// TODO: Implement your code to display the ticket list.
}
});
您可以检索特定票证及其频道 URL。
Ticket . getByChannelUrl ( channel . getUrl (), new Ticket . GetByChannelUrlHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
}
});
您可以使用Ticket.getOpenCount()
在客户端应用程序上显示未处理票证的数量。
Ticket . getOpenCount ( new Ticket . GetOpenCountHandler () {
@ Override
public void onResult ( int count , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// TODO: Implement your code with the result value.
}
});
使用ticket.close()
方法允许客户直接在其客户端应用程序上关闭工单,以便客服人员可以快速切换到其他客户查询,而无需延迟或无需客户确认。
ticket . close ( CLOSE_COMMENT , new Ticket . CloseHandler () {
@ Override
public void onResult ( Ticket ticket , SendbirdException e ) {
if ( e != null ) { // Error.
return ;
}
// TODO: Implement your code to close a ticket.
}
});
如果 API 请求失败,处理程序中的SendbirdException
参数将包含有关错误的信息。
财产 | 描述 |
---|---|
代码 | SendBirdError.ERR_REQUEST_FAILED (800220) |
信息 | 带有特定错误代码的详细错误消息(如果存在)。 |