1.获取Token
功能描述
生成用户在融云的唯一身份标识 Token,客户端在使用融云通讯能力前必须获取 Token,融云 SDK 每次连接服务器时,都需要向融云服务器提供 Token,以便验证身份。
每个用户在进入MainActivity时,都需要想融云请求Token,并连接上融云。
输入参数,我们使用Bmob注册的userId和userName, 因为返回的userId与输入的用户ld相同,这样我们在进行聊天的时候,可以直接传入对方在Bmob的用户Id,即可建立双方的连接
除了上面的输入参数外,向融云请求Token,还需要提供4个Http Request Header
数据签名的获取
我们可以通过 App-Key、Nonce、TimeStamp来进行获取,具体代码如下
*/
public class SHA1 {
/**
* 融云加密算法
* @param data
* @return
*/
public 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){
e.printStackTrace();
}
return buf.toString();
}
}
封装请求Token类
接下来就可以向融云发送Http请求,获取Token,代码如下
public class HttpManager {
//初始化 OkHttp
private static OkHttpClient mOkHttpClient;
//发送post请求的url
private static String POST_URL = "http://api-cn.ronghub.com/user/getToken.json";
//融云的App_key
private static String APP_KEY = "c9kqb3rdc200j";
//单例模式
private static HttpManager instance = null;
public HttpManager() {
mOkHttpClient = new OkHttpClient();
}
public static HttpManager getInstance(){
if(instance ==null){
instance = new HttpManager();
}
return instance;
}
//发送post请求 获取融云Token
public String postCloudToken(HashMap<String,String> hashMap){
//随机数
String nonce = String.valueOf(Math.floor(Math.random()*10000));
//时间戳
String timestamp = String.valueOf(System.currentTimeMillis()/1000);
//数据签名
String signature = SHA1.sha1("w4hvJUN1yUuA"+nonce+timestamp);
//初始化要提交的表单
FormBody.Builder builder = new FormBody.Builder();
//循环叫hashmap用的键值对添加到要提交的表单中
for(String key:hashMap.keySet()){
builder.add(key,hashMap.get(key));
}
RequestBody requestBody = builder.build();
//发送post请求
Request build = new Request.Builder()
.url(POST_URL)
.post(requestBody)
.addHeader("App-Key", APP_KEY)
.addHeader("Nonce", nonce)
.addHeader("Timestamp", timestamp)
.addHeader("Signature", signature)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
try {
return mOkHttpClient.newCall(build).execute().body().string();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
请求Token代码中的 HashMap保存的是用户Id、用户姓名、及用户头像,也就是请求Token需要传入的当前用户参数.
检查Token
获取Token之后,我们可以将Token保存在SharedPreferences里面去,每次在进入MainActivity的时候,先去检查SharedPreferences里面是否有Token,有Token就直接进行连接融云,没有就去请求融云获取Token,具体代码如下
public class SpUtils {
public static SharedPreferences preferences;
public static SharedPreferences getInstance(Context context){
if(preferences==null){
preferences = context.getSharedPreferences("app",Context.MODE_PRIVATE);
}
return preferences;
};
}
//检查TOKEN
private void checkToken() {
//获取TOKEN 需要三个参数 1.用户ID 2.头像地址 3.昵称
String token = SpUtils.getInstance(this).getString(Constant.TOKEN,"");
if(!TextUtils.isEmpty(token)){
//如果有token 就启动云服务去连接融云服务
startCloudServer();
}else {
//1.有三个参数
String tokenPhoto = BmobManager.getInstance().getUser().getTokenPhoto();
String tokenNickName = BmobManager.getInstance().getUser().getTokenNickName();
if(!TextUtils.isEmpty(tokenPhoto) || !TextUtils.isEmpty(tokenNickName)){
//创建Token
creareToken();
}else{
//创建上传提示框
createUploadDialog();
}
}
}
BmobManager.getInstance().getUser()这个方法是获取当前的用户,我把关于Bmob的所有方法都写在BmobManager里面进行封装,前面的登录实现,已经对BmobManager进去了说明
请求Token
也就是creareToken()方法, 具体代码如下
private void creareToken() {
//创建获取token的数据 用户名 和name
final HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("userId",BmobManager.getInstance().getUser().getObjectId());
hashMap.put("name",BmobManager.getInstance().getUser().getNickName());
//通过Okhttp请求Token
disposable = Observable.create(new ObservableOnSubscribe<Object>() {
@Override
public void subscribe(ObservableEmitter<Object> observableEmitter) throws Exception {
//执行请求过程
String json = HttpManager.getInstance().postCloudToken(hashMap);
observableEmitter.onNext(json);
observableEmitter.onComplete();
}
//线程调度
}).subscribeOn(Schedulers.newThread())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object s) throws Exception {
//通过gson获取融云Token
getCloudToken((String)s);
}
});
}
将Token保存到内部存储中
也就是 getCloudToken((String)s)方法,具体代码如下
public class tokenben {
//"code":200,
// "userId":"b3aaba9b03",
// "token":"KPvSFGpeOPfXE0IFW6Ti6nm4WWPy2yyjXqGumVmbBI8=@yoha.cn.rongnav.com;yoha.cn.rongcfg.com"
private int code;
private String userId;
private String token;
}
private void getCloudToken(String s) {
Gson gson = new Gson();
tokenben tokenben = gson.fromJson(s, new tokenben().getClass());
// System.out.println("==============================="+tokenben);
//将token存储到内部存储中
SpUtils.getInstance(this).edit().putString(Constant.TOKEN,tokenben.getToken()).commit();
//连接融云服务
startCloudServer();
}
连接融云
也就是startCloudServer()方法,具体代码如下
private void startCloudServer(){
//如果有token 就启动云服务去连接融云服务
startService(new Intent(this, CloudService.class));
}
这里我们使用Service去连接融云服务,因为通过startService()启动了服务,则服务是Started状态。一旦启动,服务可以在后台无限期运行,即使启动它的组件已经被销毁。 使用我们需要时刻去监听其它用户,发送过来的信息,所有需要使用Service。
CloudService介绍
在CloudService我们去连接融云,会去接收对方发送过来的聊天消息、音视频、添加好友消息、同意好友消息等等。因为Service在后台可以无限期运行,可以时时刻刻去监听.
在写CloudService代码之前,先来介绍一下CloudManager这个类,我把关于融云操作所有的方法封装在这个类中,方便我们进行管理
CloudManager代码如下
package com.example.meet.manager;
import android.content.Context;
import android.net.Uri;
import android.widget.Toast;
import com.example.meet.R;
import com.example.meet.bmob.BmobManager;
import com.example.meet.utils.LogUtils;
import org.json.JSONObject;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import io.rong.calllib.IRongCallListener;
import io.rong.calllib.IRongReceivedCallListener;
import io.rong.calllib.RongCallClient;
import io.rong.calllib.RongCallCommon;
import io.rong.imlib.IRongCallback;
import io.rong.imlib.RongIMClient;
import io.rong.imlib.model.Conversation;
import io.rong.imlib.model.Message;
import io.rong.message.ImageMessage;
import io.rong.message.LocationMessage;
import io.rong.message.TextMessage;
public class CloudManager {
private static CloudManager instance = null;
//发送post请求的url
private static String POST_URL = "http://api-cn.ronghub.com/user/getToken.json";
//融云的App_key
private static String APP_KEY = "c9kqb3rdc200j";
//融云的App_sercet
private static String APP_SECRET = "w4hvJUN1yUuA";
//ObjectName
public static final String MSG_TEXT_NAME = "RC:TxtMsg";
public static final String MSG_IMAGE_NAME = "RC:ImgMsg";
public static final String MSG_LOCATION_NAME = "RC:LBSMsg";
//普通信息
public static final String TEXT_MESSAGE = "TEXT_MESSAGE";
//添加好友的信息
public static final String SEND_ADD_FRIEND = "SEND_ADD_FRIEND";
//同意好友的信息
public static final String SEND_AGREEN_FRIEND = "SEND_AGREEN_FRIEND";
//来电铃声
public static final String callAudioPath = "http://downsc.chinaz.net/Files/DownLoad/sound1/201501/5363.wav";
//挂断铃声
public static final String callAudioHangup = "http://downsc.chinaz.net/Files/DownLoad/sound1/201501/5351.wav";
public CloudManager() {
}
public static CloudManager getInstance(){
if(instance == null){
instance = new CloudManager();
}
return instance;
}
//初始化融云
public void initCloud(Context context){
String app_key = "c9kqb3rdc200j";
RongIMClient.init(context,app_key);
}
//连接融云
public void connectCloud(String token){
RongIMClient.connect(token, new RongIMClient.ConnectCallback() {
//token错误
@Override
public void onTokenIncorrect() {
LogUtils.i("token错误");
}
//连接成功 userId 当前用户 ID
@Override
public void onSuccess(String userId) {
LogUtils.i("userId"+userId);
LogUtils.i("融云连接成功");
//发送消息测试
// CloudManager.getInstance().sendTextMessage("很高兴认识你","5c97e446e5");
}
//连接失败
@Override
public void onError(RongIMClient.ErrorCode errorCode) {
LogUtils.i("errorCode"+errorCode);
}
});
}
// 在断开和融云的连接后,有新消息时,仍然能够收到推送通知,调用 disconnect() 方法。
public void disconnect(){
RongIMClient.getInstance().disconnect();
}
//断开连接后,不想收到任何推送通知,调用 logout() 方法。
public void logout(){
RongIMClient.getInstance().logout();
}
//接收消息的监听器
public void setOnReceiveMessageListener(RongIMClient.OnReceiveMessageListener listener){
RongIMClient.setOnReceiveMessageListener( listener);
}
private IRongCallback.ISendMessageCallback iSendMessageCallback = new IRongCallback.ISendMessageCallback() {
@Override
public void onAttached(Message message) {
/**
* 消息发送前回调, 回调时消息已存储数据库
* @param message 已存库的消息体
*/
}
@Override
public void onSuccess(Message message) {
/**
* 消息发送成功。
* @param message 发送成功后的消息体
*/
LogUtils.i("发送消息成功+Success");
}
@Override
public void onError(Message message, RongIMClient.ErrorCode errorCode) {
/**
* 消息发送失败
* @param message 发送失败的消息体
* @param errorCode 具体的错误
*/
LogUtils.i("发送消息失败+Error"+errorCode);
}
};
//发生文本消息
public void sendTextMessage(String msg,String targetId){
//构建文本消息实例
TextMessage textMessage = TextMessage.obtain(msg);
Message message = Message.obtain(targetId, Conversation.ConversationType.PRIVATE,textMessage);
RongIMClient.getInstance().sendMessage(message,null,null,iSendMessageCallback);
}
//发送文本消息,但是发送的是一个Json
public void sendTextMessage(String msg,String type,String targetId){
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("msg",msg);
jsonObject.put("type",type);
jsonObject.put("targetId",targetId);
jsonObject.put("sendId", BmobManager.getInstance().getUser().getObjectId());
//开始发送信息
// LogUtils.i("发送者的id为"+targetId);
sendTextMessage(jsonObject.toString(),targetId);
}catch (Exception e){
e.printStackTrace();
}
}
//查询本地的会话记录
public void getConversationList(RongIMClient.ResultCallback<List<Conversation>> callback){
RongIMClient.getInstance().getConversationList(callback);
}
//获取本地的历史消息记录
public void getHistoryMessages(String targetId, RongIMClient.ResultCallback<List<Message>> callback){
RongIMClient.getInstance().getHistoryMessages(Conversation.ConversationType.PRIVATE,targetId,-1,1000,callback);
}
//获取服务器的历史消息记录 相当于换了一台手机跟别人聊天
public void getRemoteHistoryMessages(String targetId, RongIMClient.ResultCallback<List<Message>> callback){
RongIMClient.getInstance().getRemoteHistoryMessages(Conversation.ConversationType.PRIVATE,targetId,0,1000,callback);
}
//发送图片消息
public void sendImageMessage(File file,String targetId, RongIMClient.SendImageMessageCallback callback){
ImageMessage imageMessage = ImageMessage.obtain(Uri.fromFile(file), Uri.fromFile(file), true);
RongIMClient.getInstance().sendImageMessage(Conversation.ConversationType.PRIVATE,targetId,imageMessage,
null,null,callback);
}
//发送位置信息
public void sendLocationMessage(double lat,double lng,String poi,String targetId, IRongCallback.ISendMessageCallback callback){
LocationMessage locationMessage = LocationMessage.obtain(lat, lng, poi, null);
Message message = Message.obtain(targetId, Conversation.ConversationType.PRIVATE, locationMessage);
RongIMClient.getInstance().sendLocationMessage(message,null,null,callback);
}
//---------------------------Call API------------------------------------
/**
* 拨打视频/音频
*
* @param targetId
* @param type
*/
public void startCall(Context mContext, String targetId, RongCallCommon.CallMediaType type) {
//检查设备可用
if (!isVoIPEnabled(mContext)) {
return;
}
// if(!isConnect()){
// Toast.makeText(mContext, mContext.getString(R.string.text_server_status), Toast.LENGTH_SHORT).show();
// return;
// }
List<String> userIds = new ArrayList<>();
userIds.add(targetId);
RongCallClient.getInstance().startCall(
Conversation.ConversationType.PRIVATE,
targetId,
userIds,
null,
type,
null);
}
/**
* 音频
*
* @param targetId
*/
public void startAudioCall(Context mContext, String targetId) {
startCall(mContext, targetId, RongCallCommon.CallMediaType.AUDIO);
}
/**
* 视频
*
* @param targetId
*/
public void startVideoCall(Context mContext, String targetId) {
startCall(mContext, targetId, RongCallCommon.CallMediaType.VIDEO);
}
/**
* 监听音频通话
*
* @param listener
*/
public void setReceivedCallListener(IRongReceivedCallListener listener) {
if (null == listener) {
return;
}
RongCallClient.setReceivedCallListener(listener);
}
/**
* 接听
*
* @param callId
*/
public void acceptCall(String callId) {
LogUtils.i("acceptCall:" + callId);
RongCallClient.getInstance().acceptCall(callId);
}
/**
* 挂断
*
* @param callId
*/
public void hangUpCall(String callId) {
LogUtils.i("hangUpCall:" + callId);
RongCallClient.getInstance().hangUpCall(callId);
}
/**
* 切换媒体 视频转音频,音频转视频
*
* @param mediaType
*/
public void changeCallMediaType(RongCallCommon.CallMediaType mediaType) {
RongCallClient.getInstance().changeCallMediaType(mediaType);
}
/**
* 切换摄像头
*/
public void switchCamera() {
RongCallClient.getInstance().switchCamera();
}
/**
* 摄像头开关 是否关闭摄像头
*
* @param enabled
*/
public void setEnableLocalVideo(boolean enabled) {
RongCallClient.getInstance().setEnableLocalVideo(enabled);
}
/**
* 音频开关 是否打开麦克风
*
* @param enabled
*/
public void setEnableLocalAudio(boolean enabled) {
RongCallClient.getInstance().setEnableLocalAudio(enabled);
}
/**
* 免提开关
*
* @param enabled
*/
public void setEnableSpeakerphone(boolean enabled) {
RongCallClient.getInstance().setEnableSpeakerphone(enabled);
}
/**
* 开启录音
*
* @param filePath
*/
public void startAudioRecording(String filePath) {
RongCallClient.getInstance().startAudioRecording(filePath);
}
/**
* 关闭录音
*/
public void stopAudioRecording() {
RongCallClient.getInstance().stopAudioRecording();
}
/**
* 监听通话状态
*
* @param listener
*/
public void setVoIPCallListener(IRongCallListener listener) {
if (listener == null) {
return;
}
RongCallClient.getInstance().setVoIPCallListener(listener);
}
/**
* 检查设备是否可用通话
*
* @param mContext
*/
public boolean isVoIPEnabled(Context mContext) {
if (!RongCallClient.getInstance().isVoIPEnabled(mContext)) {
Toast.makeText(mContext, mContext.getString(R.string.text_devices_not_supper_audio), Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
}
CloudManager这里的方法后面我们会一一介绍,先来看下CloudService里面的代码
public class CloudService extends Service implements View.OnClickListener {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
initService();
initWindow();
//连接融云服务
linkCloudServer();
}
private void linkCloudServer() {
//获取Token
String token = SpUtils.getInstance(this).getString(Constant.TOKEN,"");
LogUtils.i("token"+token);
//连接融云服务
CloudManager.getInstance().connectCloud(token);
}
}
到此为此连接融云已经完成了,接下来就可以进行我们发送添加好友消息了,但是别忘记,我们需要自定义一个Application来初始化融云,初始化融云需要获取你在融云创建的应用的App_key,具体代码如下
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//Bmob的初始化
BmobManager.getInstance().initBmob(this);
//初始化融云
CloudManager.getInstance().initCloud(this);
//初始化LitePal
LitePal.initialize(this);
//初始化窗口
WindowHelper.getInstance().initWindow(this);
//初始化ZXing
ZXingLibrary.initDisplayOpinion(this);
}
}
CloudManager里面的initCloud方法
//初始化融云
public void initCloud(Context context){
String app_key = "你的应用App_key";
RongIMClient.init(context,app_key);
}
需要注意的是 CloudService和MyApplication 需要在清单文件中注册,别忘记了哦!!!