融云快速集成Demo+自定义消息+连接+会话界面+会话列表+发送消息+用户信息提供者

项目总结之即时通讯
融云的服务真是快,有问题提工单,工程师回答速度快,可以很方便解决实际开发中的问题。作为总结,我们还是随便聊聊融云的使用吧!直接进入正题————>>>
首先去融云开发者平台注册、下载SDK、导包、连接、实现会话列表和会话界面这里就简单说明一下。不懂的可以去之前文章看。本片重点说一下自定义消息和plugin扩展区域自定义。
第一步,使用第三方的东西肯定要去他们的官网注册一个开发者账号,步骤很简单,一步步填写,下一步就行。注意手机号的填写,还是要填写真实的,貌似有条规定,如果手机号为空号可能会导致他们不会给改用户下的app提供服务,所以为了安全起见还是填写真实的手机号码。注册链接地址。
第二步:下载SDK,建议SDK别使用当前太低版本、因为有些功能可能不支持。下载SDK时,我们也要把官方提供的demo下载下来,毕竟这是第一手资料,官网提供的demo功能还是比较丰富的,如果应用要求的功能不是很多,demo里面提供的基本功能使应该能满足的。demo可能是托管在github上的,所以还要有个git账号。请自行注册,毕竟开发者还是应该多去上面看看大牛写的开源东西来学习。
第三步:注册应用,使用第三方的工具,不注册怎么用呢?个人中心填写下应用的基本情况应该没啥问题了。

简要的几个步骤,具体使用可以参照官方提供的帮助文档,官方文档地址戳这里

功能介绍

前沿简介

前奏

使用第三方的库,首先就需要进行第三方要求的初始化操作,这部分代码,基本直接copy官网提供的就可以,这样可以保证准确性。所以这里简要介绍需要我们处理的几个点。
1、Manifest.xml文件中:
android:host选项的值全部为自己应用的包名。例如:android:host=”com.dsw.infor”
meta-data标签中的appkey的值要改为自己应用申请的appkey

    

     
    

     
     
    
     
    
    
     
    
    
     
     
     
     
     
     
    
    
    
    
     
     
    
     
     
    
    
    

    
    
        
            
                

                
            
        
        
            
                
                
                
            
        
        
            
                

                

                
            
        
    


2、在我们的Application中进行初始化,执行RongIM.init(this);
代码如下:

/**
 * 应用启动时,判断用户是否已接受隐私协议,如果已接受,正常初始化;否则跳转到隐私授权页面请求用户授权。
 */
public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
//        if (!AppContext.isInitialized()) {
//            AppContext.init(getApplicationContext());
//        }
        //用户已接受隐私协议,进行初始化
        String appKey = "pvxdm17jpws8r";
        //            第一个参数必须传应用上下文
        RongIM.init(this.getApplicationContext(), appKey);
        //注册Plugin自定义类型
        registerExtensionPlugin();
        //消息自定义类型
        RongIM.registerMessageType(RedPackageMessage.class);
        RongIM.registerMessageTemplate(new RedPackageItemProvider());
    }

    private void registerExtensionPlugin() {
        List moduleList = RongExtensionManager.getInstance().getExtensionModules();
        IExtensionModule defaultModule = null;
        if (moduleList != null) {
            for (IExtensionModule module : moduleList) {
                if (module instanceof DefaultExtensionModule) {
                    defaultModule = module;
                    break;
                }
            }
            if (defaultModule != null) {
                //移除已注册的默认模块,替换成自定义模块RongExtensionManager.getInstance().unregisterExtensionModule(defaultModule);
                RongExtensionManager.getInstance().unregisterExtensionModule(defaultModule);
                RongExtensionManager.getInstance().registerExtensionModule(new SealExtensionModule());
            }
        }
    }
}

3、初始化的工作完成后,然后我们就在我们成功登陆后,进行服务器的链接。此时,我们需要调用我们的后台来获取融云认证的token信息。测试阶段,我们可以使用api调试,手动生成来用。

RongIM.connect(token, new ConnectCallback() {

                    @Override
                    public void onSuccess(String arg0) {
                        Log.d("RongClound", "RongClound: Tocken Success");
                    }

                    @Override
                    public void onError(ErrorCode arg0) {
                        Log.d("RongClound", "RongClound: Tocken Error,ErrorCode:" + arg0);
                    }

                    @Override
                    public void onTokenIncorrect() {
                        Log.d("RongClound", "RongClound: onTokenIncorrect");
                    }
                });

4.单聊功能
由于IMKit中融云提供的界面都是基于fragment,所以使用也是简单,我们只需要简单配置下我们的会话列表界面就可以了,比如:



    

布局搞好了,我们要创建一个ConversationActivity来进行显示。

public class ConversationListActivity extends FragmentActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_conversation_list);

        ConversationListFragment conversationListFragment=new ConversationListFragment();
        // 此处设置 Uri. 通过 appendQueryParameter 去设置所要支持的会话类型. 例如
        // .appendQueryParameter(Conversation.ConversationType.PRIVATE.getName(),"false")
        // 表示支持单聊会话, false 表示不聚合显示, true 则为聚合显示
        Uri uri = Uri.parse("rong://" +
                getApplicationContext().getApplicationInfo().packageName).buildUpon()
                .appendPath("conversationlist")
                .appendQueryParameter(Conversation.ConversationType.PRIVATE.getName(), "false") //设置私聊会话是否聚合显示
                .appendQueryParameter(Conversation.ConversationType.GROUP.getName(), "false")//群组
                .appendQueryParameter(Conversation.ConversationType.PUBLIC_SERVICE.getName(), "false")//公共服务号
                .appendQueryParameter(Conversation.ConversationType.APP_PUBLIC_SERVICE.getName(), "false")//订阅号
                .appendQueryParameter(Conversation.ConversationType.SYSTEM.getName(), "true")//系统
                .build();

        conversationListFragment.setUri(uri);
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace(R.id.container, conversationListFragment);
        transaction.commit();

Activity创建好自然要在Manifest中进行声明

        
            
                

                

                
            
        

回话界面



    

public class ConversationActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_conversation);
        ConversationFragment conversationFragment = new ConversationFragment();
        Intent intent = getIntent(); // 取得从上一个Activity当中传递过来的Intent对象
        String targetId = null;
        if (intent != null) {
            targetId = intent.getStringExtra("targetId");
        }
        Uri uri = Uri.parse("rong://" +
                getApplicationContext().getApplicationInfo().packageName).buildUpon()
                .appendPath("conversation").appendPath("private")
                .appendQueryParameter("targetId", targetId)//设置私聊会话是否聚合显示,targetId:单聊人的id
                .build();

        conversationFragment.setUri(uri);
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace(R.id.container, conversationFragment);
        transaction.commit();
    }
}

至此单聊功能就实现了!开始进入正题自定义消息和Plugin扩展。
自定义消息
参考资料:http://www.rongcloud.cn/docs/android.html#新建消息

  1. 自定义消息实体 –RedPackageMessage(一个自定义的红包消息)
package com.example.mydemoplugin.PhoneInfoProvider;

/**
 * Created by zhangbowen on 6/15/21.
 **/

import android.os.Parcel;
import android.util.Log;

import com.alibaba.fastjson.JSON;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;

import io.rong.common.ParcelUtils;
import io.rong.imlib.MessageTag;
import io.rong.imlib.model.MessageContent;
import io.rong.message.CSSuspendMessage;

/*
 * 注解名:MessageTag ;属性:value ,flag; value 即 ObjectName 是消息的唯一标识不可以重复,
 * 开发者命名时不能以 RC 开头,避免和融云内置消息冲突;flag 是用来定义消息的可操作状态。
 *如下面代码段,自定义消息名称 CustomizeMessage ,vaule 是 app:custom ,
 * flag 是 MessageTag.ISCOUNTED | MessageTag.ISPERSISTED 表示消息计数且存库。
 * app:RedPkgMsg: 这是自定义消息类型的名称,测试的时候用"app:RedPkgMsg";
 * */
@MessageTag(value = "app:RedPkgMsg", flag = MessageTag.ISCOUNTED | MessageTag.ISPERSISTED)
public class RedPackageMessage extends MessageContent {

    //自定义的属性
    private String title;
    private String storeName;
    private String desc1;
    private String desc2;

    public RedPackageMessage() {
    }

    public static RedPackageMessage obtain(String title, String storeName, String desc1, String desc2) {
        RedPackageMessage message = new RedPackageMessage();
        message.title = title;
        message.storeName = storeName;
        message.desc1 = desc1;
        message.desc2 = desc2;
        return message;
    }

    /*
     *
     * 实现 encode() 方法,该方法的功能是将消息属性封装成 json 串,
     * 再将 json 串转成 byte 数组,该方法会在发消息时调用,如下面示例代码:
     * */
    @Override
    public byte[] encode() {
        JSONObject jsonObj = new JSONObject();

        try {
            jsonObj.put("title", this.getTitle());
            jsonObj.put("storeName", this.getStoreName());
            jsonObj.put("desc1", this.getDesc1());
            jsonObj.put("desc2", this.getDesc2());

        } catch (JSONException e) {
            Log.e("JSONException", e.getMessage());
        }

        try {
            return jsonObj.toString().getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
     * 覆盖父类的 MessageContent(byte[] data) 构造方法,该方法将对收到的消息进行解析,
     * 先由 byte 转成 json 字符串,再将 json 中内容取出赋值给消息属性。
     * */
    public RedPackageMessage(byte[] data) {
        String jsonStr = null;

        try {
            jsonStr = new String(data, "UTF-8");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }

        try {
            JSONObject jsonObj = new JSONObject(jsonStr);

            if (jsonObj.has("title"))
                setTitle(jsonObj.optString("title"));

            if (jsonObj.has("storeName"))
                setStoreName(jsonObj.optString("storeName"));

            if (jsonObj.has("desc1"))
                setDesc1(jsonObj.optString("desc1"));

            if (jsonObj.has("desc2"))
                setDesc2(jsonObj.optString("desc2"));

        } catch (JSONException e) {
            Log.d("JSONException", e.getMessage());
        }
    }

    //给消息赋值。
    public RedPackageMessage(Parcel in) {

        setTitle(ParcelUtils.readFromParcel(in));//该类为工具类,消息属性
        //这里可继续增加你消息的属性
        setStoreName(ParcelUtils.readFromParcel(in));//该类为工具类,消息属性
        setDesc1(ParcelUtils.readFromParcel(in));//该类为工具类,消息属性
        setDesc2(ParcelUtils.readFromParcel(in));//该类为工具类,消息属性
    }

    /**
     * 读取接口,目的是要从Parcel中构造一个实现了Parcelable的类的实例处理。
     */
    public static final Creator CREATOR = new Creator() {

        @Override
        public RedPackageMessage createFromParcel(Parcel source) {
            return new RedPackageMessage(source);
        }

        @Override
        public RedPackageMessage[] newArray(int size) {
            return new RedPackageMessage[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 将类的数据写入外部提供的 Parcel 中。
     *
     * @param dest  对象被写入的 Parcel。
     * @param flags 对象如何被写入的附加标志。
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        ParcelUtils.writeToParcel(dest, getTitle());
        ParcelUtils.writeToParcel(dest, getStoreName());
        ParcelUtils.writeToParcel(dest, getDesc1());
        ParcelUtils.writeToParcel(dest, getDesc2());
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getStoreName() {
        return storeName;
    }

    public void setStoreName(String storeName) {
        this.storeName = storeName;
    }

    public String getDesc1() {
        return desc1;
    }

    public void setDesc1(String desc1) {
        this.desc1 = desc1;
    }

    public String getDesc2() {
        return desc2;
    }

    public void setDesc2(String desc2) {
        this.desc2 = desc2;
    }
}

2.自定义消息提供者

package com.example.mydemoplugin.PhoneInfoProvider;

import android.content.ClipboardManager;
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.example.mydemoplugin.R;

import io.rong.imkit.RongIM;
import io.rong.imkit.emoticon.AndroidEmoji;
import io.rong.imkit.model.ProviderTag;
import io.rong.imkit.model.UIMessage;
import io.rong.imkit.utilities.OptionsPopupDialog;
import io.rong.imkit.widget.provider.IContainerItemProvider;
import io.rong.imlib.RongIMClient;
import io.rong.imlib.model.Message;

/**
 * Created by zhangbowen on 6/15/21.PhoneInfo的布局
 * desc新建一个消息类继承 IContainerItemProvider.MessageProvider 类,实现对应接口方法,
 * 1.注意开头的注解!
 * 2.注意泛型!
 */
@ProviderTag(
        messageContent = RedPackageMessage.class,
        showReadState = true
)
public class RedPackageItemProvider extends IContainerItemProvider.MessageProvider {

    public RedPackageItemProvider() {
    }

    @Override
    public View newView(Context context, ViewGroup viewGroup) {
        //这就是展示在会话界面的自定义的消息的布局
        View view = LayoutInflater.from(context).inflate(R.layout.item_redpackage_message, null);
        ViewHolder holder = new ViewHolder();
        holder.ll_msg = (FrameLayout) view.findViewById(R.id.ll_msg);
        holder.tvTitle = (TextView) view.findViewById(R.id.tv_title);
        holder.tvStoreName = (TextView) view.findViewById(R.id.tv_store_name);
        holder.tvDesc1 = (TextView) view.findViewById(R.id.tv_desc1);
        holder.tvDesc2 = (TextView) view.findViewById(R.id.tv_desc2);
        view.setTag(holder);
        return view;
    }

    @Override
    public void bindView(View view, int i, RedPackageMessage redPackageMessage, UIMessage message) {

        //根据需求,适配数据
        ViewHolder holder = (ViewHolder) view.getTag();
        if (message.getMessageDirection() == Message.MessageDirection.SEND) {//消息方向,自己发送的
//            holder.ll_msg.setBackgroundResource(io.rong.imkit.R.drawable.rc_ic_bubble_right);
        } else {
//            holder.ll_msg.setBackgroundResource(io.rong.imkit.R.drawable.rc_ic_bubble_left);
        }
//        AndroidEmoji.ensure((Spannable) holder.message.getText());//显示消息中的 Emoji 表情。
        holder.tvTitle.setText(redPackageMessage.getTitle());
        holder.tvStoreName.setText(redPackageMessage.getStoreName());
        holder.tvDesc1.setText(redPackageMessage.getDesc1());
        holder.tvDesc2.setText(redPackageMessage.getDesc2());
    }

    @Override
    public Spannable getContentSummary(RedPackageMessage redPackageMessage) {
        return new SpannableString(redPackageMessage.getDesc1());
    }

    @Override
    public void onItemClick(View view, int i, RedPackageMessage redPackageMessage, UIMessage uiMessage) {

    }

    @Override
    public void onItemLongClick(View view, int i, RedPackageMessage redPackageMessage, UIMessage uiMessage) {
        //实现长按删除等功能,咱们直接复制融云其他provider的实现
        String[] items1;//复制,删除
        items1 = new String[]{view.getContext().getResources().getString(io.rong.imkit.R.string.rc_dialog_item_message_copy), view.getContext().getResources().getString(io.rong.imkit.R.string.rc_dialog_item_message_delete)};

        OptionsPopupDialog.newInstance(view.getContext(), items1).setOptionsPopupDialogListener(new OptionsPopupDialog.OnOptionsItemClickedListener() {
            public void onOptionsItemClicked(int which) {
//                Log.e("实现长按删除等功能",uiMessage.getMessage().getMessageId()+"---"+redPackageMessage.describeContents()+"-----"+uiMessage.getMessage());
                //长安复制暂时没有实现
                if (which == 0) {
                    ClipboardManager clipboard = (ClipboardManager) view.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
//                    clipboard.setText(redPackageMessage.encode());//这里是自定义消息的消息属性
                } else if (which == 1) {
                    RongIM.getInstance().deleteMessages(new int[]{uiMessage.getMessage().getMessageId()}, (RongIMClient.ResultCallback) null);
                }
            }
        }).show();

    }

    private static class ViewHolder {
        TextView tvTitle, tvStoreName, tvDesc1, tvDesc2;
        FrameLayout ll_msg;
    }
}

3.注意自定义消息的布局:(整体布局外面再嵌套一层)




    

        

        

        

        

    

WeChatd051bc561c017d0e6e02e2410ee9c7aa.png

4.注册消息类型以及消息提供者
RongIM.init(this);
//注意,要在初始化之后注册
RongIM.registerMessageType(RedPackageMessage.class);
RongIM.registerMessageTemplate(new RedPackageItemProvider());
5.官网测试发消息


WeChatb0b6e1c0d1863f8cdc08bfcd9bd2ad24.png

6.自定义红包Plugin

/**
 * Created by zhangbowen on 6/15/21.
 * 自定义红包Plugin
 **/
public class MyPlugin implements IPluginModule {
    @Override
    public Drawable obtainDrawable(Context context) {
        return ContextCompat.getDrawable(context, io.rong.imkit.R.drawable.rc_cs_evaluate_selector);
    }

    @Override
    public String obtainTitle(Context context) {
        return "红包";
    }

    @Override
    public void onClick(Fragment fragment, RongExtension rongExtension) {
        Log.e("发红包啦!!!", rongExtension.getTargetId());
        RedPackageMessage redPackageMessage = RedPackageMessage.obtain("测试" + new Random().nextInt(1000), "商店名称" + new Random().nextInt(1000), "描述" + new Random().nextInt(1000), "描述" + new Random().nextInt(1000));
        RongIM.getInstance().sendMessage(Conversation.ConversationType.PRIVATE, rongExtension.getTargetId(), redPackageMessage, "测试一下pushContent" + new Random().nextInt(100), "测试一下pushData" + new Random().nextInt(100)
                , new IRongCallback.ISendMediaMessageCallback() {
                    @Override
                    public void onAttached(Message message) {

                    }

                    @Override
                    public void onSuccess(Message message) {

                    }

                    @Override
                    public void onError(Message message, RongIMClient.ErrorCode errorCode) {

                    }

                    @Override
                    public void onProgress(Message message, int i) {

                    }

                    @Override
                    public void onCanceled(Message message) {

                    }
                });
    }

    @Override
    public void onActivityResult(int i, int i1, Intent intent) {
        Log.e("发红包啦!!!", "onActivityResult");
    }
}
/**
 * Created by zhangbowen on 6/15/21.
 * Plugin自定义类型
 **/
public class SealExtensionModule extends DefaultExtensionModule {
    @Override
    public List getPluginModules(Conversation.ConversationType conversationType) {
        List pluginModuleList = new ArrayList<>();
        IPluginModule image = new ImagePlugin();
        IPluginModule location = new DefaultLocationPlugin();
        //        IPluginModule audio = new AudioPlugin();
        //        IPluginModule video = new VideoPlugin();
        IPluginModule file = new FilePlugin();
        IPluginModule myPlugin = new MyPlugin();

        if (conversationType.equals(Conversation.ConversationType.GROUP) ||
                conversationType.equals(Conversation.ConversationType.DISCUSSION) ||
                conversationType.equals(Conversation.ConversationType.PRIVATE)) {
            pluginModuleList.add(image);
            pluginModuleList.add(location);
            //            pluginModuleList.add(audio);
            //            pluginModuleList.add(video);
            pluginModuleList.add(file);
            pluginModuleList.add(myPlugin);
        } else {
            pluginModuleList.add(image);
        }

        return pluginModuleList;
    }

    @Override
    public List getEmoticonTabs() {
        return super.getEmoticonTabs();
    }
}

7.将自定义好的Plugin重新注册(在init初始化之后注册)

    private void registerExtensionPlugin() {
        List moduleList = RongExtensionManager.getInstance().getExtensionModules();
        IExtensionModule defaultModule = null;
        if (moduleList != null) {
            for (IExtensionModule module : moduleList) {
                if (module instanceof DefaultExtensionModule) {
                    defaultModule = module;
                    break;
                }
            }
            if (defaultModule != null) {
                //移除已注册的默认模块,替换成自定义模块RongExtensionManager.getInstance().unregisterExtensionModule(defaultModule);
                RongExtensionManager.getInstance().unregisterExtensionModule(defaultModule);
                RongExtensionManager.getInstance().registerExtensionModule(new SealExtensionModule());
            }
        }
    }

以上就是关于融云在项目中的使用,融云提供很多功能,希望以后有机会再深入研究吧!
简单demo下载地址

你可能感兴趣的:(融云快速集成Demo+自定义消息+连接+会话界面+会话列表+发送消息+用户信息提供者)