Skip to content

Latest commit

 

History

History
547 lines (432 loc) · 17.7 KB

README.md

File metadata and controls

547 lines (432 loc) · 17.7 KB

MongoIM

支持发送文字 语音 图片 短视频 位置 红包 名片...

http://file-cdn.datafans.net/github/mongoimios/cover1.jpg


架构

http://file-cdn.datafans.net/github/mongoimios/arch1.png


### UI层风格可切换 目前已经实现微信风格 你也可以自定义风格 完全自定义风格的相关逻辑还需要开发
### 消息处理层可切换 目前已经对接上融云 支持单聊 群聊 讨论组 聊天室
其它公有IM云服务还在计划中.....
IM后端逻辑相对复杂 MongoIM消息处理和服务端还在开发中.... 远期目标是开发一套稳定的可部署在私有云的IM服务
### 多终端支持 iOS:[https://github.com/anyunzhong/MongoIM-iOS](https://github.com/anyunzhong/MongoIM-iOS)
Android:[https://github.com/anyunzhong/MongoIM-Android](https://github.com/anyunzhong/MongoIM-Android)
Server:开发中....
MongoIM-Android =============
安装 ============ ```gradle compile 'net.datafans:mongo-im:1.0.2' ```
配置Manifest =============== ```xml
<!-- 查看 Wi-Fi 状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 查看网络状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- 录音 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

<!-- 控制振动器 -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 防止设备休眠 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<!-- 高德 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />

<uses-sdk tools:overrideLibrary="com.github.hiteshsondhi88.libffmpeg" />

<br />
快速开始
===============

####初始化
```java
MongoIM im = MongoIM.sharedInstance();
im.init(this);

####设置消息处理器(消息的接收和存储 连接等)

#####1.默认消息消息处理器 目前还在完善中 需要配合MongoIM服务端项目使用 目前还在开发中

MessageHandler messageHandler = new MongoMessageHandler("发送者ID");
im.setMessageHandler(messageHandler);

#####2.融云消息处理器 具体请参考 http://rongcloud.cn 引入融云框架 需要下载或者直接复制项目中的IMKit模块

compile project(':IMKit')

在Manifest中添加

        <!--融云开始-->
        <service
            android:name="io.rong.push.PushService"
            android:process="io.rong.push" > <!-- Waring: The name of the push process can't be changed!!! -->
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />

                <action android:name="io.rong.push" />
            </intent-filter>
        </service>
        <service
            android:name="io.rong.push.CommandService"
            android:process="io.rong.push" > <!-- Waring: The name of the push process can't be changed!!! -->
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />

                <action android:name="io.rong.command" />
            </intent-filter>
        </service>

        <receiver
            android:name="io.rong.push.PushReceiver"
            android:process="io.rong.push" > <!-- Waring: The name of the push process can't be changed!!! -->
            <intent-filter>
                <action android:name="io.rong.imlib.action.push.heartbeat" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.USER_PRESENT" />
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
                <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED" />

                <data android:scheme="package" />
            </intent-filter>
        </receiver>

        <activity
            android:name="io.rong.imkit.tools.SelectPictureActivity"
            android:screenOrientation="portrait" />
        <activity
            android:name="io.rong.imkit.tools.PreviewPictureActivity"
            android:screenOrientation="portrait" />
        <activity
            android:name="io.rong.imkit.tools.RongWebviewActivity"
            android:screenOrientation="portrait" />
        <activity
            android:name="io.rong.imkit.widget.provider.TakingPicturesActivity"
            android:configChanges="orientation|keyboardHidden"
            android:screenOrientation="portrait" />

        <service
            android:name="io.rong.imlib.ipc.RongService"
            android:process=":ipc" />
        <service android:name="io.rong.imlib.ReConnectService" />

        <receiver android:name="io.rong.imlib.ConnectChangeReceiver" />
        <receiver android:name="io.rong.imlib.ipc.PushMessageReceiver" >
            <intent-filter>
                <action android:name="io.rong.push.message" />
            </intent-filter>
        </receiver>
        <receiver
            android:name="io.rong.imlib.HeartbeatReceiver"
            android:process=":ipc" />

        <meta-data
            android:name="RONG_CLOUD_APP_KEY"
            android:value="0vnjpoadnzn1z" />

        <!--融云结束-->

设置消息处理器为融云

 String token = "通过融云api获取到的token";
 MessageHandler messageHandler = new RongCloudMessageHandler(this, token);
 im.setMessageHandler(messageHandler);

####会话列表 ```java new ConversationListFragment() 然后嵌入到你需要的地方 ```
####聊天 ```java new MessageFragment() 然后嵌入到你需要的地方 ``` 同时配置Activity ```xml
            <category android:name="android.intent.category.DEFAULT" />

            <data
                android:host="im.mongo.demo" //你项目的包名
                android:pathPrefix="/conversation"
                android:scheme="mongo" />
        </intent-filter>
    </activity>

发起单聊
```java
MongoIM.sharedInstance().startPrivateConversation(context, "目标用户ID");

界面及相关逻辑 ===============

####设置用户头像 昵称等

        im.setUserInfoProvider(new UserInfoProvider() {

            @Override
            public void getUserInfo(String userId, Callback callback) {
                UserInfo userInfo;
                switch (userId) {
                    case "100010":
                        userInfo = new UserInfo(userId, "Allen", "http://file-cdn.datafans.net/avatar/1.jpeg");
                        break;
                    case "100020":
                        userInfo = new UserInfo(userId, "Yanhua", "http://file-cdn.datafans.net/avatar/2.jpg");
                        break;
                    default:
                        userInfo = new UserInfo(userId, userId, "");
                }

                //userInfo可以直接从本地获取 也可以从网络获取后 然后callback
                callback.callback(userInfo);
            }
        });

####添加表情包

        //模拟一组小黄鸡动态表情 一共32个
        List<PackageEmotionItem> items = new ArrayList<>();
        for (int i = 1; i <= 32; i++) {
            PackageEmotionItem item = new PackageEmotionItem();
            item.setName("小黄鸡" + i);
            item.setRemoteGif("http://file-cdn.datafans.net/emotion/yellow_chicken/gif/" + i + ".gif");
            item.setRemoteThumb("http://file-cdn.datafans.net/emotion/yellow_chicken/png/" + i + ".png");
            items.add(item);
        }

        String tabIconPath = "http://file-cdn.datafans.net/emotion/yellow_chicken/icon3x.png";
        PackageEmotion emotion = new PackageEmotion(tabIconPath, items);
        MongoIM.sharedInstance().addPackageEmotion(emotion);

        //模拟一组小鸟动态表情 一共16个
        List<PackageEmotionItem> items2 = new ArrayList<>();
        for (int i = 1; i <= 16; i++) {
            PackageEmotionItem item = new PackageEmotionItem();
            item.setName("小小鸟" + i);
            item.setRemoteGif("http://file-cdn.datafans.net/emotion/bird/gif/" + i + ".gif");
            item.setRemoteThumb("http://file-cdn.datafans.net/emotion/bird/png/" + i + ".png");
            items2.add(item);
        }

        String tabIconPath2 = "http://file-cdn.datafans.net/emotion/bird/icon3x.png";
        PackageEmotion emotion2 = new PackageEmotion(tabIconPath2, items2);
        MongoIM.sharedInstance().addPackageEmotion(emotion2);

####点击插件后弹出的界面

        //默认已经实现的有 照片选择 拍照 选地点 如果需要自定义弹出界面 直接通过注册的方式覆盖原有实现即可
        //其它的都需要你去实现 通过传入的plugin来发送消息 发送后退出当前controller
        //如果是自定义plugin 则直接覆盖基类onClick方法即可实现相同效果
        MongoIM.sharedInstance().registerPluginPresentController(RedBagPluginProvider.class, RedBagCreateController.class);
        MongoIM.sharedInstance().registerPluginPresentController(NameCardPluginProvider.class, NameCardChooseController.class);
        MongoIM.sharedInstance().registerPluginPresentController(FavouritePluginProvider.class, FavouriteChooseController.class);

####配置需要使用的插件

im.configPluginProviders(Conversation.Type.PRIVATE, new PluginProvider[]{new PhotoAlbumPluginProvider()});

####点击消息气泡执行的动作

        MongoIM.sharedInstance().registerClickHandler(MessageContent.Type.RED_BAG, new MessageTemplateManager.ClickHandler() {
            @Override
            public void onClickMessage(Message message, Activity activity) {

                Toast toast = Toast.makeText(activity, "点击了消息", Toast.LENGTH_SHORT);
                toast.show();
            }
        });

####位置发送和显示 需要使用高德地图 将demo中的jar包放入到你的工程libs中

配置高德地图

        <!--高德地图开始-->
        <meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="高德地图key" />

        <service android:name="com.amap.api.location.APSService" />
        <!--高德地图结束-->

注册插件

        im.registerPlugin(LocationPluginProvider.class, Conversation.Type.PRIVATE);

点击地图消息后跳转

        MongoIM.sharedInstance().registerClickHandler(MessageContent.Type.LOCATION, new MessageTemplateManager.ClickHandler() {
            @Override
            public void onClickMessage(Message message, Activity activity) {

                MessageContent content = message.getContent();
                if (content instanceof LocationMessage) {
                    LocationMessage locationMessage = (LocationMessage) content;
                    Intent intent = new Intent(activity, LocationController.class);
                    intent.putExtra("lat", locationMessage.getLat());
                    intent.putExtra("lng", locationMessage.getLng());
                    activity.startActivity(intent);
                }
            }
        });

自定义扩展 ============

####自定义新的消息及显示

1.新的消息类型

如果是媒体类消息(比如图片 文字 视频等) 直接继承 MediaMessage 如果是通知类消息(比如系统提示) 直接继承 InfoNotifyMessage 当然你也可以直接继承MessageContent

@MessageContent.Tag(type = MessageContent.Type.YOUR_TYPE, action = MessageContent.Tag.PERSIST | MessageContent.Tag.COUNT)
public class YourMessage extends MediaMessage {

    private String yourField;

    @Override
    public byte[] encode() {
        return new byte[0];
    }

    @Override
    public String toJson() {
        return null;
    }

    @Override
    public void decode(byte[] bytes) {

    }
}

#####2. 消息显示 如果需要显示头像 直接继承MessageTemplate 如果不需要 直接继承BaseMessageTemplate

例如:定义一个需要显示头像类型的模版

@MessageTemplate.Tag(model = YourMessage.class)
public class YourMessageTemplate extends MessageTemplate {

    private TextView yourView;

    public YourMessageTemplate() {
        //messageContentView指消息中间部分容器
        messageContentView.addView(yourView, params);
    }


    @Override
    protected void refresh(Message message) {
        super.refresh(message);
        //更新数据
    }


    //长按消息后 需要增加自定义的弹出菜单
    @Override
    protected List<PopItem> getPopItems() {
        List<PopItem> items = new ArrayList<>();
        items.add(new PopItem("复制", new PopItem.Listener() {
            @Override
            public void onClick() {
                ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
                cmb.setPrimaryClip(ClipData.newPlainText("text", ((TextMessage) message.getContent()).getText()));
            }
        }));
        return items;
    }


}

不需要显示头像

@MessageTemplate.Tag(model = YourMessage.class)
public class YourMessageTemplate extends BaseMessageTemplate {

    private TextView yourView;

    public YourMessageTemplate() {
        //contentView指整个显示内容的区域
        contentView.addView(yourView, params);
    }


    @Override
    protected void refresh(Message message) {
        super.refresh(message);
        //将数据绑定到view上
    }
}

#####3. 注册消息实体及显示模版

MongoIM.sharedInstance().registerMessageContent(YourMessage.class);
MongoIM.sharedInstance().registerMessageTemplate(YourMessageTemplate.class);

####自定义插件

public class YourPluginProvider extends PluginProvider {


    public YourPluginProvider() {
        icon = R.mipmap.icon;
        name = "你的插件名称";
    }

}

注册插件

im.registerPlugin(YourPluginProvider.class, Conversation.Type.PRIVATE);

融云消息扩展 ============

####新增融云消息 具体可参照默认的红包 分享等消息的实现 具体细节可以参考融云官方文档

请参考RcShareMessage这个类

####注册融云消息

RongIMClient.registerMessageType(YourRongCloudMessage.class);

####对接融云消息

将融云消息转换为MongoIM消息

public class RongCloudToMongoYourMessageContentAdapter extends RongCloudToMongoMessageContentAdapter<YourRongCloudMessage> {

    @Override
    protected String getConversationSubTitle(YourRongCloudMessage content) {
        //返回消息汇总列表地方的文字
    }

    @Override
    public String getMongoMessageType() {
        return MessageContent.Type.Your_RONG_CLOUD_TYPE;
    }

    @Override
    public MessageContent getMongoMessageContent(YourRongCloudMessage message) {
        //你的转换逻辑
    }
}
@end

将MongoIM的消息转换成融云的

public class MongoToRongYourMessageContentAdapter extends MongoToRongMessageContentAdapter<YourMessage> {

    @Override
    public MessageContent getRongCloudMessageContent(YourMessage messageContent) {
        return //你的转化逻辑
    }
}

注册新增的类型

    RongCloudToMongoMessageContentAdapterManager rongManager = RongCloudToMongoMessageContentAdapterManager.sharedInstance();
    rongManager.register(YourRongCloudMessage.class, RongCloudToMongoYourMessageContentAdapter.class);
    
    
    MongoToRongCloudMessageContentAdapterManager mongoManager = MongoToRongCloudMessageContentAdapterManager.sharedInstance();
    mongoManager.register(YourMessage.class, MongoToRongYourMessageContentAdapter.class);