前段時間,做了個佳信客服的對接。在這裏做個記錄。
資源地址:
SDK下載路徑:
https://www.rongcloud.cn/downloads
接入融雲–佳信客服
https://www.rongcloud.cn/docs/customer_service.html#jiaxin
文檔:
https://www.rongcloud.cn/docs/android_imlib.html#客服
融雲獲取token
https://www.rongcloud.cn/docs/server.html#user_get_token
融雲–佳信客服–客服管理:
https://developer.rongcloud.cn/CustomerJiaXin/base/Kal0xrpnVB4nQWrIKoA=
佳信客服–後臺管理–坐席管理:
https://dev2.kefucloud.net/#
客服對話工作臺:
https://agent2.kefucloud.net/
android 問題 解決方案:官方:
https://support.rongcloud.cn/ks/NjIz
集成:
首先下載SDK分爲兩種IMKit和IMLib
IMKit包含融雲的UI頁面,IMLib只有相應的庫資源,需自己定製UI頁面。
我這裏直接使用了融雲的UI頁面
一、將IMKit以module的形式依賴到項目中
因爲IMKit中依賴了IMLib所以,將兩個module都導入到項目中
2、在app下的buile.gradle中添加依賴與配置
1)dependencies 裏面加入IMKit的依賴
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
api project(path: ':IMKit')
}
2)在lib文件夾下添加依賴的jar包與so文件
這裏爲了簡便,直接copy官方demo的lib
同時由於IMKit整體代碼數量較多,需要在
android {
…
}
中加入一些配置,用於指定libs路徑與防止65536的情況,:
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs = ['libs']
}
}
dexOptions {
incremental true
javaMaxHeapSize "4g"
}
這時同步一下環境就集成好了。
3、在IMLib的AndroidManifest.xml文件中填入自己再融雲官網申請的APPKEY
因爲融雲的頁面都是通過intent,Uri來進行調整的。
所以我們需要在AndroidManifest中指明對應的 intent-filter
這裏以直接打開客服的對話頁面爲例:
在Manifest中配置如下:
host裏的值爲自己應用的包名
pathPrefix裏面的 “/conversation/”是會話頁面的標記
在這個Activity對應的xml佈局文件中,通過Fragment導入融雲的客服頁面。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="@+id/conversation"
android:name="io.rong.imkit.fragment.ConversationFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
接下來要正式進行打開融雲客服頁面的操作了:
一、融雲SDK初始化
在應用Application的onCreate方法中執行
RongIM.init(this);
完成SDK的初始化
二、放一個按鈕,用於點擊操作打開客服對話頁面
點擊按鈕:
在點擊事件裏面,通過下面的方法打開融雲的會話頁面。:
在頁面跳轉前,需要確保融雲服務已經連接,
通過文檔,我們知道每個用戶對應一個融雲的roken,那個怎麼獲取這個token呢?
由於這個項目沒有後臺人員對接融雲客服,所以只能自己來獲取token了。
直接上代碼了:
獲取融雲token:
/**
* 獲取融雲的 token
* @param userId 用戶ID
* @return 包含融雲token的json字符串
*/
public static String getRongCloudToken(String userId, String nickName) {
StringBuffer res = new StringBuffer();
String url = HttpInterface.GET_RONG_TOKEN;
String App_Key = Constant.RongCloud.APP_KEY; //開發者平臺分配的 App Key。
String App_Secret = Constant.RongCloud.APP_SECRET;
String Timestamp = String.valueOf(System.currentTimeMillis() / 1000);//時間戳,從 1970 年 1 月 1 日 0 點 0 分 0 秒開始到現在的秒數。
String Nonce = String.valueOf(Math.floor(Math.random() * 1000000));//隨機數,無長度限制。
String Signature = sha1(App_Secret + Nonce + Timestamp);//數據簽名。
Log.i(TAG, "獲取到的融雲數據簽名:" + Signature);
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("App-Key", App_Key);
httpPost.setHeader("Timestamp", Timestamp);
httpPost.setHeader("Nonce", Nonce);
httpPost.setHeader("Signature", Signature);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>(1);
nameValuePair.add(new BasicNameValuePair("userId", userId));
HttpResponse httpResponse = null;
try {
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair, "utf-8"));
httpResponse = httpClient.execute(httpPost);
BufferedReader br = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
String line = null;
while ((line = br.readLine()) != null) {
res.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
Log.i(TAG, "獲取到融雲token:" + res.toString());
return res.toString();
}
//SHA1加密//http://www.rongcloud.cn/docs/server.html#通用_API_接口簽名規則
private static String sha1(String data) {
StringBuffer buf = new StringBuffer();
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(data.getBytes());
byte[] bits = md.digest();
for (int i = 0; i < bits.length; i++) {
int a = bits[i];
if (a < 0)
a += 256;
if (a < 16)
buf.append("0");
buf.append(Integer.toHexString(a));
}
} catch (Exception e) {
}
return buf.toString();
}
這時候獲取到的融雲token是已json形式返回的,所以我們要對json字符串進行解析:
這裏使用的是Gson解析
if (!TextUtils.isEmpty(rongJson)) {
RongCloudJsonData rongCloudJsonData = GsonUtils.parseJSON(rongJson, RongCloudJsonData.class);
if (null != rongCloudJsonData) {
String rongToken = rongCloudJsonData.getToken();
mInstance.setStringValue("rongToken", rongToken);
connectRongCloud(rongToken);
}
}
上面這段代碼要進行融雲連接融雲服務的操作,所以要放到子線程中操作。
連接融雲客服:
/**
* 連接融雲客服
* @param rongToken 融雲的token
*/
private void connectRongCloud(String rongToken) {
RongIM.connect(rongToken, new RongIMClient.ConnectCallback() {
@Override
public void onTokenIncorrect() {
Log.i(TAG, "token錯誤");
}
@Override
public void onSuccess(String s) {
Log.i(TAG, "融雲連接成功");
}
@Override
public void onError(RongIMClient.ErrorCode errorCode) {
Log.i(TAG, "融雲連接錯誤");
}
});
}
打開融合客服對話頁面:
RongIM.getInstance().startConversation(getContext(), Conversation.ConversationType.CUSTOMER_SERVICE, "service", "在線客服");
就可以打開我們在Manifest中配置的那個Activity了。
其中:“service”是客服後臺裏面,坐席管理–技能組ID裏的值。如下圖
這時候運行你的項目,如果在logcat中看到了三個進程,那說明集成沒有問題,可以繼續了。
打開APP,點擊按鈕,跳轉到客服頁面。
這時候就可以愉快的和客服聊天了。
=================================================================
是不是覺得這就結束了,並沒有。。。。
下面說說遇到的問題:
1、這樣集成以後,當你發送消息的時候,客服後臺是看不到你的暱稱的
通過文檔得知,融雲是通過Provider來獲取和保存用戶的信息的,這些信息都被保存到數據庫中了,因此我們需要通過Provider把我們的用戶信息,存到數據庫中,讓融雲可以獲取到。
解決:
參照文檔:
通過先通過RongIM.setUserInfoProvider()設置用戶信息,
然後在做頁面的跳轉,操作。如下:
RongIM.setUserInfoProvider(this, true);
RongIM.getInstance().setCurrentUserInfo(new io.rong.imlib.model.UserInfo(userId, nickName, Uri.parse(Constant.USER_ICON)));
/**
* <p>啓動會話界面。</p>
* <p>使用時,可以傳入多種會話類型 {@link io.rong.imlib.model.Conversation.ConversationType} 對應不同的會話類型,開啓不同的會話界面。
* 如果傳入的是 {@link io.rong.imlib.model.Conversation.ConversationType#CHATROOM},sdk 會默認調用
* {@link RongIMClient#joinChatRoom(String, int, RongIMClient.OperationCallback)} 加入聊天室。
* 如果你的邏輯是,只允許加入已存在的聊天室,請使用接口 {@link #startChatRoomChat(Context, String, boolean)} 並且第三個參數爲 true</p>
* @param context 應用上下文。
* @param conversationType 會話類型。
* @param targetId 根據不同的 conversationType,可能是用戶 Id、羣組 Id 或聊天室 Id。
* @param title 聊天的標題,開發者可以在聊天界面通過 intent.getData().getQueryParameter("title") 獲取該值, 再手動設置爲標題。
*/
RongIM.getInstance().startConversation(getContext(), Conversation.ConversationType.CUSTOMER_SERVICE, "service", "在線客服");
然而這樣還是沒有用。看文檔發現,
在application的onCreate方法中的初始化代碼後面還要加一行代碼
設置發送消息攜帶用戶信息。
@Override
public void onCreate() {
super.onCreate();
RongIM.init(this);
/**
* 設置消息體內是否攜帶用戶信息。
* @param state 是否攜帶用戶信息,true 攜帶,false 不攜帶。
*/
RongIM.getInstance().setMessageAttachedUserInfo(true);
}
這樣在發送消息的時候,客服後臺就接收到了傳過來的用戶名了。
問題二:
進入客服對話頁面的時候,會有一個提示:
點擊“留言”按鈕,進入留言頁面
一個web頁面,發現居然是一片空白。。。
不明白是怎麼回事,於是諮詢融雲的客服
讓我在進入客服頁面的時候斷點獲取到:
“url”:“https://web.jiaxincloud.com/gray/jiaxin-phone.html?id=z3b4zmtvnhd0mq&appName=dpdyy091&appChannel=10001”
webView加載的url地址也獲取到了,是正常的。可是webView卻沒有展示出來
最後是讓我自定義一個WebView來解決這個問題的
因爲這個頁面也是URI來實現的,所以我們自定義一個activity,在manifest中指定activity的
intent-filter
在IMKit的manifest中
這個就是容易的留言頁面,我們把intent-filter註釋掉,copy到我們自己的activity下。
<activity
android:name="io.rong.imkit.tools.RongWebviewActivity"
android:exported="false"
android:screenOrientation="portrait">
<!--<intent-filter>-->
<!--<action android:name="io.rong.imkit.intent.action.webview" />-->
<!--<category android:name="android.intent.category.DEFAULT" />-->
<!--</intent-filter>-->
</activity>
自定義留言頁面中WebView的代碼如下:
private void initWebView() {
mWebView = findViewById(R.id.webView);
WebSettings webSettings = mWebView.getSettings();
webSettings.setDomStorageEnabled(true);//主要是這句
webSettings.setJavaScriptEnabled(true);//啓用js
webSettings.setBlockNetworkImage(false);//解決圖片不顯示
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setLoadsImagesAutomatically(true);
// webSettings.setAppCacheEnabled(true);
// webSettings.setDomStorageEnabled(true);
// webSettings.supportMultipleWindows();
// webSettings.setAllowContentAccess(true);
// webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
// webSettings.setUseWideViewPort(true);
// webSettings.setLoadWithOverviewMode(true);
// webSettings.setSavePassword(true);
// webSettings.setSaveFormData(true);
mWebView.setWebChromeClient(new WebChromeClient());//這行最好不要丟掉
//該方法解決的問題是打開瀏覽器不調用系統瀏覽器,直接用webview打開
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
mWebView.loadUrl(webUrl);
}
這樣就可以正常顯示留言的頁面了
接着把玩這個客服模塊
發送語音、圖片都沒問題。
然後拍照的時候,應用奔潰了
看到在Manifest.xml的最後有一段代碼
把他放到我們應用的Manifest中就解決問題了。
<!-- 此部分代碼需要移植到您的 app 下的 manifest,並且 authorities 指定您的包名。例如:com.android.FileProvider -->
<!-- 否則使用拍照功能時,會崩潰 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.zxf.pawnfund.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/rc_file_path" />
</provider>
後面還遇到了,發送表情圖片沒問題,但是接受客服發送過來的表情卻顯示符號的問題
諮詢客服後,說是web上的表情和手機上的表情是不一樣的,他們沒有做適配,如果要正常顯示,需要自己去自定義適配。。
這裏不再贅述。。。