融云 Android SDK 2.8.0+ Extension 开发文档


            
2016-11-30 17:25 | Android

回答:

融云 SDK 2.8.0 后对 会话界面输入区域、+号扩展区域、语音消息、Emoji 等进行了优化和重构,重构后上列区域有个统一的名称: Extension。本篇文档将会对 Extension 的概念,用法,自定义进行逐一讲解。


概念

1.png

见上图 Extension 即是整个标识了红框的区域,默认包含如下:

- Text 文字输入区域

- Voice 语音消息区域(按住说话)

- Plugin 功能插件扩展区域 (相册,位置,音视频等)

- Emoji 表情区域 (包含 EmoticonTabs 扩展区域)


自定义

Extension 目前提供了两种自定义方式 : 

1 自定义增加扩展区域功能插件 PluginModules

2.png

上图红色 TODO 红框区域即是可供开发者自定义新功能插件,目前包含可功能自定义,以及对功能插件的自定义排序。另外功能插件的展示也可根据不同的会话类型来调整。

2 自定义 EmoticonTabs 扩展区域

3.png

此处可供开发者自定义扩展

SDK 提供的表情扩展如下图

4.png

5.png

6.png


用法

RongExtension

输入区域扩展栏接口类为 RongExtension。


1. 目前 IMKit 中已经在布局文件中 rc_fr_conversation.xml 默认添加了 RongExtension 模块。

2. 开发者只需要继承 ConversationFragment, 在 onCreateView 通过 view.findViewById()  找到 RongExtension 模块即可。

3. 还可以通过 ConversationFragment 访问到 RongExtension 中各个组件被点击的事件,及内部  EditText 文本变化等方法。

7.png

RCStyle SDK提供了 5 种供开发者调整的样式(默认为 SCE):

  • SCE:语音/文本切换功能+内容输入功能+扩展功能

  • SC:语音/文本切换功能+内容输入功能

  • EC:扩展功能+内容输入功能

  • CE:内容输入功能+扩展功能

  • C:内容输入功能

以上的 5 种组合开发者可在 rc_fr_conversation.xml 里 app:RCStyle="SCE" ,更改默认输入显示形式。也可动态调用 RongExtension 提供的方法代码设置。

/**
 * 设置 ExtensionBar 样式.
 *
 * @param style 目前支持 5 种样式,参照: {@link io.rong.imkit.InputBar.Style}
 */
public void setInputBarStyle(InputBar.Style style) {
    switch (style) {
        case STYLE_SWITCH_CONTAINER_EXTENSION:
            setSCE();
            break;
        case STYLE_CONTAINER:
            setC();
            break;
        case STYLE_CONTAINER_EXTENSION:
            setCE();
            break;
        case STYLE_EXTENSION_CONTAINER:
            setEC();
            break;
        case STYLE_SWITCH_CONTAINER:
            setSC();
            break;
    }
}

设置客服的输入模式:

/**
 * 设置 ExtensionBar 客服输入模式
 *
 * @param mode 输入模式, 参照: {@link CustomServiceMode}
 */
public void setExtensionBarMode(CustomServiceMode mode)

InpuBar.java 中有对 5 种组合 以及 客服 的枚举注释。

public class InputBar {
    public enum Style {
        /**
         * 录音切换-输入框-扩展
         */
        STYLE_SWITCH_CONTAINER_EXTENSION(0x123),
        /**
         * 录音切换-输入框
         */
        STYLE_SWITCH_CONTAINER(0x120),
        /**
         * 输入框-扩展
         */
        STYLE_CONTAINER_EXTENSION(0x023),
        /**
         * 扩展-输入框
         */
        STYLE_EXTENSION_CONTAINER(0x320),
        /**
         * 仅有输入框
         */
        STYLE_CONTAINER(0x020);
        int v;
        Style(int v) {
            this.v = v;
        }
        public static Style getStyle(int v) {
            Style result = null;
            for (Style style : values()) {
                if (style.v == v) {
                    result = style;
                    break;
                }
            }
            return result;
        }
    }
    public enum Type {
        /**
         * 默认输入模式
         */
        TYPE_DEFAULT,
        /**
         * 客服输入模式:仅机器人
         */
        TYPE_CS_ROBOT,
        /**
         * 客服输入模式:仅机人工
         */
        TYPE_CS_HUMAN,
        /**
         * 客服智能输入模式:机器人优先
         */
        TYPE_CS_ROBOT_FIRST,
        /**
         * 客服智能输入模式:人工优先
         */
        TYPE_CS_HUMAN_FIRST
    }
}
public class TestFragment extends ConversationFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = super.onCreateView(inflater, container, savedInstanceState);
        mRongExtension = (RongExtension) view.findViewById(R.id.input_board);
        return view;
    }
    
    ...
    /**
     * 点击 “+” 号区域, 回调中携带 ViewGroup
     *
     * @param v              “+” 号 view 实例
     * @param extensionBoard 用于展示 plugin 的 ViewGroup
     */
    @Override
    public void onPluginToggleClick(View v, ViewGroup extensionBoard) {
        super.onPluginToggleClick(v, extensionBoard);
    }
    
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        super.beforeTextChanged(s, start, count, after);
    }
    
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        super.onTextChanged(s, start, before, count);
    }
    ...
}

替换输入框背景、图片

1 rc_ext_extension_bar.xml 输入框布局文件,是整个输入框的容器,xml 内有对各部分组件的注释描述。

8.png

2 输入框的 EditText 的布局文件是 rc_ext_input_edit_text.xml , 可通过此文件替换你需要的背景。

9.png

3 语音输入的布局文件是 rc_ext_voice_input.xml

10.png


默认扩展功能插件区域 Plugins

注意:下列功能插件需要展示用户头像和昵称的均需开发者对用户信息做实现。


1 相册已经封装到了 IMKit 里面 ImagePlugin.java ,包含发送图片以及拍照发送的功能。


2 文件已经封装到 IMKit  里面 FilePlugin.java。


3 位置功能 内置了已经实现了基于高德地图的 发送当前位置 以及 位置共享 功能,如果开发者有其他厂商地图的需求,需要自定义 Plugin。如果开发者需要使用默认实现好了的地理位置的功能,只需要将 高德地图(融云官网 Android SDK 内下载) 的三个 jar 添加至 IMKlit Module Libs 目录下即可。

11.png

- DefaultLocationPlugin.java 地理位置

- RealTimeLocationPlugin.java 位置共享

- CombineLocationPlugin.java 地理位置 和 位置共享的功能聚合


4 音频、视频两个功能插件需要依赖 CallKit 、CallLib 两个 Module,Module 官网 Android SDK 提供下载。需要注意的是使用音视频功能需要在官网开发者账号中开通相关服务,开通后生效时间为 1 个自然日。 依赖配置可参考官网 SealTalk


5 红包功能需要在官网 Android sdk 中获取 RedPacket Module ,将其依赖至你的主工程下,另外红包提供接口, 进入"我的钱包" :

/**
 * 进入我的钱包页面
 * @param activity :从哪个activity的跳转
 */
JrmfClient.intentWallet(Activity activity);

目前红包功能仅支持 Private、Group 两种会话类型。

6 语音输入功能基于科大讯飞。需要从 SealTalk 中获取 Recognizer Module 


上述 7 个功能插件。代码部分已经由 SDK 完成,开发者只需添加 Jar 和 Module 就能开箱即用。

12.png


自定义

一 、DefaultExtensionModule

SDK 中默认提供了一套+号扩展插件功能区域的类,即 DefaultExtensionModule,即便你不做任何代码的编写都会自动适配这套 DefaultExtensionModule 下包含的 Plugin 以及 EmoticonTab。

二、注册 和 去重 

如果需要自定义功能插件 

RongExtensionManager.getInstance().registerExtensionModule(new SampleExtensionModule());

注册上面代码的需要在 RongIM.init 后。我们建议在 Application 的 Context 中进行注册,此时是最佳注册时机。


需要注意的是要对 DefaultExtensionModule 进行去重不然 Plugins 下的功能可能会出现重复,例如出现两套 图片、文件、音视频的 Plugin。去重示例代码如下:

13.png


三 Plugins 和 EmoticonTabs

如果仅仅只是想 自定义 Plugins 或 EmoticonTabs 其中一项,另外一项保持默认跟随 sdk 配置,开发者可自定义继承自 DefaultExtensionModule 的类。重写类中的 getPluginModules 或者 getEmoticonTabs 方法。需要被保留为默认跟随 SDK 配置项的即调用 super 其父类中的方法即可。如果 Plugins 或 EmoticonTabs 两项需要全部自定义则可直接实现 IExtensionModule。

14.png


四 自定义 Plugin 和 Plugins 排序

15.png

示例的插件模块代码需要自定义类继承 IPluginModule :

public class SamplePlugin implements IPluginModule {
    Conversation.ConversationType conversationType;
    String targetId;
    @Override
    public Drawable obtainDrawable(Context context) {
        //设置插件 Plugin 图标
        return ContextCompat.getDrawable(context, R.drawable.rc_ext_plugin_image_selector);
    }
    @Override
    public String obtainTitle(Context context) {
        //设置插件 Plugin 展示文字
        return "示例";
    }
    @Override
    public void onClick(final Fragment currentFragment, RongExtension extension) {
        //示例获取 会话类型、targetId、Context,此处可根据产品需求自定义逻辑,如:开启新的 Activity 等。
        conversationType = extension.getConversationType();
        targetId = extension.getTargetId();
        Message message = Message.obtain(targetId, conversationType, TextMessage.obtain("示例插件功能"));
        RongIM.getInstance().sendMessage(message, null, null, new IRongCallback.ISendMessageCallback() {
            @Override
            public void onAttached(Message message) {
            }
            @Override
            public void onSuccess(Message message) {
                Toast.makeText(currentFragment.getActivity(), "消息发送成功, 示例获取 Context", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onError(Message message, RongIMClient.ErrorCode errorCode) {
            }
        });
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    }
}

调用 SamplePlugin :

public class SampleExtensionModule extends DefaultExtensionModule {
    @Override
    public List<IPluginModule> getPluginModules(Conversation.ConversationType conversationType) {
//        super.getPluginModules(conversationType);  如果需要对红包进行排序可从父类中的 getPluginModules 集合中过滤取出 JrmfExtensionModule
        List<IPluginModule> pluginModuleList = new ArrayList<>();
        pluginModuleList.add(new SamplePlugin());
        return pluginModuleList;
    }
    @Override
    public List<IEmoticonTab> getEmoticonTabs() {
        return super.getEmoticonTabs();
    }
}

排序: 决定扩展插件 Plugins 的展示顺序是由你返回集合的顺序决定的。

例如:

@Override
public List<IPluginModule> getPluginModules(Conversation.ConversationType conversationType) {
//        super.getPluginModules(conversationType);  如果需要对红包进行排序可从父类中的 getPluginModules 集合中过滤取出 JrmfExtensionModule
    List<IPluginModule> pluginModuleList = new ArrayList<>();
    pluginModuleList.add(new SamplePlugin());
    pluginModuleList.add(new LocationPlugin());
    pluginModuleList.add(new ImagePlugin());
    // 此时扩展区域的展示顺序应该为 : 示例、位置、图片、红包
    return pluginModuleList;
}

16.png

 自定义 Plugins 时例子也可参考  DefaultExtensionModule 中的 getPluginModules 方法。

五、自定义 EmoticonTabs

17.png

自定义类实现 IEmoticonTab ,示例代码如下:

public class SampleTab implements IEmoticonTab {
    @Override
    public Drawable obtainTabDrawable(Context context) {
        //展示的图标
        return context.getResources().getDrawable(R.drawable.rc_tab_emoji);
    }
    @Override
    public View obtainTabPager(Context context) {
        //初始化 Tab 中的内容, 返回 View 或 View 的子类皆可。还可参考 EmojiTab 中 obtainTabPager
        TextView textView = new TextView(context);
        textView.setText("Sample EmoticonTabs ");
        return textView;
    }
    @Override
    public void onTableSelected(int position) {
    }
}

调用:

public class SampleExtensionModule extends DefaultExtensionModule {
    private EditText mEditText;
    @Override
    public List<IPluginModule> getPluginModules(Conversation.ConversationType conversationType) {
//        super.getPluginModules(conversationType);  如果需要对红包进行排序可从父类中的 getPluginModules 集合中过滤取出 JrmfExtensionModule
        List<IPluginModule> pluginModuleList = new ArrayList<>();
        pluginModuleList.add(new SamplePlugin());
        pluginModuleList.add(new LocationPlugin());
        pluginModuleList.add(new ImagePlugin());
        // 此时扩展区域的展示顺序应该为 : 示例、位置、图片、红包
        return pluginModuleList;
    }
    @Override
    public void onAttachedToExtension(RongExtension extension) {
        mEditText = extension.getInputEditText();
    }
    @Override
    public void onDetachedFromExtension() {
        mEditText = null;
    }
    @Override
    public List<IEmoticonTab> getEmoticonTabs() {
        List<IEmoticonTab> list = new ArrayList<>();
        EmojiTab emojiTab = new EmojiTab();
        list.add(emojiTab);
        list.add(new SampleTab());
        return list;
    }
}

排序方式也是按照集合中元素的顺序。


参考资料

- http://support.rongcloud.cn/kb/NTQ4

- https://github.com/sealtalk/sealtalk-android


您认为此回答对您有帮助?

共有 5 位开发者认为此问题有帮助

我对此仍有疑问!继续追问