├── .drone.yml
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── README.md
├── demo
├── .eslintrc.js
├── .storybook
│ ├── addons.js
│ ├── config.js
│ └── webpack.config.js
├── README.md
├── build.zip
├── config
│ ├── env.js
│ ├── jest
│ │ ├── cssTransform.js
│ │ └── fileTransform.js
│ ├── paths.js
│ ├── polyfills.js
│ ├── webpack.config.dev.js
│ ├── webpack.config.prod.js
│ └── webpackDevServer.config.js
├── fontdemo
│ ├── font
│ │ ├── demo.css
│ │ ├── demo.html
│ │ ├── demo_fontclass.html
│ │ ├── demo_symbol.html
│ │ ├── demo_unicode.html
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.js
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ └── iconfont.woff
│ ├── fontello
│ │ ├── LICENSE.txt
│ │ ├── README.txt
│ │ ├── config.json
│ │ ├── css
│ │ │ ├── animation.css
│ │ │ ├── fontello-codes.css
│ │ │ ├── fontello-embedded.css
│ │ │ ├── fontello-ie7-codes.css
│ │ │ ├── fontello-ie7.css
│ │ │ └── fontello.css
│ │ ├── demo.html
│ │ └── font
│ │ │ ├── fontello.eot
│ │ │ ├── fontello.svg
│ │ │ ├── fontello.ttf
│ │ │ ├── fontello.woff
│ │ │ └── fontello.woff2
│ └── iconfont
│ │ ├── demo.css
│ │ ├── demo_fontclass.html
│ │ ├── demo_symbol.html
│ │ ├── demo_unicode.html
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.js
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ └── iconfont.woff
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── scripts
│ ├── build.js
│ ├── start.js
│ └── test.js
├── src
│ ├── App.css
│ ├── App.js
│ ├── Routes.js
│ ├── components
│ │ ├── blacklist
│ │ │ ├── BlacklistModal.js
│ │ │ └── style
│ │ │ │ └── BlacklistModal.less
│ │ ├── chat
│ │ │ ├── Audio.js
│ │ │ ├── ChatEmoji.js
│ │ │ ├── ChatMessage.js
│ │ │ ├── ReplyMessage.js
│ │ │ └── style
│ │ │ │ ├── ChatEmoji.less
│ │ │ │ ├── ChatMessage.less
│ │ │ │ ├── ReplyMessage.less
│ │ │ │ └── index.less
│ │ ├── common
│ │ │ ├── AppliedRoute.js
│ │ │ ├── AsyncComponent.js
│ │ │ ├── AsyncComponentBak.js
│ │ │ ├── EditInput.js
│ │ │ ├── FadingRoute.js
│ │ │ ├── LoadingComponent.js
│ │ │ ├── ModalComponent.js
│ │ │ └── style
│ │ │ │ ├── ModalComponent.less
│ │ │ │ └── webrtc.less
│ │ ├── contact
│ │ │ ├── ContactHead.js
│ │ │ ├── ContactItem.js
│ │ │ ├── UserInfoModal.js
│ │ │ └── style
│ │ │ │ └── index.less
│ │ ├── friend
│ │ │ ├── AddFriendsModal.js
│ │ │ └── FriendsRequestModal.js
│ │ ├── group
│ │ │ ├── AddGroupModal.js
│ │ │ ├── GroupInfo.js
│ │ │ ├── GroupInviteModal.js
│ │ │ ├── GroupMembers.js
│ │ │ ├── GroupRequestModal.js
│ │ │ ├── JoinGroupModal.js
│ │ │ └── style
│ │ │ │ ├── AddGrouModal.less
│ │ │ │ ├── JoinGroupModal.less
│ │ │ │ └── index.less
│ │ ├── header
│ │ │ ├── HeaderOps.js
│ │ │ ├── HeaderTab.js
│ │ │ └── style
│ │ │ │ ├── HeaderOps.less
│ │ │ │ ├── HeaderTab.less
│ │ │ │ └── index.less
│ │ ├── list
│ │ │ ├── ListItem.js
│ │ │ └── style
│ │ │ │ └── index.less
│ │ ├── recorder
│ │ │ ├── index.jsx
│ │ │ ├── index.less
│ │ │ └── recordAudio.js
│ │ ├── videoCall
│ │ │ ├── AddAVMemberModal.js
│ │ │ ├── AlertModal.js
│ │ │ ├── Channel.js
│ │ │ ├── MiniModal.js
│ │ │ ├── MultiAVModal.js
│ │ │ └── PtopCallModal.js
│ │ └── videoSetting
│ │ │ └── videoSettingModal.js
│ ├── config
│ │ ├── EMedia_sdk-dev.js
│ │ ├── EMedia_x1v1_3.4.1.js
│ │ ├── Easemob-chat-3.6.3.js
│ │ ├── Easemob-chat-4.0.9.js
│ │ ├── Easemob-chat-4.1.0.js
│ │ ├── Easemob-chat-4.1.1.js
│ │ ├── Easemob-chat-4.1.2.js
│ │ ├── Easemob-chat-4.1.3.js
│ │ ├── Easemob-chat-4.1.4.js
│ │ ├── Easemob-chat-4.1.5.js
│ │ ├── Easemob-chat-4.1.7.js
│ │ ├── Easemob-chat-4.2.0.js
│ │ ├── Easemob-chat-4.2.1.js
│ │ ├── Easemob-chat-4.3.0.js
│ │ ├── Easemob-chat-4.4.0.js
│ │ ├── Easemob-chat-4.5.0.js
│ │ ├── Easemob-chat-4.5.1.js
│ │ ├── Easemob-chat-4.6.0.js
│ │ ├── Easemob-chat-4.7.0.js
│ │ ├── Easemob-chat-4.8.0.js
│ │ ├── Easemob-chat-4.8.1.js
│ │ ├── Easemob-chat.d.ts
│ │ ├── WebIM.js
│ │ ├── WebIMConfig.js
│ │ ├── config.js
│ │ ├── emoji.js
│ │ ├── i18n
│ │ │ ├── cn.js
│ │ │ ├── index.js
│ │ │ └── us.js
│ │ └── index.js
│ ├── const
│ │ └── index.js
│ ├── containers
│ │ ├── chat
│ │ │ ├── Chat.js
│ │ │ └── style
│ │ │ │ └── index.less
│ │ ├── chinamobile
│ │ │ ├── Chinamobile.js
│ │ │ └── style
│ │ │ │ └── index.less
│ │ ├── contact
│ │ │ └── Contact.js
│ │ └── loginregister
│ │ │ ├── Login.js
│ │ │ ├── Register.js
│ │ │ ├── ResetPassword.js
│ │ │ ├── Server.js
│ │ │ └── index.less
│ ├── index.js
│ ├── layout
│ │ ├── DefaultLayout.js
│ │ ├── Layout.js
│ │ ├── RightSider.js
│ │ ├── Sider.js
│ │ └── style
│ │ │ └── index.less
│ ├── logo.svg
│ ├── redux
│ │ ├── BlacklistRedux.js
│ │ ├── ChatRoomRedux.js
│ │ ├── CommonRedux.js
│ │ ├── ContactInfoScreenRedux.js
│ │ ├── ContactsScreenRedux.js
│ │ ├── CreateStore.js
│ │ ├── DemoRedux.js
│ │ ├── GroupInviteRedux.js
│ │ ├── GroupMemberRedux.js
│ │ ├── GroupRedux.js
│ │ ├── GroupRequestRedux.js
│ │ ├── IndexRedux.js
│ │ ├── LoginRedux.js
│ │ ├── MessageRedux.js
│ │ ├── RegisterRedux.js
│ │ ├── ResetPasswordRedux.js
│ │ ├── RosterRedux.js
│ │ ├── ServerRedux.js
│ │ ├── StartupRedux.js
│ │ ├── StrangerRedux.js
│ │ ├── SubscribeRedux.js
│ │ ├── VideoCallRedux.js
│ │ ├── WebIMRedux.js
│ │ └── index.js
│ ├── registerServiceWorker.js
│ ├── selectors
│ │ ├── ChatSelector.js
│ │ └── ContactSelector.js
│ ├── themes
│ │ ├── css
│ │ │ └── fontello.css
│ │ ├── faces
│ │ │ ├── ee_1.png
│ │ │ ├── ee_10.png
│ │ │ ├── ee_11.png
│ │ │ ├── ee_12.png
│ │ │ ├── ee_13.png
│ │ │ ├── ee_14.png
│ │ │ ├── ee_15.png
│ │ │ ├── ee_16.png
│ │ │ ├── ee_17.png
│ │ │ ├── ee_18.png
│ │ │ ├── ee_19.png
│ │ │ ├── ee_2.png
│ │ │ ├── ee_20.png
│ │ │ ├── ee_21.png
│ │ │ ├── ee_22.png
│ │ │ ├── ee_23.png
│ │ │ ├── ee_24.png
│ │ │ ├── ee_25.png
│ │ │ ├── ee_26.png
│ │ │ ├── ee_27.png
│ │ │ ├── ee_28.png
│ │ │ ├── ee_29.png
│ │ │ ├── ee_3.png
│ │ │ ├── ee_30.png
│ │ │ ├── ee_31.png
│ │ │ ├── ee_32.png
│ │ │ ├── ee_33.png
│ │ │ ├── ee_34.png
│ │ │ ├── ee_35.png
│ │ │ ├── ee_4.png
│ │ │ ├── ee_5.png
│ │ │ ├── ee_6.png
│ │ │ ├── ee_7.png
│ │ │ ├── ee_8.png
│ │ │ └── ee_9.png
│ │ ├── font
│ │ │ ├── iconfont.css
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.js
│ │ │ ├── iconfont.svg
│ │ │ ├── iconfont.ttf
│ │ │ └── iconfont.woff
│ │ ├── fontello
│ │ │ ├── fontello.eot
│ │ │ ├── fontello.svg
│ │ │ ├── fontello.ttf
│ │ │ ├── fontello.woff
│ │ │ └── fontello.woff2
│ │ ├── iconfont
│ │ │ ├── iconfont.css
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.svg
│ │ │ ├── iconfont.ttf
│ │ │ └── iconfont.woff
│ │ ├── img
│ │ │ ├── 1.jpg
│ │ │ ├── acceptCall@2x.png
│ │ │ ├── avatar-big@2x.png
│ │ │ ├── avatar@2x.png
│ │ │ ├── avtool.svg
│ │ │ ├── camera-close@2x.png
│ │ │ ├── camera@2x.png
│ │ │ ├── default-img.png
│ │ │ ├── hangupCall@2x.png
│ │ │ ├── invite_member@2x.png
│ │ │ ├── microphone-mute@2x.png
│ │ │ ├── microphone@2x.png
│ │ │ ├── minimodal@2x.png
│ │ │ ├── narrow@2x.png
│ │ │ ├── rtc-bg@2x.png
│ │ │ ├── talking@2x.png
│ │ │ ├── video-bg2.png
│ │ │ ├── video-bg@2x.png
│ │ │ └── video-loading@2x.png
│ │ ├── ngprogress.less
│ │ ├── theme.js
│ │ ├── theme.less
│ │ ├── webim
│ │ │ ├── iconfont.css
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.js
│ │ │ ├── iconfont.svg
│ │ │ ├── iconfont.ttf
│ │ │ └── iconfont.woff
│ │ └── webim2
│ │ │ ├── iconfont.css
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.js
│ │ │ ├── iconfont.svg
│ │ │ ├── iconfont.ttf
│ │ │ └── iconfont.woff
│ └── utils
│ │ ├── AppDB.js
│ │ ├── history.js
│ │ ├── index.js
│ │ ├── loglevel.js
│ │ └── overlay.js
├── stories
│ └── index.js
└── storybook-static
│ └── favicon.ico
├── package-lock.json
├── simpleDemo
├── cert.pem
├── demo.html
├── easmeob-im
│ ├── chatroom.js
│ ├── friend.js
│ ├── group.js
│ ├── info.js
│ ├── login.js
│ └── message.js
├── key.pem
├── readme.md
├── sdk
│ └── Easemob-chat-3.6.3.js
└── utils
│ ├── WebIMConfig.js
│ ├── initWeb.js
│ └── jquery-3.4.1.js
└── travis.sh
/.drone.yml:
--------------------------------------------------------------------------------
1 | workspace:
2 | base: /data/apps/opt
3 | path: webim-h5
4 |
5 |
6 | pipeline:
7 |
8 | restore-cache:
9 | image: drillster/drone-volume-cache
10 | restore: true
11 | mount:
12 | - node_modules
13 | - tag
14 | volumes:
15 | - /data/apps/opt/webim-h5:/cache
16 |
17 | build:
18 | image: node:7.8
19 | privileged: true
20 | commands:
21 | - cd sdk && npm link && cd ..
22 | - cd webrtc && npm link && cd ..
23 | - cd emedia && npm link && cd ..
24 | - npm link easemob-websdk
25 | - npm link easemob-webrtc
26 | - npm link easemob-emedia
27 | - cd demo && npm install
28 | - npm run build
29 | # 2.0 demo 相关编译操作在demo目录下面
30 | - cd ..
31 | - cp -rf demo/build image/docker/webim/webim
32 | - cp -rf demo/storybook-static image/docker/webim/storybook
33 | - echo 'build success'
34 | when:
35 | branch: [ dev, master ]
36 |
37 |
38 | dockerize-sandbox:
39 | image: plugins/docker
40 | environment:
41 | - DOCKER_LAUNCH_DEBUG=true
42 | debug: true
43 | repo: docker-registry-cn.easemob.com/kubernetes/im/webim
44 | #2.0会被drone截断成2
45 | tags: 20
46 | registry: docker-registry-cn.easemob.com
47 | secrets: [ docker_username, docker_password ]
48 | dockerfile: image/docker/webim/Dockerfile
49 | context: image/docker/webim/
50 | when:
51 | branch: dev
52 |
53 | deploy-sandbox:
54 | image: docker-registry-cn.easemob.com/kubernetes/im/webim-h5-deploy:latest
55 | pull: true
56 | environment:
57 | - DOCKER_LAUNCH_DEBUG=true
58 | - TAG=20
59 | secrets: [ ssh_key, jumpserver_host, jumpserver_port, sandbox_host ]
60 | debug: true
61 | volumes:
62 | - /var/run/docker.sock:/var/run/docker.sock
63 | when:
64 | branch: dev
65 |
66 | dockerize-online:
67 | image: plugins/docker
68 | environment:
69 | - DOCKER_LAUNCH_DEBUG=true
70 | debug: true
71 | repo: docker-registry-cn.easemob.com/kubernetes/im/webim
72 | tags: ${DRONE_COMMIT:0:7}
73 | registry: docker-registry-cn.easemob.com
74 | secrets: [ docker_username, docker_password ]
75 | dockerfile: image/docker/webim/Dockerfile
76 | context: image/docker/webim/
77 | when:
78 | branch: master
79 |
80 | deploy-online:
81 | image: docker-registry-cn.easemob.com/kubernetes/im/webim-h5-online:latest
82 | pull: true
83 | environment:
84 | - DOCKER_LAUNCH_DEBUG=true
85 | - TAG=${DRONE_COMMIT:0:7}
86 | secrets: [ ssh_key, jumpserver_host, jumpserver_port, online_host ]
87 | debug: true
88 | volumes:
89 | - /data/tag/webim-h5:/data/tag/webim-h5
90 | - /var/run/docker.sock:/var/run/docker.sock
91 | when:
92 | branch: master
93 |
94 | rollback-online:
95 | image: docker-registry-cn.easemob.com/kubernetes/im/webim-h5-rollback:latest
96 | pull: true
97 | environment:
98 | - DOCKER_LAUNCH_DEBUG=true
99 | secrets: [ ssh_key, jumpserver_host, jumpserver_port, online_host ]
100 | debug: true
101 | volumes:
102 | - /data/tag/webim-h5:/data/tag/webim-h5
103 | - /var/run/docker.sock:/var/run/docker.sock
104 | when:
105 | branch: rollback
106 |
107 | rebuild-cache:
108 | image: drillster/drone-volume-cache
109 | rebuild: true
110 | mount:
111 | - node_modules
112 | - tag
113 | volumes:
114 | - /data/apps/opt/webim-h5:/cache
115 |
116 | notify:
117 | image: drillster/drone-email
118 | port: 25
119 | secrets: [ plugin_host, plugin_from, plugin_username, plugin_password ]
120 | when:
121 | status: [ failure, success ]
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | /.project
4 | .idea/*
5 | *.swp
6 | demo/build/*
7 | *.map
8 | *.vscode
9 | publish/*
10 | npm-debug.log
11 | web-im
12 | web-im-*.zip
13 | image/docker/webim/webim
14 | coverage/*
15 | # demo/javascript/dist/demo-*.js
16 | # sdk/dist/websdk-*.js
17 | # sdk/dist/websdk-*.js.map
18 | # webrtc/dist/webrtc-*.js
19 | demo/remote_docker_restart.sh
20 | *.orig
21 | demo/*.sh
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "12.4"
4 | install: true
5 | script:
6 | - chmod 755 ./travis.sh
7 | - "./travis.sh"
8 | env:
9 | global:
10 | - secure: "dLoqONm8TDA1rNluFU+kAeu/xKpPevvA/N4/mL88pd8vNV2A8UnzOofjrSfruvsHFtmk28H3n81hLZddL0rH7njnd6Cp6hyGsKMGyO8W4zcrb1VWie5Dv5t+WuC/c0at8zu2ik/7z/FAC/Xr5BRmuujtphG/rz14O3wviikXRSXqhrmThqjFDjHK3EwbRtC9ZjswudfwtF41GASi6biZS7jrufu3b/YCgEMYad9/EldcbcMQnIDKZoCUum5u2qI3Mov6d0SFrhnhcsBRbijiVkh4zkdgKW/Gc25O66scw+OyXFpiJE13vKHy8Q2+ut+06V2eU5dpOcC//ijQeBBk1tUqT0trzgRcIrQfK7j9nCYCHssg2egtMJuiIXPwMNR9OmAGQTV5se+h2OSfRs5VyCgrAGi5LuDUCBjnz+I8r/AFlQGbZrBt0f8DQzDmjmHvGorKavIU+xvxkS0z4CnXyZd92KE8HCFkFB7dCytPZW7JIhBkEQIy6gBCXL4xMzhNPWc7bFbFNohHuEP1+StIvJIJDtlCUyoLG7X3GAaKDHtwx9EMiGghbdVIM9jbczFg6e/M9EOhtgb4olsr+NDTt5FpJPSP8zHWh5UI60MAuUWiwJ4Hp94AnmC+NzZ0MOcFhkcwvAwYdlSol24J4sYl3ntQL+scQRs5IoBAFHTg3UQ="
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 版本更新说明:
2 | ## v3.3.2 @2020-10-19
3 | * [IM SDK] 增加支持设置固定 deviceId
4 | * [IM SDK] 修改 getGroup 方法去掉参数
5 | * [IM SDK] 修复拉历史消息 bug
6 | * [IM SDK] 修复发送附件消息对3.3.0之前 api 的兼容问题
7 | * [IM SDK] 修复使用 uniapp 打包的 app,退到后台回来时websocket无法连接的问题
8 | * [webim demo] 增加提示注册失败原因:用户名超出64字节
9 | * [webim demo] 增加群组非管理员邀请其他用户进群没有权限提示
10 | * [webim demo] 修复部分已知bug
11 |
12 |
13 | ## v3.2.5 @2020-6-10
14 | ### Feature
15 | * [demo] 1v1视频无法互通
16 | * [demo] 使用v3.1.2 IM SDK
17 |
18 | ## v3.2.0 @2020-5-15
19 | ### Feature
20 | * [demo] 群组管理员对群成员进行禁言、拉黑等操作没有权限时增加提示
21 | * [demo] web端A给webB发起音视频会议,B接起后邀请手机端C,C没有收到邀请信息
22 | * [demo] web端发送给小程序和iOS IM SDK Demo的语音消息,时长都显示为0”
23 | * [demo] web端发送的语音,iOS端无法播放
24 | * [demo] 使用v3.1.2 SDK
25 |
26 | ## v3.1.6 @2020
27 | ### Feature
28 | * [demo] iOS客户端邀请chrome浏览器加入音视频会议,chrome浏览器收到会议邀请时未有弹窗,导致无法接受邀请 2020/3/4
29 | * [demo] 切换聊天室时还能收到上一个聊天室的通知消息 2020/3/18
30 |
31 |
32 | ## v3.1.5 @2020-2-19
33 | ### Feature
34 | * [demo] 音视频会议支持小程序
35 | * [demo] 增加共享桌面
36 | * [demo] 部分bug
37 |
38 | ## v3.0.17 @2019-12-31
39 | ### Feature
40 | * [demo] 去掉依赖多人音视频sdk emedia 只因用webrtc
41 | * [demo] 以及imsdk 去掉默认恢复deliver 只有单聊并且配置里设置为true才发送
42 | * [demo] 加发送语音
43 | * [demo] 用户注册失败加提示
44 | * [demo] 修复不能重复发送相同图片文件
45 | * [demo] 以及 emedia 修复在http下demo打不开
46 |
47 | ## v3.0.5 @2019-08-22
48 | ### Feature
49 | * [demo] 修改移除好友的回调
50 | * [demo] 修改简单demo添加黑名单/移除黑名单
51 | * [sdk] 扩展消息增加发送json对象
52 | * [sdk] 简化添加黑名单/移除黑名单API
53 | * [sdk] 修复electron下socket建立不成功
54 |
55 | ## v3.0.4 @2019-07-30
56 | ### Feature
57 | * [demo] 增加消息撤回
58 | * [demo] 简单demo增加发送视频文件实现
59 | * [sdk] 修复无法发送扩展消息bug
60 |
61 | ## v3.0.2 @2019-07-18
62 | ### Feature
63 | * [demo] 优化部分简单demo
64 | * [sdk] 下上传文件走dns
65 | * [sdk] 修复无法拉取历史消息bug
66 | * [sdk] 修复loc/cmd消息 messageId bug
67 |
68 | ## v3.0.1 @2019-07-09
69 | ### Feature
70 |
71 | * [demo] 修复简单demo未设置appkey问题
72 | * [demo] 基于3.0sdk添加好友去掉反添加好友过程
73 | * [demo] 根据需求调整项目结构
74 | * [demo] 解决起服务是打印警告问题
75 |
76 |
77 | ## v3.0.0 @2019-06-29
78 | ### Feature
79 |
80 | * [demo] 增加接受群邀请功能
81 | * [demo] 增加和调整一些群操作通知
82 | * [demo] 使用最新基于私有协议的sdk
83 | * [demo] 拆分sdk源码为单独repo
84 | * [demo] 修复部分bug
85 | * [sdk] 基于私有协议重写
86 | * [sdk] 增加拉取历史消息接口
87 | * [sdk] 增加撤回消息接口
88 | * [sdk] 增加接受群邀请接口
89 |
90 | ## v1.11.1 @2019-03-18
91 | ###Feature
92 |
93 | * [sdk] 通过设置isHttpDNS为true,从服务端获取DNS配置文件
94 | * [demo] 配置文件文件增加配置isHttpDNS
95 | * [demo] 项目初始化sdk增加isHttpDNS
96 | * [demo] 解决safari视频无图片、无声音问题
97 |
98 |
99 | ###BugFix
100 |
101 |
102 | ## v1.10.0 @2018-09-17
103 |
104 | ###Feature
105 |
106 | * [demo] 多人音视频
107 |
108 | ###BugFix
109 |
110 | * [demo] 在视频界面中,切到其他界面,视频界面不在了。但是视频还在继续 中
111 | * [demo] 火狐 邀请 chrome, 进入多人会议,都收不到视频通知
112 | * [demo] 不选择会话,收不到视频来电
113 | * [demo] 多人视频 开关视频键状态不对
114 | * [demo] chrome和firfox多人音视频会议中,chrome不显示firefox用户的视频
115 | * [demo] 多人视频,一个浏览器登录两个账号,有一个账号 ui经常收不到视频邀请
116 |
117 |
118 | ## v1.6.0 @2018-01-29
119 |
120 | ###Feature
121 |
122 | * [demo] 多人音视频
123 | * [sdk] 多人音视频
124 |
125 | ###BugFix
126 |
127 | * [demo] 无法发送表情
128 |
129 | ## v1.5.0 @2017-11-17
130 |
131 | ###Feature
132 |
133 | * [demo] 添加Rest Interface的Test case
134 | * [demo] sdk/demo 上传功能兼容ie8
135 |
136 | ###BugFix
137 |
138 | * [demo] 多设备登录异常
139 | * [demo] 新建需要审批的公有群,加入必须有审批流程
140 | * [demo] 鼠标悬浮在群禁言图标上出现提示信息“禁言”
141 | * [demo] demo.html中从cdn引入sdk
142 | * [demo] 修复无法准确统计离线消息数的bug
143 | * [demo] window.history.pushState在windows的chrome上有兼容性问题,统一改成window.location.href
144 | * [demo] window.location.href = xxxx,如果修改的是href.search参数(?a=x&b=y)时候, 如果遇到file方式打开本地index.html会直接跳转页面,造成登录一直不成功,改成修改 href.hash 参数(#a=x&b=y)
145 | * [demo] 将群管理员可操作的项目展示给管理员
146 |
147 | ## v1.4.11 @ 2017-09-22
148 |
149 | ###Feature
150 |
151 | * [demo] 响应式布局,一套Demo同时支持PC和H5,自适应不同终端屏幕尺寸
152 | * [demo] 完全基于React + Redux的单向数据流
153 | * [demo] 引入ant-design组件库,方便开发者后续开发
154 | * [demo] 专为移动端h5打造的webim 适配微信/QQ 和各种手机浏览器
155 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Demo(WebIM)介绍
2 |
3 |
4 | 更新时间:2023-04-10
5 |
6 | -----
7 | ## 新增群组Mentions 功能, 使用Antd Mentions组件
8 |
9 | 实现方案:
10 |
11 | 文本消息新增扩展字段`em_at_list`, 表示被@的用户ID,
12 |
13 | - 'ALL' 表示@所有人
14 | - ['userId', 'userId2'] 表示@指定用户
15 |
16 | ```javascript
17 | const MENTION_ALL = 'ALL';
18 | let mentionList = ['userId', 'userId1'];
19 | let isMentionALl = true
20 |
21 | let txt = {
22 | to: 'groupId',
23 | chatType: 'groupChat',
24 | msg: '@user 你好',
25 | type: 'txt',
26 | ext: {
27 | em_at_list: isMentionALl ? MENTION_ALL : atList
28 | }
29 | }
30 | ```
31 | 收到文本消息, 如扩展字段包含`em_at_list`则表示为@消息,
32 | 如果`em_at_list`包含当前用户,则进行UI更新
33 |
34 | ```javascript
35 | // onTextMessage回调中
36 | let mentionList = message?.ext?.em_at_list
37 | // 如果存在mentionList, 并且不是当前用户多端同步的消息
38 | if(mentionList && message.from !== WebIM.conn.user){
39 | // 如果是@所有人或者mentionList包含当前用户ID
40 | if(mentionList === MENTION_ALL || mentionList.includes(WebIM.conn.user)){
41 | // 则进行UI更新
42 | }
43 | }
44 | ```
45 |
46 |
47 | 更新时间:2022-07-15
48 |
49 | -----
50 |
51 | 环信即时通讯 WEB 端提供示例应用可供体验。为方便体验,建议使用你自己的 Demo 应用,具体步骤如下:
52 |
53 | 1. 在 [环信即时通讯云 IM 管理后台](https://console.easemob.com/user/login) 通过邮箱注册,可以看到默认的 Demo 应用(默认应用是全功能开通的应用);
54 |
55 | 2. 在上图页面 Demo 应用右侧点击 **查看**,选择 **开放注册**;
56 |
57 | [](https://docs-im.easemob.com/_detail/ccim/android/quickstart/3.png?id=ccim%3Aandroid%3Aquickstart%3Ademo)
58 |
59 | 3. 打开 Demo,点击 **服务器配置**;
60 |
61 |
62 | 4. 将 Demo 的 App Key 填入,点击 **保存配置**;
63 |
64 | 5. 然后点击 **注册用户** 进行体验。
65 |
66 | **注意**
67 |
68 | 注册模式分两种,开放注册和授权注册。只有开放注册时,才可以客户端注册。
69 |
70 | - 开放注册是为了测试使用,正式环境中不推荐使用该方式注册环信账号;
71 | - 授权注册的流程应该是你的应用服务器通过环信提供的 REST API 注册,之后将 token 保存到你的应用服务器或返回给客户端。
72 |
73 | ## 代码下载
74 |
75 | - 下载源代码:[github 源码地址](https://github.com/easemob/webim)
76 |
77 | 欢迎大家提交 PR 改进和修复 WebIM 中的问题。
78 |
79 | ## 运行 WebIM 工程
80 |
81 | 从[IM SDK 及 Demo 下载](https://www.easemob.com/download/im) 下载 WEB SDK 压缩包,然后解压。解压后在 `demo` 文件夹下,即为 WebIM 的工程目录。
82 |
83 | 1. 初始化安装
84 | - 在/demo下执行 `npm install`
85 |
86 | 2. 运行demo
87 | - `cd demo && npm start`
88 |
89 | http://localhost:3001
90 | - `cd demo && HTTPS=true npm start` (webrtc supports HTTPS only)
91 |
92 | https://localhost:3001
93 |
94 | ## 主要模块介绍
95 |
96 |
97 | Demo 中有几大模块
98 |
99 | - components —— 项目中定义的组件
100 | - config —— SDK 初始化配置
101 | - containers —— 容器组件,包含 contact, chat, login/regester
102 | - layout —— chat 部分的布局
103 | - selectors —— 缓存数据,优化性能
104 | - utils —— 数据库和工具方法
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/demo/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true
6 | },
7 | "extends": "react-app",
8 | "parserOptions": {
9 | "ecmaFeatures": {
10 | "experimentalObjectRestSpread": true,
11 | "jsx": true
12 | },
13 | "sourceType": "module"
14 | },
15 | "plugins": [
16 | "react"
17 | ],
18 | "rules": {
19 |
20 | 'indent': [2, 4], // 强制使用一致的缩进
21 | 'eqeqeq': [2, 'always'], // 要求使用 === 和 !==
22 | 'semi': [2, 'never'], // 要求或禁止使用分号代替 ASI
23 | 'quotes': [2, 'single'], // 强制使用一致的反勾号、双引号或单引号
24 |
25 | "array-bracket-spacing": [
26 | "error",
27 | "always"
28 | ],
29 | "object-curly-spacing": [
30 | "error",
31 | "always"
32 | ],
33 | "semi": [
34 | "error",
35 | "never"
36 | ],
37 | "template-curly-spacing": ["error", "never"],
38 | "jsx-a11y/label-has-associated-control": "off",
39 | "jsx-a11y/label-has-for": "off",
40 | "jsx-a11y/anchor-is-valid": [0],
41 | "jsx-a11y/no-static-element-interactions": [0],
42 | "jsx-a11y/click-events-have-key-events": [0],
43 | "jsx-a11y/alt-text": "off",
44 | "jsx-a11y/href-no-hash": "off"
45 | }
46 | };
47 |
--------------------------------------------------------------------------------
/demo/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
2 |
3 | import '@storybook/addon-actions/register';
4 | import '@storybook/addon-links/register';
5 |
--------------------------------------------------------------------------------
/demo/.storybook/config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
2 |
3 | import { configure } from '@storybook/react';
4 |
5 | function loadStories() {
6 | require('../stories');
7 | }
8 |
9 | configure(loadStories, module);
10 |
--------------------------------------------------------------------------------
/demo/.storybook/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path")
2 | const autoprefixer = require("autoprefixer")
3 |
4 | function resolve(dir) {
5 | return path.join(__dirname, "..", dir)
6 | }
7 |
8 | console.log(resolve("src"))
9 |
10 | module.exports = {
11 | resolve: {
12 | alias: {
13 | "@": resolve("src")
14 | }
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.woff$|\.woff2$|\.eot$|\.ttf$|\.svg$|\.png$/,
20 | loader: require.resolve("file-loader"),
21 | options: {
22 | name: "static/media/[name].[hash:8].[ext]"
23 | }
24 | },
25 | // {
26 | // test: /\.png$/,
27 | // loader: require.resolve("url-loader"),
28 | // options: {}
29 | // },
30 | {
31 | test: /\.scss$/,
32 | loaders: ["style-loader", "css-loader", "sass-loader"],
33 | include: path.resolve(__dirname, "../")
34 | },
35 | {
36 | test: /\.css$/,
37 | use: [
38 | require.resolve("style-loader"),
39 | {
40 | loader: require.resolve("css-loader"),
41 | options: {
42 | importLoaders: 1
43 | }
44 | },
45 | {
46 | loader: require.resolve("postcss-loader"),
47 | options: {
48 | // Necessary for external CSS imports to work
49 | // https://github.com/facebookincubator/create-react-app/issues/2677
50 | ident: "postcss",
51 | plugins: () => [
52 | require("postcss-flexbugs-fixes"),
53 | autoprefixer({
54 | browsers: [
55 | ">1%",
56 | "last 4 versions",
57 | "Firefox ESR",
58 | "not ie < 9" // React doesn't support IE8 anyway
59 | ],
60 | flexbox: "no-2009"
61 | })
62 | ]
63 | }
64 | }
65 | ]
66 | },
67 | // ** STOP ** Are you adding a new loader?
68 | // Remember to add the new extension(s) to the "file" loader exclusion list.
69 | {
70 | test: /\.less$/,
71 | use: [
72 | require.resolve("style-loader"),
73 | {
74 | loader: require.resolve("css-loader")
75 | // options: {
76 | // importLoaders: 1
77 | // }
78 | },
79 | {
80 | loader: require.resolve("postcss-loader"),
81 | options: {
82 | // Necessary for external CSS imports to work
83 | // https://github.com/facebookincubator/create-react-app/issues/2677
84 | ident: "postcss",
85 | plugins: () => [
86 | require("postcss-flexbugs-fixes"),
87 | autoprefixer({
88 | browsers: [
89 | ">1%",
90 | "last 4 versions",
91 | "Firefox ESR",
92 | "not ie < 9" // React doesn't support IE8 anyway
93 | ],
94 | flexbox: "no-2009"
95 | })
96 | ]
97 | }
98 | },
99 | {
100 | loader: require.resolve("less-loader"),
101 | options: {
102 | // TODO 通过theme.js定义antd组件样式,并且支持按照依赖导入 https://ant.design/docs/react/customize-theme-cn
103 | // TODO custom style by theme.js, https://ant.design/docs/react/customize-theme-cn
104 | // modifyVars: getThemeConfig()
105 | }
106 | }
107 | ]
108 | }
109 | ]
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | ## 说明
2 | WebIM 3 (webim-h5) 在2.x的基础上, 主要做了以下更新:
3 | 1. 更换新版基于私有协议重写的sdk
4 | 2. 群组增加接受邀请/拒绝加群邀请功能
5 | 3. 修复部分bug
6 | WebIM 2 (webim-h5) 在1.x的基础上, 主要做了以下更新:
7 | 1. 响应式布局, 一套Demo同时支持PC和H5,自适应不同终端屏幕尺寸
8 | 2. 完全基于React + Redux的单向数据流
9 | 3. 引入ant-design组件库,方便开发者后续开发
10 | 4. 支持所有的现代浏览器(不支持IE6-11)
11 |
12 | ## 项目结构
13 | + config 为项目配置文件夹
14 | + fontdemo 为icon demo
15 | + scripts 为项目package.json中scripts所运行脚本
16 | + src 为项目源码
17 |
18 | ## 注意
19 | + sdk 文件夹下 webimSDK为即时通讯sdk, EMedia_x1v1为单人音视频sdk, EMedia_sdk-dev为多人音视频sdk,同时EMedia_x1v1依赖webimSDK, 音视频必须用https
20 | + simpleDemo 为简单demo,提供最简单直接的api调用示例
21 | + demo 为基于react+redux写的完整功能的demo
22 | + 更多关于sdk[集成文档](http://docs-im.easemob.com/im/web/intro/start)
23 |
24 |
25 | ## 安装
26 |
27 | 1. 初始化安装
28 | - 在/demo下执行 `npm i` `npm install`
29 |
30 | 2. 运行demo
31 | - `cd demo && npm start` (requires node@>=6)
32 |
33 | http://localhost:3001
34 | - `cd demo && HTTPS=true npm start` (webrtc supports HTTPS only)
35 |
36 | https://localhost:3001
37 |
38 | 3. 发布demo
39 | `cd demo && npm run build `
40 | /demo/build 目录下的就是可以运行和部署的版本
41 |
--------------------------------------------------------------------------------
/demo/build.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easemob/easemob-demo-react/434bab461d4b401fbe73d4ad70fea8f6359d8f9e/demo/build.zip
--------------------------------------------------------------------------------
/demo/config/env.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const paths = require('./paths');
6 |
7 | // Make sure that including paths.js after env.js will read .env variables.
8 | delete require.cache[require.resolve('./paths')];
9 |
10 | const NODE_ENV = process.env.NODE_ENV;
11 | if (!NODE_ENV) {
12 | throw new Error(
13 | 'The NODE_ENV environment variable is required but was not specified.'
14 | );
15 | }
16 |
17 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
18 | var dotenvFiles = [
19 | `${paths.dotenv}.${NODE_ENV}.local`,
20 | `${paths.dotenv}.${NODE_ENV}`,
21 | // Don't include `.env.local` for `test` environment
22 | // since normally you expect tests to produce the same
23 | // results for everyone
24 | NODE_ENV !== 'test' && `${paths.dotenv}.local`,
25 | paths.dotenv,
26 | ].filter(Boolean);
27 |
28 | // Load environment variables from .env* files. Suppress warnings using silent
29 | // if this file is missing. dotenv will never modify any environment variables
30 | // that have already been set.
31 | // https://github.com/motdotla/dotenv
32 | dotenvFiles.forEach(dotenvFile => {
33 | if (fs.existsSync(dotenvFile)) {
34 | require('dotenv').config({
35 | path: dotenvFile,
36 | });
37 | }
38 | });
39 |
40 | // We support resolving modules according to `NODE_PATH`.
41 | // This lets you use absolute paths in imports inside large monorepos:
42 | // https://github.com/facebookincubator/create-react-app/issues/253.
43 | // It works similar to `NODE_PATH` in Node itself:
44 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
45 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
46 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
47 | // https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421
48 | // We also resolve them to make sure all tools using them work consistently.
49 | const appDirectory = fs.realpathSync(process.cwd());
50 | process.env.NODE_PATH = (process.env.NODE_PATH || '')
51 | .split(path.delimiter)
52 | .filter(folder => folder && !path.isAbsolute(folder))
53 | .map(folder => path.resolve(appDirectory, folder))
54 | .join(path.delimiter);
55 |
56 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
57 | // injected into the application via DefinePlugin in Webpack configuration.
58 | const REACT_APP = /^REACT_APP_/i;
59 |
60 | function getClientEnvironment(publicUrl) {
61 | const raw = Object.keys(process.env)
62 | .filter(key => REACT_APP.test(key))
63 | .reduce(
64 | (env, key) => {
65 | env[key] = process.env[key];
66 | return env;
67 | },
68 | {
69 | // Useful for determining whether we’re running in production mode.
70 | // Most importantly, it switches React into the correct mode.
71 | NODE_ENV: process.env.NODE_ENV || 'development',
72 | // Useful for resolving the correct path to static assets in `public`.
73 | // For example, .
74 | // This should only be used as an escape hatch. Normally you would put
75 | // images into the `src` and `import` them in code to get their paths.
76 | PUBLIC_URL: publicUrl,
77 | }
78 | );
79 | // Stringify all values so we can feed into Webpack DefinePlugin
80 | const stringified = {
81 | 'process.env': Object.keys(raw).reduce((env, key) => {
82 | env[key] = JSON.stringify(raw[key]);
83 | return env;
84 | }, {}),
85 | };
86 |
87 | return { raw, stringified };
88 | }
89 |
90 | module.exports = getClientEnvironment;
91 |
--------------------------------------------------------------------------------
/demo/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/demo/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/demo/config/paths.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const path = require("path")
4 | const fs = require("fs")
5 | const url = require("url")
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebookincubator/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd())
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath)
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL
13 |
14 | function ensureSlash(path, needsSlash) {
15 | const hasSlash = path.endsWith("/")
16 | if (hasSlash && !needsSlash) {
17 | return path.substr(path, path.length - 1)
18 | } else if (!hasSlash && needsSlash) {
19 | return `${path}/`
20 | } else {
21 | return path
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right
20 |
29 |