WEB通知和React Native之即时通讯(iOS Android)
WEB通知和React Native之即时通讯(iOS Android)
一,需求分析
1.1,允许服务器主动发送信息给客户端,客户端能监听到并且能接收。
1.2,为了方便同一个系统内的用户可以指定某个用户可以私聊。
1.3,给指定用户或多个用户发送通知。
二,技术介绍
2.1.WebSocket介绍
1,WebSocket 是什么?
2,WebSocket 的作用
- WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
- HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws
(如果加密,则为wss
),服务器网址就是 URL。
3,WebSocket 构造函数
WebSocket 对象作为一个构造函数,用于新建 WebSocket 实例。执行如下语句之后,客户端就会与服务器进行连接。
var ws = new WebSocket('ws://localhost:8080');
4,webSocket.readyState
- CONNECTING:值为0,表示正在连接。
- OPEN:值为1,表示连接成功,可以通信了。
- CLOSING:值为2,表示连接正在关闭。
- CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
5,webSocket.onopen
实例对象的onopen
属性,用于指定连接成功后的回调函数。
ws.onopen = function () {
ws.send('Hello Server!');
}
如果要指定多个回调函数,可以使用addEventListener
方法。
ws.addEventListener('open', function (event) {
ws.send('Hello Server!');
});
6,webSocket.send()
实例对象的send()
方法用于向服务器发送数据。
(1)发送文本
ws.send('your message');
(2)发送 Blob 对象
var file = document
.querySelector('input[type="file"]')
.files[0];
ws.send(file);
(3)发送 ArrayBuffer 对象
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
ws.send(binary.buffer);
(4)发送json对象
var messageObj = {fromUserId:1,message:'您好,jackson影琪',toUserId:2};
var messageJson = JSON.stringify(messageObj);
ws.send(messageJson);
7,webSocket.onmessage
对象的onmessage
属性,用于指定收到服务器数据后的回调函数。
ws.onmessage = function(event) {
var data = event.data;
// 处理数据
}; ws.addEventListener("message", function(event) {
var data = event.data;
// 处理数据
});
服务器数据可能是文本,也可能是二进制数据(blob
对象或Arraybuffer
对象)
ws.onmessage = function(event){
if(typeof event.data === String) {
console.log("Received data string");
} if(event.data instanceof ArrayBuffer){
var buffer = event.data;
console.log("Received arraybuffer");
}
}
8,webSocket.onclose
对象的onclose
属性,用于指定连接关闭后的回调函数。
ws.onclose = function(event) {
var code = event.code;
var reason = event.reason;
var wasClean = event.wasClean;
// handle close event
}; ws.addEventListener("close", function(event) {
var code = event.code;
var reason = event.reason;
var wasClean = event.wasClean;
// handle close event
});
9,webSocket.onerror
对象的onerror
属性,用于指定报错时的回调函数。
ws.onerror = function(event) {
// handle error event
}; ws.addEventListener("error", function(event) {
// handle error event
});
2.2,react-native-gifted-chat介绍
- messages(Array) - 消息数组,用于展示消息 有特定的格式
{
_id: 1, //消息的ID
text: 'My message', //发送的消息内容
createdAt: new Date(), //发送的时间
user: {/发送方的用户信息
_id: 2, //发送方的ID
name: 'Jackson', //发送方的昵称
avatar: 'https://pic.cnblogs.com/avatar/1040068/20181013100635.png',, //发送方的头像
},
image: 'https://pic.cnblogs.com/avatar/1040068/20181013100635.png',
//添加你所需要扩展的键值对
} - user(Object) - 配置用户信息
{
_id: 1, //发送消息需要和配置的id一致 avatar:'https://pic.cnblogs.com/avatar/1040068/20181013100635.png', //头像 若不设置则不显示
name:'jackson影琪', //昵称
} - renderBubble(Function) - 自定义气泡
//气泡
renderBubble(props) {
return (
<Bubble
{...props}
wrapperStyle={{
left: {//对方的气泡
backgroundColor: '#ffffff',
},
right: {//我方的气泡
backgroundColor: '#1fb922',
}
}}
/>
);
} - text(String) - 输入框的默认值;默认是undefined
- placeholder(String) - 输入框的占位字符
- messageIdGenerator(Function) - 为你的新消息自动生成一个id. 默认是用 UUID v4, 由uuid库实现uuid
- onSend(Function) - 点击send时的回调
- locale(String) -本地化日期
- timeFormat(String) - 格式化时间,默认是本地时间,即当前时区的时间
- dateFormat(String) - 日期格式化
- isAnimated(Bool) - 键盘出现时,是否有动画
- loadEarlier(Bool) - 是否显示加载更早的消息按钮 "Load earlier messages"
- onLoadEarlier(Function) - 加载更多消息时的回调
- isLoadingEarlier(Bool) - 点击加载更早的消息时是否出现转菊花的图标
- renderLoading(Function) - 加载页面未加载出来时的页面
//加载更多消息
loadEarlier={self.state.isMore}//
isLoadingEarlier={self.state.isMore}//
renderLoadEarlier={() => {
return (
<Text
onPress={self.onLoadEarlier}
style={[
styles.LookMoreStyle
]}
>{self.state.moreData}</Text>
);
}} - renderLoadEarlier(Function) - 配置 "Load earlier messages" 加载更早消息的按钮
- renderAvatar(Function) - 配置头像,如果设置'null'则头像都不显示
//头像
renderAvatar(props) {
return (
<Avatar
{...props}
/>
);
} - showUserAvatar(Bool) - 是否展示自己的头像,默认时false 只展示别人的头像
- onPressAvatar(Function(user)) - 点击头像时的回调
- renderAvatarOnTop(Bool) 头像显示在顶部还是底部,默认是底部
- renderSystemMessage(Function) - 自定义系统消息
- onLongPress(Function(context,message)) - 长按消息气泡时的回调,详细可以看github的演示 showActionSheetWithOptions()
- inverted(Bool) - 反转消息的显示顺序,默认是true 即消息显示的顺序是否和你message数组的顺序相同
- renderMessage(Function) - 自定义消息的内容View
- renderMessageText(Function) - 自定义消息的文本
- renderMessageImage(Function) - 自定义图片消息
- imageProps(Object) - 额外的属性要传递给默认创建的组件rendermessageimage点去去查看文档
- lightboxProps(Object) - 额外的属性传递给Modal框(体现在点击图片的Modal)
- 点击查看第三方 - Lightbox
- renderCustomView(Function) - 在气泡内创建一个自己自定义的视图,即创建自定义的消息
- renderDay(Function) - 自定义消息上方的日期
- renderTime(Function) - 自定义消息中的时间
- renderFooter(Function) - 自定义listView的底部, 例如.'User is typing...'; 点击查看示例 example/App.js for an example
- renderChatFooter(Function) - 自定义组件的渲染下messagecontainer(从ListView分开)
- renderInputToolbar(Function) - 自定义你的底部工具栏
- renderComposer(Function) - 自定义textInput输入框
- renderActions(Function) - 自定义输入框左边的按钮
- renderSend(Function) -自定义发送按钮;您可以很容易地将子组件传递给原始组件,例如使用自定义图标。
- renderAccessory(Function) - 在消息编辑器下面的自定义第二行操作
- onPressActionButton\(Function) - 当点击输入框左边的按钮时的回调 (如果设置了 actionSheet将不会执行)
- bottomOffset(Integer) - 从屏幕底部的聊天距离(如显示选项卡栏,则非常有用)
- minInputToolbarHeight(Integer) - 工具栏的最小高度,默认是44
- listViewProps(Object) - 列表的属性,用于扩展你的列表
listViewProps={{
// //ListView/FlatView中标识是否可以加载更多(当现在获取到的数据已经是全部了,不能再继续获取数据了,则设为false,当还有数据可以获取则设为true)
canLoad: true,
//标识现在是否ListView/FlatView现在正在加载(根据这个值来决定是否显示"正在加载的cell")(loadMore()方法进去后设为true,fetch加载完数据后设为false)
isLoadding: false,
//是否显示下拉刷新的cell
ifShowRefresh: true,
//ListView/FlatList是否可以滚动
scrollEnabled: true,
//记录当前加载到了哪一页
page: 1,
onScroll:self._onScroll.bind(this)
}} - textInputProps(Object) - 输入框的属性,用于扩展你的输入框
- keyboardShouldPersistTaps(Enum) - 确定键盘在敲击后是否应该保持可见。一个枚举; 详情见 <ScrollView>
- onInputTextChanged(Function) - 输入框编辑时的回调
- maxInputLength(Integer) - 输入框输入的最多字符数
- showAvatarForEveryMessage(Bool) - 默认是false每条消息都显示头像
系统消息格式
{
_id: 1,
text: 'This is a system message',
createdAt: new Date(),
system: true,
// Any additional custom parameters are passed through
}
三,即时通讯实现
3.1,实现步骤
第一步:建立链接
componentWillMount() {
let self = this;
//建立链接
ws = new WebSocket('ws://127.0.0.1:8080/websocket/'+str);
ws.onopen = (evt) => {
// 打开一个连接
// console.log('WebSocket==' + evt)
alert("连接成功啦")
//ws.send('something'); // 发送一个消息
};
ws.onmessage = (e) => {
// }
// 接收到了一个消息
//alert(JSON.parse(e.data).text)
console.log('e.data==' + e.data);
}; ws.onerror = (e) => {
// 发生了一个错误
console.log('e.message==' + e.message);
}; ws.onclose = (e) => {
// 连接被关闭了
console.log('e.code===' + e.code, 'e.reason===' + e.reason);
};
}
第二步:发送消息
onSend(messages = []) {
let self = this
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, messages),
}))
// alert(messages[0].text)
this.doSend(messages[0].text)
} // 发送消息
doSend = (message) => {
var messageObj = {
fromUserId: this.state.userData._id,
fromNickName: this.state.userData.name,
message: message,
toUserId: this.props.Account.id,
toNickName: this.props.Account.name,
sendTime: new Date() };
var messageJson = JSON.stringify(messageObj);
ws.send(messageJson);
}
第三步:接收消息
ws.onmessage = (e) => {
// {
// _id: 1, //消息的ID
// text: 'My message', //发送的消息内容
// createdAt: new Date(), //发送的时间
// user: {/发送方的用户信息
// _id: 2, //发送方的ID
// name: 'Jackson', //发送方的昵称
// avatar: 'https://pic.cnblogs.com/avatar/1040068/20181013100635.png',, //发送方的头像
// },
// }
// 接收到了一个消息
//alert(JSON.parse(e.data).text)
console.log('e.data==' + e.data);
}
componentWillUnmount() {
ws.close()
this.setState = (state, callback) => {
return;
};
}
3.2.聊天界面构建
1,使用react-native-gifted-chat,安装
npm install react-native-gifted-chat --save
2,引入使用
/**
* Created by Jackson on 2018/11/12.
* 聊天界面
*/
import React, { PureComponent } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Keyboard,
Platform,
StatusBar
} from 'react-native';
//聊天
import { GiftedChat, Bubble, Avatar } from 'react-native-gifted-chat'
export default class ChatBox extends PureComponent {
constructor(props) {
super(props);
this.renderBubble = this.renderBubble.bind(this);
this.renderAvatar = this.renderAvatar.bind(this);
this.state = {
//聊天
messages: [],
userData: {
_id: 1,
name:'jackson影琪',
avatar: 'https://pic.cnblogs.com/avatar/1040068/20181013100635.png',
},
messageId: 1,
} }
componentDidMount() {
let self = this
/****************************聊天组件 start **************************************************/
setTimeout(function(){
self.setState({
messages: [ {
_id: 2,
text: '微信小程序开发的基本流程',
createdAt: new Date('2018-10-25T15:41:00+08:00'),
user: {
_id: 1,
name: 'jackson影琪',
avatar: 'https://pic.cnblogs.com/avatar/1040068/20181013100635.png',
},
//image: 'https://img2018.cnblogs.com/blog/1040068/201810/1040068-20181024162047704-1159291775.png',
},
{
_id: 1,
text: 'Hello jackson影琪',
createdAt: new Date('2016-06-07T10:00:00+08:00'),
user: {
_id: 2,
name: 'jackson',
avatar: 'https://img2018.cnblogs.com/blog/1040068/201811/1040068-20181101192529807-2132606645.jpg'
},
image: 'https://pic.cnblogs.com/avatar/1040068/20181013100635.png',
},
],
})
},2000)
/****************************聊天组件 end **************************************************/ } /****************************聊天 start **************************************************/
onSend(messages = []) {
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, messages),
}))
// alert(messages[0].text)
let self = this
self.state.messageId += 2
let m = {
_id: self.state.messageId,
text: '前端知识点总结(HTML)',
createdAt: new Date(),
user: {
_id: 2,
name: '',
avatar: 'https://img2018.cnblogs.com/blog/1040068/201811/1040068-20181101192529807-2132606645.jpg'
},
image: 'https://img2018.cnblogs.com/blog/1040068/201811/1040068-20181109115100292-977588541.png',
}
self.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, m),
}))
}
//气泡
renderBubble(props) {
return (
<Bubble
{...props}
wrapperStyle={{
left: {
backgroundColor: '#ffffff',
},
right: {
backgroundColor: '#1fb922',
}
}}
/>
);
}
//头像
renderAvatar(props) {
return (
<Avatar
{...props}
/>
);
}
/****************************聊天 end **************************************************/
render() {
let self = this;
return (
<TouchableOpacity
activeOpacity={1}
style={{ flex: 1,}}
onPress={() => { Keyboard.dismiss() }}
> {/* //聊天 */}
<GiftedChat
// onPressAvatar={()=>{alert('Keyboard.dismiss'); Keyboard.dismiss()}}
messages={this.state.messages}
onSend={messages => this.onSend(messages)}
renderBubble={this.renderBubble}//气泡
renderAvatar={this.renderAvatar}//头像
showUserAvatar={true}//是否显示自己的头像,默认不显示
//onLongPress={()=>{alert('onLongPress')}}//长按消息
// 输入组件
placeholder={'请输入内容'}//输入框占位符
// label={'发送'}
containerStyle={{ marginBottom: 2 }}//发送按钮
children={
<View
style={[
styles.buttonBoxBorder
]}
>
<Text
style={[
styles.buttonText,
]}
>发送</Text>
</View>
}
// textStyle={{ color: '#70b24e' }}//按钮字的颜色
timeFormat={'MM月DD日 HH:mm:ss'}//格式化日前
dateFormat={'YYYY年MM月DD日'}
// locale={'zh-cn'}
isAnimated={true}
// renderAvatarOnTop={true}
user={this.state.userData}//用户信息
/>
</TouchableOpacity>
)
} } const styles = StyleSheet.create({
buttonText: {
paddingHorizontal: 15,
paddingVertical: 5,
textAlign: 'center',
color: '#fff',
fontSize: 14
},
buttonBoxBorder: {
overflow: 'hidden',
borderRadius: 5,
borderWidth: 1,
backgroundColor: "#70b24e",
borderColor: "#70b24e",
marginRight: 12,
marginBottom: 6,
},
})
效果如下:
3.3,使用的方法
1,下拉加载更多
{/* //聊天 */}
<GiftedChat
// onPressAvatar={()=>{alert('Keyboard.dismiss'); Keyboard.dismiss()}}
messages={this.state.messages}
onSend={messages => this.onSend(messages)}//发送消息 ... //加载更多消息
loadEarlier={self.state.isMore}//
isLoadingEarlier={self.state.isMore}//
renderLoadEarlier={() => {
return (
<Text
onPress={self.onLoadEarlier}
style={[
styles.LookMoreStyle
]}
>{self.state.moreData}</Text>
);
}} listViewProps={{
// //ListView/FlatView中标识是否可以加载更多(当现在获取到的数据已经是全部了,不能再继续获取数据了,则设为false,当还有数据可以获取则设为true)
canLoad: true,
//标识现在是否ListView/FlatView现在正在加载(根据这个值来决定是否显示"正在加载的cell")(loadMore()方法进去后设为true,fetch加载完数据后设为false)
isLoadding: false,
//是否显示下拉刷新的cell
ifShowRefresh: true,
//ListView/FlatList是否可以滚动
scrollEnabled: true,
//记录当前加载到了哪一页
page: 1,
onScroll:self._onScroll.bind(this)
}}
/>
//加载更早的数据
onLoadEarlier = () => {
let self = this;
self.state.Currentpage += 1;
self.setState({
isMore: true,
moreData: '正在加载更多...'
})
self.getMessageData()
} //上拉加载//翻页
_onScroll(event) {
let self = this
let y = event.nativeEvent.contentOffset.y;
let height = event.nativeEvent.layoutMeasurement.height;
let contentHeight = event.nativeEvent.contentSize.height;
if (y + height >= contentHeight - 20 && y > 0 && this.state.contentHeight != contentHeight) {//上啦下一页
self.state.contentHeight=contentHeight
self.onLoadEarlier() }
else if (y < 0 || y == 0) {//下拉上一页ios }
}
2,在消息前后追加消息
//prepend(),在父级最前面追加一个子元素
self.setState(previousState => ({
messages: GiftedChat.prepend(previousState.messages, ReceivedMessageData),
})) //append(),在父级最后追加一个子元素
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, messages),
}))
3,完整代码
{/* //聊天 */}
<GiftedChat
// onPressAvatar={()=>{alert('Keyboard.dismiss'); Keyboard.dismiss()}}
messages={this.state.messages}
onSend={messages => this.onSend(messages)}//发送消息
renderBubble={this.renderBubble}//气泡
renderAvatar={this.renderAvatar}//头像
showUserAvatar={true}// 显示发送方的头像
showAvatarForEveryMessage={true}//每条消息都显示头像
//onLongPress={()=>{alert('onLongPress')}}
// 输入组件
placeholder={'请输入内容'}
// label={'发送'}
containerStyle={{ marginBottom: 2 }}
children={
<View
style={[
styles.buttonBoxBorder
]}
>
<Text
style={[
styles.buttonText,
]}
>发送</Text>
</View>
}//渲染发送按钮
// textStyle={{ color: '#70b24e' }}
timeFormat={'MM月DD日 HH:mm:ss'}
dateFormat={'YYYY年MM月DD日'}
// locale={'zh-cn'}
isAnimated={true}
// renderAvatarOnTop={true}
user={this.state.userData} // 系统消息样式
wrapperStyle={{ paddingLeft: 12, paddingRight: 12 }}
textStyle={{ lineHeight: 20 }}
//加载更多消息
loadEarlier={self.state.isMore}//
isLoadingEarlier={self.state.isMore}//
renderLoadEarlier={() => {
return (
<Text
onPress={self.onLoadEarlier}
style={[
styles.LookMoreStyle
]}
>{self.state.moreData}</Text>
);
}} listViewProps={{
// //ListView/FlatView中标识是否可以加载更多(当现在获取到的数据已经是全部了,不能再继续获取数据了,则设为false,当还有数据可以获取则设为true)
canLoad: true,
//标识现在是否ListView/FlatView现在正在加载(根据这个值来决定是否显示"正在加载的cell")(loadMore()方法进去后设为true,fetch加载完数据后设为false)
isLoadding: false,
//是否显示下拉刷新的cell
ifShowRefresh: true,
//ListView/FlatList是否可以滚动
scrollEnabled: true,
//记录当前加载到了哪一页
page: 1,
onScroll:self._onScroll.bind(this)
}}
/>
效果展示:
注意:
1,如下格式的图片链接不能正常显示
avatar: 'http://img3.imgtn.bdimg.com/it/u=1614455141,2952757874&fm=26&gp=0.jpg',
四,后台实现
4.1,Java spring cloud实现
Java 的 web 一般都依托于 servlet 容器。Tomcat、Jetty、Resin等。Spring 框架对 WebSocket 也提供了支持。
1.Spring 对于 WebSocket 的支持基于下面的 jar 包:
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
2.Spring 在收到 WebSocket 事件时,会自动调用事件对应的方法。
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class WebSocketService { private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketService.class);
// ... }
3.完整代码实现
... public class WebSocketService {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketService.class); public static Map<String, Session> sessionMap = new ConcurrentHashMap<String, Session>(); private HcAppchatService hcAppchatService = SpringContextHandler.getBean(HcAppchatService.class);
/**
* 建立连接后触发的回调
*/
@OnOpen
public void onOpen(@PathParam("userId") String userId, Session session) {
LOGGER.info("聊天打开onOpen:userId={}", userId);
if (sessionMap == null) {
sessionMap = new ConcurrentHashMap<String, Session>();
}
/**
* 断开连接后触发的回调
*/
@OnClose
public void OnClose(@PathParam("userId") String userId) {
LOGGER.info("聊天关闭OnClose:userId={}", userId);
sessionMap.remove(userId);
}
/**
* 收到消息时触发的回调
*/
@OnMessage
public void OnMessage(@PathParam("userId") String userId, Session session, String message) throws IOException{
LOGGER.info("发送消息:userId={}", userId);
LOGGER.info("发送消息:message={}", message);
HcAppchat hcAppchat = JSON.parseObject(message, HcAppchat.class);
sendMessageTo(hcAppchat);
//sendMessageAll(message);
}
/**
* 传输消息出错时触发的回调
*/
@OnError
public void error(Session session, Throwable t) {
LOGGER.error("socket通讯出现异常:", t.getMessage());
t.printStackTrace();
} public void sendMessageTo(HcAppchat hcAppchat) throws IOException {
Session se = sessionMap.get(String.valueOf(hcAppchat.getAcceptId()));
Date now = new Date();
hcAppchat.setCreateDate(now);
if(se != null){
WebMessage webms = new WebMessage();
hcAppchat.setStatus(1);
boolean result = hcAppchatService.insert(hcAppchat);
LOGGER.info("用户在线,直接发送消息:result={}", result);
webms.setId(hcAppchat.getId());
webms.setCreatedAt(DateUtil.dateStr(now, "yyyy-MM-dd HH:mm:ss"));
webms.setText(hcAppchat.getText());
User user = hcAppchatService.queryUserInfo(hcAppchat.getSendId());
webms.setUser(user);
LOGGER.info("发送消息给【" + user.getName() + "】, message={}", JSON.toJSONString(webms));
se.getAsyncRemote().sendText(JSON.toJSONString(webms));
}else{
hcAppchat.setStatus(0);
boolean result = hcAppchatService.insert(hcAppchat);
if(result){
LOGGER.info("接受消息用户不在线,将消息保存数据库成功!");
}else{
LOGGER.info("接受消息用户不在线,将消息保存数据库失败!");
}
}
}
se.getAsyncRemote().sendText(message);
}
}
}
4.2,nodeJS实现
常用的 Node 实现有以下三种。
下面以socket.io为例
var IO = require('socket.io');
//var dbservice = require('./services/db_mssql.js');//链接数据库
//var settingConfig = require('./config/settingConfig.js');//解析存储过程 //var dbName = settingConfig.getValueByKey("dbName"); var socketFun = function (server) {
var socketIO = IO(server);
var userSockets = {};
socketIO.on('connection', function (socket) { //已建立链接 加入
socket.on('join', function (userId) {
socket.userId = userId;
userSockets[userId] = socket;
})
//发送通知
socket.on('notification', function (json) {
if (socket.userId == undefined) {
socket.emit('notification', {
"httpCode": 500,
"message": "请登录后再发送消息",
"data": {}
});
return;
}
//var spName = "存储过程的代称";
json.createPeopleId = socket.userId;
//支持多人接收消息
var receivePeopleIds = [];
if (json.receivePeopleId!=null)
receivePeopleIds = json.receivePeopleId.split(';');
for (var i = 0; i < receivePeopleIds.length; i++) { var json = {
"receivePeopleId": receivePeopleIds[i],
"content": json.content,
"url": json.url,
"creatPeopleId": json.creatPeopleId
};
console.log('-------json---------',json);
//dbservice.operateDatabase(dbName, spName, json, function (data) {//存进数据库
//console.log(data);
//});
var otherSocket = userSockets[json.receivePeopleId]
if (otherSocket != null) {
otherSocket.emit('notification', {
"httpCode": 200,
"message": "",
"data": json
});
}
}
});
//关闭链接
socket.on('disconnect', function () {
var userId = socket.userId;
delete userSockets[userId];
});
})
} module.exports = socketFun;
web端调用实例
var socket = io('ws://127.0.0.1:3000');//链接消息系统 socket.on('connect', function () {//建立链接
socket.emit('join', userId);
console.log('1')
});
var json = {
"receivePeopleId": createId,
"content": content,
"url": TaskUrl,
"creatPeopleId": d.CreateUserId
};
socket.emit('notification', json);//发送通知
WEB通知和React Native之即时通讯(iOS Android)的更多相关文章
- React Native之微信分享(iOS Android)
React Native之微信分享(iOS Android) 在使用React Native开发项目的时候,基本都会使用到微信好友或者微信朋友圈分享功能吧,那么今天我就带大家实现以下RN微信好友以及朋 ...
- React Native 真机调试(iOS / Android)
React Native 真机调试(iOS / Android) https://reactnative.dev/docs/running-on-device https://developer.ap ...
- 30天React Native从零到IOS/Android双平台发布总结
前言 本人有近十年的技术背景,除了APP开发之外对后端.前端等都比较熟悉,近期做一个APP项目需要IOS.Android两个平台都需要,只能硬着头皮上.其实很早就想开发APP也很早就接触Android ...
- React Native之通知栏消息提示(android)
React Native之通知栏消息提示(android) 一,需求分析与概述 1.1,推送作为手机应用的基本功能,是手机应用的重要部分,如果自己实现一套推送系统费时费力,所以大部分的应用都会选择使用 ...
- 教程视频、项目源码、全部干货【微信小程序、React Native、Java、iOS、数据结构】
把我收藏多年的教学视频.项目源码分享给大家,大神就可以忽略了,很多东西都是基础性的,都是期初学习阶段收集的东西. 微信小程序(入门级,有web前端基础的人群): 链接: https://pan.bai ...
- React Native分析(index.ios.js)
定义创建组件MyComponent(index.ios.js): 'use strict' var React = require('react-native'); var { AppRegistry ...
- 【REACT NATIVE 系列教程之十二】REACT NATIVE(JS/ES)与IOS(OBJECT-C)交互通信
http://blog.csdn.net/xiaominghimi/article/details/51586492 一用到跨平台的引擎必然要有引擎与各平台原生进行交互通信的需要.那么Himi先讲解R ...
- react native报错处理com.android.build.api.transform.TransformException: com.android.builder.dexing.DexArchiveBuilderException: com.android.builder.dexing.DexArchiveBuilderException: Failed to process
背景:最近准备在使用react-native开发的app中接入友盟,来进行用户行为统计,分享,授权登录等操作. 在使用的过程中,遇到了一些错误信息,在此记录一下. 在修改android目录下的buil ...
- react native 5.54 出ios版本遇到的坑(应该是在xcode10下才会有的吧)记录。。。。。。 据说5.7已经修复了
1. config.h找不到 rm -r ~/.rncache/cd node_modules/react-native/third-party/glog-0.3.4/./configure --ho ...
随机推荐
- windows安装elasticsearch
1. 去官网 https://www.elastic.co/cn/ 下载 注意: ES对JDK版本有较高的要求,5.x及以上版本需要JDK8支持,本人此次使用2.4.6版本2. 下载后,JDK先安装, ...
- 【开源】SpringBoot&Netty实现仿微信网页版项目更新
阅读本文约“2.3分钟” 项目更新啦!V1.3.0 还记得那个聊天室的小项目吗? SpringBoot 加 Netty 实现聊天室 没错,这次已经完整进行了版本的替换,酥酥聊天室! 基于原项目的改动, ...
- 设计模式之解释器模式——Java语言描述
解释器模式提供了评估语言的语法或表达式的方式,它属于行为型模式.这种模式实现了一个表达式接口,该接口解释一个特定的上下文.这种模式被用在SQL解析.符号处理引擎等 介绍 意图 给定一个语言,定义它的文 ...
- 全球排名第一的免费开源ERP Odoo 12产品上海发布会报名开始
Odoo V12 产品上海发布会暨企业数字化转型论坛 点击进入活动报名通道 高成本的软件开发,耗时的系统安装,繁琐的操作培训… 这一系列问题都是企业数字化管理的痛点, "软件"成为 ...
- 关于测试:JUnit4课程
JUnit4课程 JUnit4快速入门 测试实践 1.导入jar(右键Build Path --> Add Libraries --> Junit --> Junit4) 2.新建测 ...
- JIRA笔记(一):安装部署JIRA
(一) 说明 说明JIRA的安装及破解. 操作系统:WIN 10 数据库:Oracle 12C R2(这个版本的jira,atlassian建议的是 12C R1,不过R2也能用,其他版本不清 ...
- GitHub和75亿美金
如果你是看到了75亿进来的,还在纳闷前面那个github的是个什么,你可以走人了?如果你进来是想看到微软两个字的,请继续. 微软以75亿美金的股票收购Github这件事情,从周六一早我爬山到香山琉璃塔 ...
- CentOS.7下安装配置FTP和SFTP服务
一: FTP Centos7中默认已经安装了sshd服务(sftp), vsftpd需要手动安装 1.安装并启动FTP服务 1.1 安装vsftpd 使用 yum 安装 vsftpd yum inst ...
- python 爬取全本免费小说网的小说
这几天朋友说想看电子书,但是只能在网上看,不能下载到本地后看,问我有啥办法?我找了好几个小说网址看了下,你只能直接在网上看,要下载txt要冲钱买会员,而且还不能在浏览器上直接复制粘贴.之后我就想到py ...
- 使用laravel-admin后台sdk报错Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID、Provisional headers are shown
报错Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID请先确定自己的资源url是否可以确实访问到(地址正确与否.访问权限是否开启等) 若n ...