深受您的 Android 应用也能够聊(第二版本)

By admin in 亚洲必赢app在哪下载 on 2018年9月16日

简介

起去年 LeanCloud
发布实时通信(IM)服务后,基于用户反映和工程师对需的化以及指向事情的提炼,上周专业揭晓了「实时通信
2.0
」。设计意见还是是「灵活、解耦、可做、可定制」,具体可参考《实时通信支出指南》,了解
LeanCloud 实时通信的基本概念和模型。

下载和安

可以到 LeanCloud
官方下载点下载
LeanCloud IM SDK v2 版。将下充斥到之 jar 包加入工程即可。

相当底文本聊天

咱俩先行由最简便的环入手,看看怎么用 LeanCloud IM SDK v2
贯彻一对一文本闲聊。

初始化

跟 LeanCloud 其他服务同,实时聊天服务的初始化也是当 Application 的
onCreate 方法被进行的:

public class MyApplication extends Application{

    public void onCreate(){
      ...
      AVOSCloud.initialize(this,"{{appId}}","{{appKey}}");
      ...
    }
}

再者于AndroidManifest.xml中间声明:

<manifest>
   ...

   <application
        android:name=".MyApplication"
        ....>
        ...

        <service android:name="com.avos.avoscloud.PushService" />

        <receiver android:name="com.avos.avoscloud.AVBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>
        ...
   </application>

</manifest>

连着下我们得完成用户登录。

登录

万一聊天发起方名叫 Tom,为直观起见,我们采用用户名来作为 clientId
登录聊天系统(LeanCloud 云端只要求 clientId
在行使内唯一即可,具体用什么数据由应用层决定),代码如下:

AVIMClient imClient = AVIMClient.getInstance("Tom");
imClient.open(new IMClientCallback(){
  @Override
  public void done(AVIMClient client, AVException e) {
    if (null != e) {
      // 出错了,可能是网络问题无法连接 LeanCloud 云端,请检查网络之后重试。
      // 此时聊天服务不可用。
      e.printStackTrace();
    } else {
      // 成功登录,可以开始进行聊天了(假设为 MainActivity)。
      Intent intent = new Intent(currentActivity, MainActivity.class);
      currentActivity.startActivity(intent);
    };
  }
});

成立对话

一经我们设和「Bob」这个用户展开聊天,我们事先创造一个会话,代码如下:

List<String> clientIds = new ArrayList<String>();
clientIds.add("Tom");
clientIds.add("Bob");

// 我们给对话增加一个自定义属性 type,表示单聊还是群聊
// 常量定义:
// int ConversationType_OneOne = 0; // 两个人之间的单聊
// int ConversationType_Group = 1;  // 多人之间的群聊
Map<String, Object> attr = new HashMap<String, Object>();
attr.put("type", ConversationType_OneOne);

imClient.createConversation(clientIds, attr, new AVIMConversationCreatedCallback() {
  @Override
  public void done(AVIMConversation conversation, AVException e) {
    if (null != conversation) {
      // 成功了,这时候可以显示对话的 Activity 页面(假定为 ChatActivity)了。
      Intent intent = new Intent(this, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      startActivity(intent);
    }
  }
});

树的「对话」在控制台怎么查

假如您所显现,我们创建一个会话之上,指定了成员(Tom 和
Bob)和一个附加的属性({type: 0})。这些多少保存及云端后,你于
控制台 -> 存储 -> 数据 里面会相,_Conversation
表中多了平漫漫记下,新记录之 m 属性值为["Tom", "Bob"]attr
属性值为{"type":0}。如您所预期,m 属性就是对准诺在成员列表,attr
属性就是用户多的前额外属性值(以目标的花样储存)。

发送信息

起好对话后,要发送信息是非常粗略的:

AVIMMessage message = new AVIMMessage();
message.setContent("hello");
conversation.sendMessage(message, new AVIMConversationCallback() {
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      Logger.d("发送成功,msgId=" + message.getMessageId());
    }
  }
});

吓了,这样平等长条信息就是发送过去了。但是问题来了,对于「Bob」而言,他怎么才会接纳别人发给他的信呢?

信接收

于 Bob 这同端,要力所能及接到至消息,需要如下几步:

1,进行初始化;

2,实现和谐的 AVIMMessageHandler,响应新消息到达通知,主要是之类函数:

public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client);

于 Tom 发过来的信息,要展示出来,我们特需要兑现 onMessage
即可,示例代码如下:

class CustomMessageHandler extends AVIMMessageHandler {
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 新消息到来了。在这里增加你自己的处理代码。
    String msgContent = message.getContent();
    Logger.d(conversation.getConversationid() + " 收到一条新消息:" + msgContent);
  }
}

3,进行登录,代码也跟发送端一样。

完整代码如下:

// 自定义消息响应类
class CustomMessageHandler extends AVIMMessageHandler {
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 新消息到来了。在这里增加你自己的处理代码。
    String msgContent = message.getContent();
    Logger.d(conversation.getConversationid() + " 收到一条新消息:" + msgContent);
  }
}

// application 的初始化部分
public void onCreate(){
  ...
  AVOSCloud.initialize(this,"{{appId}}","{{appKey}}");
  AVIMMessageManager.registerDefaultMessageHandler(new CustomMessageHandler());
  ...
}

// 用户登录部分
AVIMClient imClient = AVIMClient.getInstance("Bob");
imClient.open(new IMClientCallback(){
  @Override
  public void done(AVIMClient client, AVException e) {
    if (null != e) {
      // 出错了,可能是网络问题无法连接 LeanCloud 云端,请检查网络之后重试。
      // 此时聊天服务不可用。
      e.printStackTrace();
    } else {
      // 成功登录,可以开始进行聊天了。
    };
  }
});

注意!
AVIMMessageManager.registerDefaultMessageHandler() 一定要于
AVIMClient.open() 之前调用,否则恐怕造成服务器发回去的有信息丢失。

差一点只根本的回调接口

由地方的例证中可以看,要收取至他人为你发送的消息,需要重载
AVIMMessageHandler 类。从 v2 版开始,LeanCloud IM SDK
大量施用回调来举报操作结果,但是对于有些消极之音讯通知,则要采用接口来落实的,包括:

  • 眼下网出现变化
  • 对话中起新的音信
  • 对话中来新成员在
  • 对话中出成员离开
  • 被请加入某对话
  • 让蹬来对话

LeanCloud IM SDK 内部采用了三栽接口来响应这些事件。

网事件响应接口

主要用以处理网络转移事件,接口定义在
AVIMClientEventHandler,主要函数为:

  /**
   * 实现本方法以处理网络断开事件
   */
  public abstract void onConnectionPaused(AVIMClient client);

  /**
   * 实现本方法以处理网络恢复事件
   */
  public abstract void onConnectionResume(AVIMClient client);

当网络中断的状况下,所有的音收发和对话操作都见面出现问题。

通过 AVIMClient.setClientEventHandler(AVIMClientEventHandler handler)
可以设定全局的 ClientEventHandler。

对话成员变动响应接口

重在用以处理对话中成员变动的波,接口定义在
AVIMConversationEventHandler,主要函数为:

  /**
   * 实现本方法以处理聊天对话中的参与者离开事件
   *
   * @param members 离开的参与者
   * @param kickedBy 踢人者,自愿退出的情况下踢人者就是参与者
   */
  public abstract void onMemberLeft(AVIMClient client,
      AVIMConversation conversation, List<String> members, String kickedBy);

  /**
   * 实现本方法以处理聊天对话中的参与者加入事件
   *
   * @param members 加入的参与者
   * @param invitedBy 邀请人,有可能是加入的参与者本身
   */
  public abstract void onMemberJoined(AVIMClient client,
      AVIMConversation conversation, List<String> members, String invitedBy);

  /**
   * 实现本方法来处理当前用户被踢出某个聊天对话事件
   *
   * @param kickedBy 踢出你的人
   */
  public abstract void onKicked(AVIMClient client, AVIMConversation conversation,
      String kickedBy);

  /**
   * 实现本方法来处理当前用户被邀请到某个聊天对话事件
   *
   * @param conversation 被邀请的聊天对话
   * @param operator 邀请你的人
   */
  public abstract void onInvited(AVIMClient client, AVIMConversation conversation,
      String operator);

通过
AVIMMessageManager.setConversationEventHandler(AVIMConversationEventHandler handler)
可以安装全局的 ConversationEventHandler。

信息应接口

第一用以处理新消息到达事件,接口定义在
MessageHandlerAVIMMessageHandler
是一个空的落实类似,我们应该通过重载 AVIMMessageHandler
的相关方来好信息处理。主要的主意来:

  // 收到新的消息
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation);

  // 自己发送的消息已经被对方接收
  @Override
  public void onMessageReceipt(AVIMMessage message, AVIMConversation conversation, AVIMClient client);

通过 AVIMMessageManager.registerDefaultMessageHandler(handler)
可以安装全局的 MessageHandler。

俺们落实这三像样接口,就可拍卖所有的关照消息了。示例代码如下:

class CustomNetworkHandler extends AVIMClientEventHandler {
  @Override
  public void onConnectionPaused(AVIMClient client) {
    // 请按自己需求改写
    Logger.d("connect paused");
  }

  @Override
  public void onConnectionResume(AVIMClient client) {
    // 请按自己需求改写
    Logger.d("connect resume");
  }
}

class CustomConversationHandler extends AVIMConversationEventHandler {
  public private Context gContext = null;
  private void toast(String str) {
    Toast.makeText(gContext, str, Toast.LENGTH_SHORT).show();
  }
  private void toast(Context context, String str) {
    Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
  }

  @Override
  public void onMemberLeft(AVIMClient client, AVIMConversation conversation, List<String> members, String kickedBy) {
    // 请按自己需求改写
    toast(MsgUtils.nameByUserIds(members) + " left, kicked by " + MsgUtils.nameByUserId(kickedBy));
    //注:MsgUtils 是一个辅助类,nameByUserIds 用来将 userId 转换成用户名
  }

  @Override
  public void onMemberJoined(AVIMClient client, AVIMConversation conversation, List<String> members, String invitedBy) {
    // 请按自己需求改写
    toast(MsgUtils.nameByUserIds(members) + " joined , invited by " + MsgUtils.nameByUserId(invitedBy));
    //注:MsgUtils 是一个辅助类,nameByUserIds 用来将 userId 转换成用户名
  }

  @Override
  public void onKicked(AVIMClient client, AVIMConversation conversation, String kickedBy) {
    // 请按自己需求改写
    toast("you are kicked by " + MsgUtils.nameByUserId(kickedBy));
  }

  @Override
  public void onInvited(AVIMClient client, AVIMConversation conversation, String operator) {
    // 请按自己需求改写
    toast("you are invited by " + MsgUtils.nameByUserId(operator));
  }
};

class CustomMsgHandler extends AVIMMessageHandler {
  @Override
  public void onMessage(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 请按自己需求改写
    String msgContent = message.getContent();
    Logger.d(conversation.getConversationid() + " 收到一条新消息:" + msgContent);
  }

  @Override
  public void onMessageReceipt(AVIMMessage message, AVIMConversation conversation, AVIMClient client) {
    // 请按自己需求改写
    Logger.d("发往对话 " + conversation.getConversationid() + " 的消息 "+ message.getMessageId() +" 已被接收");
  }
}

// 设置事件响应接口
AVIMClient.setClientEventHandler(new CustomNetworkHandler());
AVIMMessageManager.setConversationEventHandler(new CustomConversationHandler());
AVIMMessageManager.registerDefaultMessageHandler(new CustomMsgHandler());

支撑富媒体之闲话消息

上面的代码演示了怎么发送简单文本信息,但是现在之交互方式已经越来越多样化,图像、语音、视频已经是杀广阔的消息类型。v2
版的 LeanCloud IM SDK 已经可以十分好地支撑这些富媒体消息,具体说明如下:

基类:AVIMTypedMessage

富有富媒体消息的基类,其声明也

//SDK定义的消息类型,LeanCloud SDK 自身使用的类型是负数,所有正数留给开发者自定义扩展类型使用,0 作为「没有类型」被保留起来。
enum AVIMReservedMessageType {
  UnsupportedMessageType(0),
  TextMessageType(-1),
  ImageMessageType(-2),
  AudioMessageType(-3),
  VideoMessageType(-4),
  LocationMessageType(-5),
  FileMessageType(-6);
};

public abstract class AVIMTypedMessage extends AVIMMessage {
  public AVIMTypedMessage();

  public int getMessageType();

  @Override
  public final String getContent();

  @Override
  public final void setContent(String content);
}

文件消息(AVIMTextMessage)

AVIMTypedMessage 子类,表示一般的公文消息,其宣称也

public class AVIMTextMessage extends AVIMTypedMessage {
  public String getText();
  public void setText(String text);

  public Map<String, Object> getAttrs();
  public void setAttrs(Map<String, Object> attr);
}

足见到,对于文本消息,主要的特性有 textattr 两独,通过简单的
getter/setter 就可以拜到。要发送文书消息,示例代码为:

AVIMTextMessage message = new AVIMTextMessage();
message.setText("hello");
conversation.sendMessage(message, new AVIMConversationCallback() {
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      Logger.d("message sent.");
    }
  }
});

文件消息(AVIMFileMessage)

AVIMTypedMessage
子类,用来发送带附件的音讯,开发者可以就此它来发送「离线文件」。对于此类消息,LeanCloud
IM SDK 内部会先行把文件上传到 LeanCloud 文件存储服务器(自带 CDN
功能),然后将公文首先数据(url,文件大小等等)放在信息包内发送到
LeanCloud 实时通信服务端。其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMFileessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMFileMessage(File localFile) throws FileNotFoundException, IOException;
// 传入 AVFile 实例,构造消息对象
public AVIMFileMessage(AVFile file);

暨公事消息看似,文件消息啊支撑附带文本及其他自定义属性,可以通过如下方法上加
/ 获取更多信息:

  • String getText() / void setText(String text)
  • Map<String, Object> getAttrs() / void setAttrs(Map<String,
    Object> attr);

出殡文书消息之演示代码为:

String localZipfilePath;
try {
  AVIMFileMessage message = new AVIMFileMessage(localZipfilePath);
  message.setText("这是你要的文档");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

吸纳及这般消息之后,开发者可以通过以下方法,获取到文件首先数据(size
等)和一个带有二前进制数据的 AVFile 对象:

  • AVFile getAVFile() 方法会返回一个二进制文件之 AVFile
    实例,之后方可通过 AVFile 来成功多少下载或者其它操作,具体可以参见
    AVFile
    说明
  • String getFileUrl() 方法会返回二进制文件的 url
  • long getSize() 方法会返回二进制文件之莫过于尺寸(单位:byte)
  • Map<String, Object> getFileMetaData()
    可以收获二进制文件之别样元数据信息。

图像信息(AVIMImageMessage)

AVIMFileMessage
子类,专门用来发送图像及附带文本的搅和消息,其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMImageMessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMImageMessage(File localFile) throws FileNotFoundException, IOException;
// 传入 AVFile 实例,构造消息对象
public AVIMImageMessage(AVFile file);

出殡图像信息之演示代码为:

String localImagePath;
try {
  AVIMImageMessage message = new AVIMImageMessage(localImagePath);
  message.setText("你说我好看不?");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

收纳至这样消息随后,开发者可以经过如下方法,获取到多图像元数据(width,height,图像
size)和一个分包图像数据的 AVFile 对象:

  • int getWidth() 方法会返回图像的幅度(单位:pixel)
  • int getHeight() 方法会返回图像的可观(单位:pixel)
  • AVFile getAVFile() (继承自
    AVIMFileMessage)方法会返回一个图像文件的 AVFile 实例
  • String getFileUrl() (继承自 AVIMFileMessage)方法会返回图像文件的
    url
  • long getSize() (继承自
    AVIMFileMessage)方法会返回图像文件的实际上尺寸(单位:byte)
  • String getText() (继承自
    AVIMFileMessage)方法会返回随图像一起发送的公文信息。
  • Map<String, Object> getFileMetaData() (继承自
    AVIMFileMessage)可以获得图像的另外元数据信息。

板消息(AVIMAudioMessage)

AVIMFileMessage
子类,专门用来发送语音及附带文本的交集消息,其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMAudioMessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMAudioMessage(File localFile) throws FileNotFoundException, IOException;   
// 传入 AVFile 实例,构造消息对象
public AVIMAudioMessage(AVFile file);

出殡音频消息之演示代码为:

String localAudioPath;
try {
  AVIMAudioMessage message = new AVIMAudioMessage(localAudioPath);
  message.setText("听听我唱的小苹果:)");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

收下及这般消息之后,开发者可以透过如下方法,获取到多文章频元数据(时长
duration、音频 size)和一个暗含音频数据的 AVFile 对象:

  • double getDuration() 方法会返回音频的尺寸(单位:秒)
  • AVFile getAVFile() (继承自
    AVIMFileMessage)方法会返回一个音频文件的 AVFile 实例
  • String getFileUrl() (继承自 AVIMFileMessage)方法会返回音频文件的
    url
  • long getSize() (继承自
    AVIMFileMessage)方法会返回音频文件的实际尺寸(单位:byte)
  • String getText() (继承自
    AVIMFileMessage)方法会返回随音频一起发送的文书信息。
  • Map<String, Object> getFileMetaData() (继承自
    AVIMFileMessage)可以收获音频的其它元数据信息。

视频信息(AVIMVideoMessage)

AVIMFileMessage
子类,专门为此来发送视频以及附带文本的鱼龙混杂消息,其构造函数声明也:

// 传入本地文件路径,构造消息对象
public AVIMVideoMessage(String localPath) throws FileNotFoundException, IOException;
// 传入本地文件,构造消息对象
public AVIMVideoMessage(File localFile) throws FileNotFoundException, IOException;
// 传入 AVFile 文件,构造消息对象
public AVIMVideoMessage(AVFile file);

发送视频信息的示范代码为:

String localVideoPath;
try {
  AVIMVideoMessage message = new AVIMVideoMessage(localVideoPath);
  message.setText("敢不敢跟我比一比");
  conversation.sendMessage(message, new AVIMConversationCallback() {
    @Override
    public void done(AVException e) {
      if (null != e) {
        // 出错了。。。
        e.printStackTrace();
      } else {
        Logger.d("message sent");
      }
    }
  });
} catch (Exception ex) {
}

收下及这样消息之后,开发者可以得透过如下方法,获取到多少盼频元数据(时长
duration、视频 size)和一个含有视频数据的 AVFile 对象:

  • double getDuration() 方法会返回视频的长短(单位:秒)
  • AVFile getAVFile() (继承自
    AVIMFileMessage)方法会返回一个视频文件的 AVFile 实例
  • String getFileUrl() (继承自 AVIMFileMessage)方法会返回视频文件的
    url
  • long getSize() (继承自
    AVIMFileMessage)方法会返回视频文件的莫过于尺寸(单位:byte)
  • String getText() (继承自
    AVIMFileMessage)方法会返回随视频一起发送的文本信息。
  • Map<String, Object> getFileMetaData() (继承自
    AVIMFileMessage)可以抱视频的另元数据信息。

地理位置信息(AVIMLocationMessage)

AVIMTypedMessage
子类,支持发送地理位置信息及附带文本的杂消息,其声明也:

public class AVIMLocationMessage extends AVIMTypedMessage {
  public String getText();
  public void setText(String text);

  public Map<String, Object> getAttrs();
  public void setAttrs(Map<String, Object> attr);

  public AVGeoPoint getLocation();
  public void setLocation(AVGeoPoint location);
}

跟公事消息看似,地理位置信息才是搭了一个 AVGeoPoint 的 Location
属性。要发送位置信息之演示代码为:

AVIMLocationMessage message = new AVIMLocationMessage();
message.setText("快点过来!");
message.setLocation(new AVGeoPoint(15.9, 56.4));
conversation.sendMessage(message, new AVIMConversationCallback() {
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      Logger.d("message sent");
    }
  }
});

收纳至如此的消息随后,开发者可以得到现实的地理位置数据。

何以接纳富媒体消息

新版 LeanCloud IM SDK 内部封装了针对富媒体消息之支撑,所有富媒体消息还是于
AVIMTypedMessage 派生出的。发送的时光可以直接调用
conversation.sendMessage()
函数。在接收端,我们呢特意增加了扳平像样回调接口
AVIMTypedMessageHandler,其定义也:

public class AVIMTypedMessageHandler<T extends AVIMTypedMessage> extends MessageHandler<T> {

  @Override
  public void onMessage(T message, AVIMConversation conversation, AVIMClient client);

  @Override
  public void onMessageReceipt(T message, AVIMConversation conversation, AVIMClient client);
}

开发者可以编制好的信处理 handler,然后调用
AVIMMessageManager.registerMessageHandler(Class<? extends AVIMMessage> clazz, MessageHandler<?> handler)
函数来报目标 handler。

接收端对于富媒体消息之关照处理的示范代码如下:

class MsgHandler extends AVIMTypedMessageHandler<AVIMTypedMessage> {

  @Override
  public void onMessage(AVIMTypedMessage message, AVIMConversation conversation, AVIMClient client) {
    // 请按自己需求改写
    switch(message.getMessageType()) {
    case AVIMReservedMessageType.TextMessageType:
      AVIMTextMessage textMsg = (AVIMTextMessage)message;
      Logger.d("收到文本消息:" + textMsg.getText() + ", msgId:" + textMsg.getMessageId());
      break;
    case AVIMReservedMessageType.FileMessageType:
      AVIMFileMessage fileMsg = (AVIMFileMessage)message;
      Logger.id("收到文件消息。msgId=" + fileMsg.getMessageId() + ", url=" + fileMsg.getFileUrl() + ", size=" + fileMsg.getSize());
      break;
    case AVIMReservedMessageType.ImageMessageType:
      AVIMImageMessage imageMsg = (AVIMImageMessage)message;
      Logger.id("收到图片消息。msgId=" + imageMsg.getMessageId() + ", url=" + imageMsg.getFileUrl() + ", width=" + imageMsg.getWidth() + ", height=" + imageMsg.getHeight());
      break;
    case AVIMReservedMessageType.AudioMessageType:
      AVIMAudioMessage audioMsg = (AVIMAudioMessage)message;
      Logger.id("收到音频消息。msgId=" + audioMsg.getMessageId() + ", url=" + audioMsg.getFileUrl() + ", duration=" + audioMsg.getDuration());
      break;
    case AVIMReservedMessageType.VideoMessageType:
      AVIMVideoMessage videoMsg = (AVIMAudioMessage)message;
      Logger.id("收到视频消息。msgId=" + videoMsg.getMessageId() + ", url=" + videoMsg.getFileUrl() + ", duration=" + videoMsg.getDuration());
      break;
    case AVIMReservedMessageType.LocationMessageType:
      AVIMLocationMessage locMsg = (AVIMLocationMessage)message;
      Logger.id("收到位置消息。msgId=" + locMsg.getMessageId() + ", latitude=" + locMsg.getLocation().getLatitude() + ", longitude=" + locMsg.getLocation().getLongitude());
      break;
    }
  }

  @Override
  public void onMessageReceipt(AVIMTypedMessage message, AVIMConversation conversation, AVIMClient client) {
  }
}
MsgHandler msgHandler = new MsgHandler();
AVIMMessageManager.registerMessageHandler(AVIMTypedMessage.class, msgHandler);

LeanCloud IM SDK 内部消息分发的逻辑是这样的:对于收到的任一新消息,SDK
内部都见面先解析消息之花色,根据项目找到开发者也这无异于项目注册的拍卖
handler,然后逐一调用这些 handler 的 onMessage
函数。如果没找到专门处理及时无异于路消息的 handler,就会见传送给
defaultHandler 处理。

这样一来,在开发者也 TypedMessage(及其子类) 指定了专门的
handler,也指定了全局的 defaultHandler
了底早晚,如果发送端发送的凡通用的 AVIMMessage 消息,那么受端就是
AVIMMessageManager.registerDefaultMessageHandler()中指定的 handler
被调用;如果发送的凡 AVIMTypedMessage(及其子类)的音信,那么受端就是
AVIMMessageManager.registerMessageHandler()中指定的 handler 被调用。

怎扩大自己的富媒体消息

持续给
AVIMTypedMessage,开发者也可以扩大自己之富媒体消息。其要求及手续是:

  • 实现新的音类型,继承自 AVIMTypedMessage。这里要留意少触及:
    • 于 class 上增加一个 @AVIMMessageType(type=123) 的
      Annotation,具体信息类型的价(123)由开发者自己主宰(LeanCloud
      内建的信类型应用负数,所有正数都留给开发者扩展使用)。
    • 以消息中属性上而追加 @AVIMMessageField(name=””) 的
      Annotation,name
      也可选取字段在声明字段属性,同时起定义之字段要发生相应的
      getter/setter 方法。
  • 调用
    AVIMMessageManager.registerAVIMMessageType(Class<? extends AVIMTypedMessage> messageType)
    函数进行路注册
  • 调用
    AVIMMessageManager.registerMessageHandler(Class<? extends AVIMMessage> clazz, MessageHandler<?> handler)
    函数进行信息处理 handler 注册。

AVIMTextMessage 的源码如下,可供参考:

@AVIMMessageType(type = -1)
public class AVIMTextMessage extends AVIMTypedMessage {

  @AVIMMessageField(name = "_lctext")
  String text;
  @AVIMMessageField(name = "_lcattrs")
  Map<String, Object> attrs;

  public String getText() {
    return this.text;
  }

  public void setText(String text) {
    this.text = text;
  }

  public Map<String, Object> getAttrs() {
    return this.attrs;
  }

  public void setAttrs(Map<String, Object> attr) {
    this.attrs = attr;
  }
}

群组聊天

跟前方的单聊类似,群组聊天为需要先成立一个对话(AVIMConversation),然后发送、接收新的信息。

创造群组

跟单聊类似,建立一个大多人数拉的群组也是颇粗略的。例如:

Map<String, Object> attr = new HashMap<String, Object>();
attr.put("type", ConversationType_Group);
imClient.createConversation(clientIds, attr, new AVIMConversationCreatedCallback() {
  @Override
  public void done(AVIMConversation conversation, AVException e) {
    if (null != conversation) {
      // 成功了!
      Intent intent = new Intent(currentActivity, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      currentActivity.startActivity(intent);
    }
  }
});

打响之后,我们就是可入聊天界面了。

往群组发送信息

发送信息非常简单,与前方单聊的场景同样。

咱俩见面小心到,AVIMConversation 还有一个发送信息之章程:

public void sendMessage(final AVIMMessage message, final int messageFlag,
      final AVIMConversationCallback callback)

一旦这边 flag 的概念来如下三栽类型:

  • 暂态消息(AVIMConversation.TRANSIENT_MESSAGE_FLAG)。这种消息不会见叫电动保存(以后在历史信息被无法找到她),也未支持延迟收,离线用户还无会见收到推送通知,所以适合用来开控制协议。譬如聊天过程中「某某正在输入中…」这样的状态信息,就抱通过暂态消息来发送。
  • 通常消息(AVIMConversation.NONTRANSIENT_MESSAGE_FLAG)。这种信息就是是咱们尽常用之信息类型,在
    LeanCloud
    云端会活动保存起来,支持延迟收和离线推送,以后当历史信息中好找到其。
  • 内需回执消息(AVIMConversation.RECEIPT_MESSAGE_FLAG)。这啊是一样种植家常消息,只是消息于对方接收后
    LeanCloud 服务端会发送一个回执通知给发送方(这虽是
    AVIMMessageHandler 中
    public void onMessageReceipt(AVIMMessage message, AVIMConversation conversation, AVIMClient client)
    函数被调用的空子)。

接到群组消息

接过一个群组的信息,与接纳单聊的信息啊是相同的。

分子管理

以询问及聊天室成员之后,可以吃用户约部分协调之情侣在,作为管理员也堪去除一些「可怕」的积极分子。
参加新成员的 API 如下:

// 假设需要邀请 Alex,Ben,Chad 三人加入对话
List<String> userIds = new ArrayList<String>();
userIds.add("Alex");
userIds.add("Ben");
userIds.add("Chad");
conversation.addMembers(userIds, new AVIMConversationCallback() {
  @Override
  public void done(AVException error) {
    if (null != error) {
      // 加入失败,报错.
      error.printStackTrace();
    } else {
      // 发出邀请,此后新成员就可以看到这个对话中的所有消息了。
      Logger.d("invited.");
    }
  }
});

邀成功之后,相关方收到通知的时序是这么的:

    操作者(管理员)                    被邀请者                        其他人
1, 发出请求 addMembers
2,                               收到 onInvited 通知
3, 收到 onMemberJoined 通知      收到 onMemberJoined 通知      收到 onMemberJoined 通知

相应地,踢人常之调用 API 是:

List<String> userIds = new ArrayList<String>();
userIds.add("Alex");
conversation.kickMembers(userIds, new AVIMConversationCallback() {
  @Override
  public void done(AVException error) {
    if (null != error) {
      // 失败,报错.
      error.printStackTrace();
    } else {
      // 成功。
      Logger.d("kicked.");
    }
  }
});

踢人时常,相关方收到通知的时序亚洲必赢app在哪下载如下:

    操作者(管理员)                被踢者                       其他人
1, 发出请求 kickMembers
2,                          收到 onKicked 通知
3, 收到 onMemberLeft 通知                             收到 onMemberLeft 通知

注意!
假若请、踢人操作有的时,被邀请者/被踢者当前不在线,那么通知消息并无见面被离线缓存,所以她们又上线的时候用未会见接收通知。

取得历史信息

LeanMessage 会将非暂态消息自动保存在云端,之后开发者可以经
AVIMConversation 来取该对话的具有历史信息。获取历史信息的 API 如下:

String oldestMsgId;
long oldestMsgTimestamp;
conversation.queryMessages(oldestMsgId,oldestMsgTimestamp, limit, new AVIMHistoryMessageCallback(){
  @Override
  public void done(List<AVIMMessage> messages, AVException e) {
    if (null != e) {
      // 出错了:(
    } else {
      // 成功,可以将消息加入缓存,同时更新 UI
    }
  }
});

注意:
落历史信息的当儿,LeanCloud
云端是打某条信息开始,往前头寻找开发者指定的 N
条消息,返回给客户端。为者,获取历史信息需要传入三独参数:起始消息的
msgId,起始消息之殡葬时间戳,需要取得之信息条数。

通过这无异于 API 拿到的音信就是是 AVIMMessage 或 AVIMTypedMessage
实例数组,开发者可以像之前接受新信息通知一致处理。

启用离线消息推送(仅对 iOS 平台用户中)

随便是特聊还是群聊,当用户 A
发出信息后,如果目标对话中生出部分用户眼前不在线,LeanCloud
云端可以供离线推送的法门来提醒用户。这等同效应默认是关的,你得在
LeanCloud 应用控制台中开启它。开启方法如下:

  • 报到 LeanCloud 应用控制台,选择是的使用上;
  • 慎选最好顶端的「消息」服务,依次点击左边菜单「实时消息」->「设置」;
  • 以右侧「iOS
    用户离线时的推送内容」下填好你若推送出去的音讯内容,保存;

这般 iOS 平台上的用户就足以收到 Push Notification
了(当然,前提是运本身申请及了 RemoteNotification
权限,也拿科学的推送证书及污染至了 LeanCloud 控制台)。

群组消息不打扰(仅对 iOS 平台用户中)

任凭是独自聊还是群聊,对于发于普通的 Conversation
的便消息,如果接收方当前不在线,LeanCloud 云端支持通过 Push
Notification
的艺术开展提醒。一般情形下这都是很好的,但是如果某群组特别活泼,那离线用户就见面接受了多的推送,会形成不聊之搅和。

针对斯 LeanCloud IM 服务啊同意单个用户来关闭/打开某个对话之离线推送功能。

搜群组

管是单聊,还是群聊,在 LeanCloud IM SDK
里面都是对话(Conversation)。我们于对话设置了之类几种植特性:

  • conversationId,字符串,对话 id,只读,对话创建之后由 LeanCloud
    云端赋予一个大局唯一的 id。
  • creator,字符串,对话创建者 id,只念,标识对话创建者信息
  • members,数组,对话参与者,这里记录了有着的参与者
  • name,字符串,对话的名,optional,可用来对于群组命名
  • attributes,Map/Dict,自定义属性,optional,供开发者自己扩大用。

咱提供了特别的近乎,来寻觅一定的群组:通过 imClient.getQuery()
得到一个 AVIMConversationQuery 实例,然后调用
AVIMConversationQuery.wherexxx
系列措施来充实约规范。例如要寻找时登录用户参与的有所群聊对话,其代码为

// 搜索 Tom 参与的所有群组对话
List<String> clients = new ArrayList<String>();
clients.add("Tom");
AVIMConversationQuery conversationQuery = imClient.getQuery();
conversationQuery.containsMember(clients);

// 之前有常量定义:
// const int ConversationType_OneOne = 0;
// const int ConversationType_Group = 1;
conversationQuery.whereEqualTo("attr.type", ConversationType_Group);

conversationQuery.findInBackground(new AVIMConversationQueryCallback(){
  @Override
  public void done(List<AVIMConversation> conversations, AVException e) {
    if (null != e) {
      // 出错了。。。
      e.printStackTrace();
    } else {
      if (null != conversation) {
        Logger.d("找到了符合条件的 " + conversations.size() + " 个对话");
      } else {
        Logger.d("没有找到符合条件的对话");
      }
    }
  }
});

AVIMConversationQuery 中设置规范的点子以及 AVQuery 类似。这里
conversationQuery.containsMember()
表示对话之成员中至少含有这些人口,可用来因一些成员查找对话;与之类似的还有一个
conversationQuery.withMembers()
则表示出还只有发生这些分子,用来冲所有成员查找目标对话;conversationQuery.whereXXX()
密密麻麻措施可用来界定对话名称和由定义属性,这里而强调的一点凡是,对于自定义属性的格原则,属性名一定要是因为
attr 开头,如上例所示,限定额外的 type 条件的时段需要指定的属于性名是
attr.type。具体可参考其头文件。

开放聊天室

绽开聊天室(也吃暂态对话)可以用来很多地方,譬如弹幕、直播等等。在
LeanCloud IM SDK
中,开放聊天室是同样接近特殊之群组,它吧支撑创造、加入/踢来成员等操作,消息记录会被封存并而供应获取;与平常群组不一样的地方实际体现为:

  • 不支持查询成员列表,你可经相关 API 查询在线人数;
  • 未支持离线消息、离线推送通知等职能;
  • 不曾成员进入、离开的关照;
  • 一个用户同样次等登录只能参加一个开放聊天室,加入新的盛开聊天室后会自行离开原先的聊天室;
  • 在后半时内断网重连见面自动进入原聊天室,超过此日子虽要重新加入;

创开放聊天室

暨普通的群组类似,建立一个盛开聊天室也是殊粗略的,只是以
AVIMClient.createConversation(conversationMembers, name, attributes, isTransient, callback)
中我们要传入 isTransient=true 选项。例如:

Map<String, Object> attr = new HashMap<String, Object>();
attr.put("type", ConversationType_Group);
imClient.createConversation(clientIds, name, attr, true, new AVIMConversationCreatedCallback() {
  @Override
  public void done(AVIMConversation conversation, AVException e) {
    if (null != conversation) {
      // 成功了,进入聊天室
      Intent intent = new Intent(currentActivity, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      currentActivity.startActivity(intent);
    }
  }
});

始建成功之后,我们即便可入聊天界面了。开放聊天室的其他操作,都与一般群组操作一样。

进入开放聊天室

设若任何极端用户还好入开放聊天室。作为开发者,我们得以经过通过特定条件检索到有开放聊天室,然后允许用户自由在,其演示代码为:

conversation.join(new AVIMConversationCallback(){
  @Override
  public void done(AVException e) {
    if (null != e) {
      // 出错了:(
    } else {
      // 成功,此时可以进入聊天界面了。。。
      Intent intent = new Intent(currentActivity, ChatActivity.class);
      Intent.putExtra(“conversation”, conversation);
      currentActivity.startActivity(intent);
    }
  }
});

询问在线人数

通过 AVIMConversation.getMemberCount()
方法可实时查询开放聊天室的在线人数。示例代码如下:

conversation.getMemberCount(new AVIMConversationMemberCountCallback(){
  @Override
  public void done(Integer memberCount, AVException e) {
    if (null != e) {
      // 出错了:(
    } else {
      // 成功,此时 memberCount 的数值就是实时在线人数
    }
  }
});

签名与安康

为满足开发者对权力和验证的渴求,LeanCloud
还设计了操作签名的机制。我们得以以 LeanCloud
应用控制台中的「设置」->「应用选项」->「聊天推送」下面勾选「聊天服务签约认证」来启用签名(强烈推荐这样做)。启用后,所有的用户登录、对话创建/加入、邀请成员、踢来成员等操作都亟需证明签名,这样开发者就足以对信息进行充分的主宰。

客户端即时边究竟该如何运用也?我们唯有需要贯彻 SignatureFactory
接口,然后于用户登录之前,把此接口的实例赋值给 AVIMClient
即可(AVIMClient.setSignatureFactory(factory))。

设定了 signatureFactory 之后,对于欲鉴权的操作,LeanCloud IM SDK
与劳务器端通讯的当儿还见面带动及采用自己别的 Signature 信息,LeanCloud
云端会使 app 的 masterKey 来证实信息的有效,保证聊天渠道的安康。

对于 SignatureFactory 接口,我们无非待贯彻就片独函数即可:

  /**
   * 实现一个基础签名方法 其中的签名算法会在SessionManager和AVIMClient(V2)中被使用
   */
  public Signature createSignature(String peerId, List<String> watchIds) throws SignatureException;

  /**
   * 实现AVIMConversation相关的签名计算
   */
  public Signature createConversationSignature(String conversationId, String clientId,
      List<String> targetIds, String action) throws SignatureException;

createSignature
函数会以用户登录的当儿被调用,createConversationSignature
会在对话创建/加入、邀请成员、踢来成员等操作时吃调用。

公需要举行的即使是仍前文所陈述之签名算法实现签约,其中 Signature
声明如下:

public class Signature {
  public List<String> getSignedPeerIds();
  public void setSignedPeerIds(List<String> signedPeerIds);

  public String getSignature();
  public void setSignature(String signature);

  public long getTimestamp();
  public void setTimestamp(long timestamp);

  public String getNonce();
  public void setNonce(String nonce);
}

里面四独特性分别是:

  • signature 签名
  • timestamp 时间戳,单位秒
  • nonce 随机字符串 nonce
  • signedPeerIds 放行的 clientId 列表,v2 中已经摈弃不用

下面的代码展示了因 LeanCloud
云代码进行签约时,客户端的实现部分,你得参照其来成功自己之逻辑实现:

public class KeepAliveSignatureFactory implements SignatureFactory {
 @Override
 public Signature createSignature(String peerId, List<String> watchIds) {
   Map<String,Object> params = new HashMap<String,Object>();
   params.put("self_id",peerId);
   params.put("watch_ids",watchIds);

   try{
     Object result =  AVCloud.callFunction("sign",params);
     if(result instanceof Map){
       Map<String,Object> serverSignature = (Map<String,Object>) result;
       Signature signature = new Signature();
       signature.setSignature((String)serverSignature.get("signature"));
       signature.setTimestamp((Long)serverSignature.get("timestamp"));
       signature.setNonce((String)serverSignature.get("nonce"));
       return signature;
     }
   }catch(AVException e){
     throw (SignatureFactory.SignatureException) e;
   }
   return null;
 }

  @Override
  public Signature createConversationSignature(String convId, String peerId, List<String> targetPeerIds,String action){
   Map<String,Object> params = new HashMap<String,Object>();
   params.put("self_id",peerId);
   params.put("group_id",convId);
   params.put("group_peer_ids",targetPeerIds);
   params.put("action",action);

   try{
     Object result = AVCloud.callFunction("group_sign",params);
     if(result instanceof Map){
        Map<String,Object> serverSignature = (Map<String,Object>) result;
        Signature signature = new Signature();
        signature.setSignature((String)serverSignature.get("signature"));
        signature.setTimestamp((Long)serverSignature.get("timestamp"));
        signature.setNonce((String)serverSignature.get("nonce"));
        return signature;
     }
   }catch(AVException e){
     throw (SignatureFactory.SignatureException) e;
   }
   return null;
  }
}

LeanCloud IM SDK
专注做好底层的报道服务,有重新多好定制化的地方,譬如说:

  • 账户体系跟 IM 系统是分手之;
  • 信息成为离线推送的时段,推送内容开发者是可以定制的;
  • 经 web hook,开发者可以对信息进行双重多处理;
  • 闲谈过程中经过信息鉴权机制,开发者可以产生双重多控制;

盖不够 UI
组件,实事求是地讲话在新用户接入成本或有些高,但是当业务范围扩张、产品求变换多过后,相信大家会愈来愈爱
LeanCloud 这种自由灵活的下体验,以及稳定快速的服务品质。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2018 亚洲必赢app官方下载 版权所有