融云知识点

Posted jielundewode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了融云知识点相关的知识,希望对你有一定的参考价值。

1.为选择图片发送界面加上返回

融云自带的选择发送图片界面没有返回按钮,为了app界面统一完整需要加上:
首先,连接融云服务器之前:

    //扩展功能自定义
        InputProvider.ExtendProvider[] provider = {
                new MyImageInputProvider(RongContext.getInstance()),//图片
                new CameraInputProvider(RongContext.getInstance())//相机
        };
        RongIM.getInstance().resetInputExtensionProvider(Conversation.ConversationType.PRIVATE, provider);
        RongIM.getInstance().resetInputExtensionProvider(Conversation.ConversationType.GROUP, provider);

自定义一个ImageProvider,实现打开自定义Activity界面的功能:

public class MyImageInputProvider extends ImageInputProvider {
    public MyImageInputProvider(RongContext context) {
        super(context);
    }

    public void onPluginClick(View view) {
        Intent intent = new Intent();
        intent.setClass(view.getContext(), SelPicActivity_.class);
        this.startActivityForResult(intent, 23);
    }
}

自定义一个SelPicActivity,主要代码还是来自于sdk的io.rong.imkit.tools.SelectPictureActivity,主要是添加一个返回按钮

2.聊天图片可滑动切换

融云目前没有类似qq那样的可滑动切换查看聊天发送的图片,首先需要监听发送消息及接收的消息,如果是图片就保存到数据库中。

   /**
         *  设置接收消息的监听器。
         * 需要注意的是其应该放在连接融云服务器之前。
         */
        RongIM.setOnReceiveMessageListener(new MyReceiveMsgListener(app));
  /**
         *  设置发送消息的监听器。
         * 需要注意的是其应该放在连接融云服务器之后。
         */
 RongIM.getInstance().setSendMessageListener(new MySendMessageListener(app));

接下来看接口实现:

/**
 * Desc:融云接受消息监听(connect方法之前调用)
 */
public class MyReceiveMsgListener implements RongIMClient.OnReceiveMessageListener {
    ParentsApp app;

    public MyReceiveMsgListener(ParentsApp app) {
        this.app = app;
    }

    @Override
    public boolean onReceived(Message message, int i) {

        if (message.getContent() instanceof ImageMessage) {
            ImageMessage m = (ImageMessage) message.getContent();
            ImPhoto photo = new ImPhoto(message.getMessageId(), message.getTargetId(), m.getRemoteUri().toString());
            ImPhoto.save(app, photo);
        }

        return false;
    }
}
/**
 * Desc:融云发送消息监听(connect方法之后)
 */
public class MySendMessageListener implements RongIM.OnSendMessageListener {

    private ParentsApp app;

    public MySendMessageListener(ParentsApp app) {
        this.app = app;
    }

    public Message onSend(Message message) {
        if (message.getContent() instanceof ImageMessage) {
            ImageMessage m = (ImageMessage) message.getContent();
            if (m.getLocalUri() != null) {
                ImPhoto photo = new ImPhoto(message.getMessageId(), message.getTargetId(), m.getLocalUri().toString());
                ImPhoto.save(app, photo);
            } else if (m.getRemoteUri() != null) {
                ImPhoto photo = new ImPhoto(message.getMessageId(), message.getTargetId(), m.getRemoteUri().toString());
                ImPhoto.save(app, photo);
            }
//
//                    LogUtils.e(m.getLocalUri().toString());
//                    LogUtils.e(message.getMessageId() + "???????");
        }
        return message;
    }

    @Override
    public boolean onSent(Message message, RongIM.SentMessageErrorCode sentMessageErrorCode) {
        if (message.getContent() instanceof ImageMessage) {
            ImageMessage m = (ImageMessage) message.getContent();
            ImPhoto photo = new ImPhoto(message.getMessageId(), message.getTargetId(), m.getRemoteUri().toString());
            ImPhoto.save(app, photo);
            LogUtils.e(m.getRemoteUri().toString());
            LogUtils.e(message.getMessageId() + "-*---------");
        }
        return true;
    }
}

来看一个ImPhoto的实现(用了xutils的DbUtils保存到数据库,很简单,不再赘述),也很简单

/**
 * Desc:聊天信息中的图片
 */
@Table(name = "chat_photo")
public class ImPhoto implements Parcelable {

    public static final Parcelable.Creator<ImPhoto> CREATOR = new Parcelable.Creator<ImPhoto>() {
        @Override
        public ImPhoto createFromParcel(Parcel source) {
            return new ImPhoto(source);
        }

        @Override
        public ImPhoto[] newArray(int size) {
            return new ImPhoto[size];
        }
    };
    @Column(name = "id", isId = true, autoGen = false)
    public int id;
    @Column(name = "imid")
    public String imid;//谁的聊天记录中的图片
    @Column(name = "url")
    public String url;

    public ImPhoto() {
    }

    public ImPhoto(int id, String imid, String url) {
        this.id = id;
        this.imid = imid;
        this.url = url;
    }

    protected ImPhoto(Parcel in) {
        this.id = in.readInt();
        this.imid = in.readString();
        this.url = in.readString();
    }

    public static void save(Context context, ImPhoto photo) {
        DbManager dbManager = DbUtils.getDb(context);
        try {
            dbManager.saveOrUpdate(photo);
            List<ImPhoto> imPhotos = dbManager.findAll(ImPhoto.class);
            int count = imPhotos.size();
            if (count > 100) {
                for (int i = 0; i < count - 30; ++i) {
                    dbManager.deleteById(ImPhoto.class, imPhotos.get(i).getId());
                }
            }
        } catch (DbException e) {
            e.printStackTrace();
        }

    }

    public static Map<Integer, List<ImPhoto>> getPhotos(Context context, int id) {
        DbManager dbManager = DbUtils.getDb(context);
        try {
            Map<Integer, List<ImPhoto>> res = new HashMap<>();
            List<ImPhoto> imPhotos = dbManager.findAll(ImPhoto.class);
            if (imPhotos == null || imPhotos.size() == 0) {
                return null;
            }
            int count = imPhotos.size();

            for (int i = 0; i < count; ++i) {
                if (imPhotos.get(i).getId() == id) {
                    res.put(i, imPhotos);
                    break;
                }
            }
            return res;
        } catch (DbException e) {
            return null;
        }

    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getImid() {
        return imid;
    }

    public void setImid(String imid) {
        this.imid = imid;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.id);
        dest.writeString(this.imid);
        dest.writeString(this.url);
    }
}

接下来最关键的,定义聊天内容点击事件

public class MyConversationBehaviorListener implements RongIM.ConversationBehaviorListener {
    /**
     * 当点击用户头像后执行。
     *
     * @param context          上下文。
     * @param conversationType 会话类型。
     * @param userInfo         被点击的用户的信息。
     * @return 如果用户自己处理了点击后的逻辑,则返回 true,否则返回 false,false 走融云默认处理方式。
     */
    @Override
    public boolean onUserPortraitClick(Context context, Conversation.ConversationType conversationType, UserInfo userInfo) {
        if (conversationType != Conversation.ConversationType.GROUP)
            return false;
        String imid = userInfo.getUserId();
        // if (Integer.parseInt(imid.substring(2)) != ((TeacherApp) context).getTeacher().id) {
        RongIM.getInstance().startPrivateChat(context, imid, userInfo.getName() + "\n" + "聊天");
        // }
        return true;
    }

    /**
     * 当长按用户头像后执行。
     *
     * @param context          上下文。
     * @param conversationType 会话类型。
     * @param userInfo         被点击的用户的信息。
     * @return 如果用户自己处理了点击后的逻辑,则返回 true,否则返回 false,false 走融云默认处理方式。
     */
    @Override
    public boolean onUserPortraitLongClick(Context context, Conversation.ConversationType conversationType, UserInfo userInfo) {
        //   AddFriendsInfoActivity_.intent(context).extra("imId", userInfo.getUserId()).extra("showAddBtn", false).start();
        return false;
    }

    /**
     * 当点击消息时执行。
     *
     * @param context 上下文。
     * @param view    触发点击的 View。
     * @param message 被点击的消息的实体信息。
     * @return 如果用户自己处理了点击后的逻辑,则返回 true, 否则返回 false, false 走融云默认处理方式。
     */
    @Override
    public boolean onMessageClick(Context context, View view, Message message) {
        if (message.getContent() instanceof ImageMessage) {
            Map<Integer, List<ImPhoto>> result = ImPhoto.getPhotos(context, message.getMessageId());
            if (result == null) {
                startSingleBrowser(context, message);
                return true;
            }
            Set<Map.Entry<Integer, List<ImPhoto>>> entry = result.entrySet();
            if (entry == null || entry.size() == 0) {
                startSingleBrowser(context, message);
                return true;
            }


            Map.Entry<Integer, List<ImPhoto>> dd = entry.iterator().next();
            if (dd.getKey() >= dd.getValue().size()) {
                startSingleBrowser(context, message);
                return true;
            }

            PhotoActivity_.intent(context).flags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    .extra("pos", dd.getKey())
                    .extra("photos", (ArrayList<ImPhoto>) dd.getValue())
                    .start();


        }
        return false;
    }


    void startSingleBrowser(Context context, Message message) {
        ImageMessage imageMessage = (ImageMessage) message.getContent();
        Intent intent = new Intent(context, PhotoActivity2_.class);

        intent.putExtra("photo", imageMessage.getLocalUri() == null ? imageMessage.getRemoteUri() : imageMessage.getLocalUri());
        if (imageMessage.getThumUri() != null)
            intent.putExtra("thumbnail", imageMessage.getThumUri());

        context.startActivity(intent);
    }

    /**
     * 当长按消息时执行。
     *
     * @param context 上下文。
     * @param view    触发点击的 View。
     * @param message 被长按的消息的实体信息。
     * @return 如果用户自己处理了长按后的逻辑,则返回 true,否则返回 false,false 走融云默认处理方式。
     */
    @Override
    public boolean onMessageLongClick(Context context, View view, Message message) {
//        if (message.getContent() instanceof ImageMessage) {
//            popWindow(context, view);
//            sendJpg(message);
//            return true;
//        }
        return false;
    }


    /**
     * 当点击链接消息时执行。
     *
     * @param context 上下文。
     * @param link    被点击的链接。
     * @return 如果用户自己处理了点击后的逻辑处理,则返回 true, 否则返回 false, false 走融云默认处理方式。
     */
    @Override
    public boolean onMessageLinkClick(Context context, String link) {
        return false;
    }

}

在连接融云服务器之前,调用这个接口:

  /**
         * 设置会话列表界面操作的监听器。
         */
        RongIM.setConversationBehaviorListener(new MyConversationBehaviorListener());

最后编写图片浏览Activity

@EActivity(R.layout.activity_image_browser)
public class PhotoActivity extends BaseActivity {

    @App
    ParentsApp app;

    @Extra("pos")
    int pos;

    @Extra("photos")
    ArrayList<ImPhoto> imPhotos;

    @ViewById(R.id.tv_title)
    TextView title;

    @ViewById(R.id.vp)
    ViewPager viewPager;

    @AfterViews
    void init() {
        initViews();
        ImagePagerAdapter adapter = new ImagePagerAdapter();
        viewPager.setAdapter(adapter);
        viewPager.setCurrentItem(pos);
    }

    private void initViews() {
        title.setText("照片查看");
    }

    @Click({R.id.back, R.id.tv})
    public void back() {
        finish();
    }

    @Override
    public void onSuccess() {

    }

    /**
     * @Description: 图片适配器
     */
    public class ImagePagerAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            return imPhotos.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            PhotoView view = new PhotoView(app);
            view.enable();
            view.setScaleType(ImageView.ScaleType.FIT_CENTER);
            view.setBackgroundColor(getResources().getColor(R.color.black));
            Glide.with(PhotoActivity.this)
                    .load(imPhotos.get(position).getUrl())
                    .error(R.drawable.default_error)
                    .placeholder(R.drawable.default_error)
                    .skipMemoryCache(true)
                    .dontTransform()
                    .into(view);
            container.addView(view);
            return view;
        }


        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

    }

}

布局文件

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <include
        android:id="@+id/title"
        layout="@layout/title_layout"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/title"/>

</RelativeLayout>

3.为好友加上头像

融云只提供聊天管道,好友关系需要自己维护,下面示例下为好友加上背景。
首先获取好友之后,需要将其保存到融云用户中:

    void refreshIm(ImFriend im, DbManager dbUtils) {
        try {
            ImFriend friend = dbUtils.findById(ImFriend.class, im.getImid());
            if (friend == null) {
                dbUtils.save(im);
            } else {
                dbUtils.update(im);
                if (TextUtils.isEmpty(im.getPicSrc())) {
                    if (!TextUtils.isEmpty(friend.getPicSrc())) {
                    //注意新的头像添加后通知融云刷新下用户信息
                        RongIM.getInstance().refreshUserInfoCache(new UserInfo(im.getImid(), im.getFriendName(), null));
                    }
                } else {
                    if (!im.getPicSrc().equals(friend.getPicSrc()))
                        RongIM.getInstance().refreshUserInfoCache(new UserInfo(im.getImid(), im.getFriendName(), Uri.parse(im.getPicSrc())));
                }
            }
        } catch (DbException e) {
            LogUtils.e("保存imFriend失败");
        }
    }

接下来设置用户提供者(在连接融云服务器之前):

   RongIM.setUserInfoProvider(new RongIM.UserInfoProvider() {
            @Override
            public UserInfo getUserInfo(String s) {
                try {
                    ImFriend imFriend = dbUtils.findById(ImFriend.class, s);
                    if (imFriend != null) {
                        UserInfo userInfo;
                        if (imFriend.getPicSrc() == null) {
                            userInfo = new UserInfo(imFriend.getImid(), imFriend.getFriendName(), null);
                        } else
                            userInfo = new UserInfo(imFriend.getImid(), imFriend.getFriendName(), Uri.parse(imFriend.getPicSrc()));
                        //  LogUtils.e("返回了");
                        RongIM.getInstance().refreshUserInfoCache(userInfo);
                        return userInfo;
                    }

                } catch (DbException e) {

                }
                // LogUtils.e("获取联系人信息:" + s);
                return getInfo(s);
            }
        }, true);

如果群组也有头像:

       RongIM.getInstance().setGroupInfoProvider(new RongIM.GroupInfoProvider() {

            @Override
            public Group getGroupInfo(String groupId) {

                try {
                    ImGroup imGroup = dbUtils.findById(ImGroup.class, groupId);
                    if (imGroup == null)
                        return null;
                    //暂时没有班级头像,传null
                    Group group = new Group(imGroup.id, imGroup.name, null);
                    return group;
                } catch (DbException e) {
                    LogUtils.e("数据库查找群信息失败");
                    return null;
                }

            }
        }, true);
  private UserInfo getInfo(final String s) {
        final DbManager dbUtils = DbUtils.getDb(app);
        info = null;
        requestFlag = false;
        //执行到此处说明本地没有缓存,请求网络
        OkHttpUtils
                .get()
                .url(Constants.GET_IM_INFO_URL)
                .addParams("IMID", s)
                .addParams("Token", CommonUtils.getParent(app).getToken())
                .tag(MainActivity.this)
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Request request, Exception e) {
                        requestFlag = true;
                        CommonUtils.showNoNet(app);
                    }

                    @Override
                    public void onResponse(String response) {
                        try {
                            JSONObject object = new JSONObject(response);
                            ImFriend imFriend = new ImFriend(s, object.getString("Name"), object.getString("PicSrc"));
                            if (imFriend.getPicSrc() == null) {
                                info = new UserInfo(imFriend.getImid(), imFriend.getFriendName(), null);
                            } else
                                info = new UserInfo(imFriend.getImid(), imFriend.getFriendName(), Uri.parse(imFriend.getPicSrc()));
                            RongIM.getInstance().refreshUserInfoCache(info);
                            dbUtils.saveOrUpdate(imFriend);
                            RongIM.getInstance().refreshUserInfoCache(info);
                        } catch (Exception e) {
                        }
                        requestFlag = true;
                    }
                });

        while (!requestFlag) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
            }
        }

        return info;
    }

填充用户头像与群组头像逻辑基本一致。

4.群组聊天实现@功能

直接上源码,懒得写了:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/layout_title"
        android:layout_width="match_parent"
        android:layout_height="132px"
        android:background="@color/status_color">

        <ImageView
            android:id="@+id/back"
            android:layout_width="40px"
            android:layout_height="40px"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20px"
            android:src="@drawable/btn_back"
            app:layout_auto_basewidth="height"/>

        <TextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@id/back"
            android:gravity="center"
            android:text="返回"
            android:textColor="@color/white"
            android:textSize="46px"/>

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:textColor="@color/white"
                android:textSize="45px"/>

            <TextView
                android:id="@+id/tv_title2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/tv_title"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="10px"
                android:text="聊天"
                android:textColor="@color/white"
                android:textSize="30px"/>
        </RelativeLayout>

        <ImageView
            android:id="@+id/img_user_info"
            android:layout_width="28dp"
            android:layout_height="28dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="10dp"
            android:scaleType="fitCenter"
            android:src="@drawable/ctp"
            app:layout_auto_basewidth="height"/>
    </RelativeLayout>

    <fragment
        android:id="@+id/conversation"
        android:name="io.rong.imkit.fragment.ConversationFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>
import android.content.Intent;
import android.net.Uri;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.beisai.utils.LogUtils;

import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.OnActivityResult;
import org.androidannotations.annotations.ViewById;

import java.util.Locale;

import io.rong.imkit.RongContext;
import io.rong.imkit.RongIM;
import io.rong.imkit.fragment.ConversationFragment;
import io.rong.imkit.widget.provider.TextInputProvider;
import io.rong.imlib.model.Conversation;

@EActivity(R.layout.activity_conversation)
public class ConversationActivity extends BaseActivity {

    @ViewById(R.id.img_user_info)
    ImageView imgInfo;

    /*显示聊天人姓名:王大狗*/
    @ViewById(R.id.tv_title)
    TextView mTitle;

    /*副标题,显示:王二狗的妈妈*/
    @ViewById(R.id.tv_title2)
    TextView mTitle2;

//    /**
//     * 刚刚创建完讨论组后获得讨论组的id 为targetIds,需要根据 为targetIds 获取 targetId
//     */
//    private String mTargetIds;
    /**
     * 目标 Id
     */
    private String mTargetId;
    /**
     * 会话类型
     */
    private Conversation.ConversationType mConversationType;
    private String chatType;
    private String sInput;

    @AfterViews
    void init() {
        getIntentDate(getIntent());
    }

    /**
     * 展示如何从 Intent 中得到 融云会话页面传递的 Uri
     */
    private void getIntentDate(Intent intent) {

        chatType = intent.getData().getLastPathSegment();//获得当前会话类型
        if (chatType.equals("group")) {
            imgInfo.setVisibility(View.GONE);
            mTitle.setText(intent.getData().getQueryParameter("title"));
            mTitle2.setText("群聊");
        } else {
            imgInfo.setVisibility(View.VISIBLE);
            String[] title = intent.getData().getQueryParameter("title").split("\n");
            mTitle.setText(title[0]);
            try {
                mTitle2.setText(title[1]);
            } catch (Exception e) {
                mTitle2.setText("聊天");
            }
        }
        checkTextInputEditTextChanged();
        mTargetId = intent.getData().getQueryParameter("targetId");

        //   mTargetIds = intent.getData().getQueryParameter("targetIds");

        mConversationType = Conversation.ConversationType.valueOf(intent.getData().getLastPathSegment().toUpperCase(Locale.getDefault
                ()));

        enterFragment(mConversationType, mTargetId);

    }

    String beforeText;
    String onTextChange;

    /**
     * 检测输入框变化
     */

    public void checkTextInputEditTextChanged() {

        TextInputProvider textInputProvider = new TextInputProvider(RongContext.getInstance());

        RongIM.setPrimaryInputProvider(textInputProvider);
        textInputProvider.setEditTextChangedListener(new TextWatcher() {

            @Override

            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                LogUtils.e("beforeTextChanged------>" + s);
                beforeText = s.toString();
            }


            @Override

            public void onTextChanged(CharSequence s, int start, int before, int count) {
                LogUtils.e("onTextChanged------>" + s);
                onTextChange = s.toString();
            }


            @Override

            public void afterTextChanged(Editable s) {
                LogUtils.e("after------>" + s);
                if (TextUtils.isEmpty(beforeText) ||beforeText.equals(onTextChange)) {
                    return;
                }
                sInput = s.toString();
                if ("group".equals(getIntent().getData().getLastPathSegment())) {
                    if (s.toString().endsWith("@")) {
                        AtActivity_.intent(ConversationActivity.this)
                                .parcelableArrayListExtra("member", getIntent().getParcelableArrayListExtra("member"))
                                .extra("classId", mTargetId.substring(2))
                                .startForResult(61);
                    }
                }
            }

        });
    }

    @OnActivityResult(61)
    void onResult(int resultCode, @OnActivityResult.Extra String txt) {
        TextInputProvider textInputProvider = (TextInputProvider) RongContext.getInstance().getPrimaryInputProvider();
        if (resultCode == RESULT_OK) {
            //重置文本框数据
            textInputProvider.setEditTextContent(sInput + txt);
        }
        //else {
        //textInputProvider.setEditTextContent(sInput + " ");
        // }
    }

    /**
     * 加载会话页面 ConversationFragment
     *
     * @param mConversationType 会话类型
     * @param mTargetId         目标 Id
     */
    private void enterFragment(Conversation.ConversationType mConversationType, String mTargetId) {

        ConversationFragment fragment = (ConversationFragment) getSupportFragmentManager().findFragmentById(R.id.conversation);

        Uri uri = Uri.parse("rong://" + getApplicationInfo().packageName).buildUpon()
                .appendPath("conversation").appendPath(mConversationType.getName().toLowerCase())
                .appendQueryParameter("targetId", mTargetId).build();

        fragment.setUri(uri);
    }
}

AtActivity不贴了,就是展示群组成员,选择好后回调即可。

以上是关于融云知识点的主要内容,如果未能解决你的问题,请参考以下文章

融云 iOS 常见问题总汇

android小知识点代码片段

融云im撤回消息

融云微课堂第五讲 | 基于原生代码开发 Flutter 插件

升级融云 4.0 及以上版本的兼容方案

融云升级到到5.0报错