美文网首页三方管理iOS 实战进阶Tools
一步一步教你用WebSocket进行消息推送(iOS版本)

一步一步教你用WebSocket进行消息推送(iOS版本)

作者: Thebloodelves | 来源:发表于2016-10-11 13:31 被阅读6462次

      写作原因:公司这个月的项目计划是优化推送;目前我们推送用的个推(不是不好,项目限制),然后服务器那边人员忙(本人菜鸡iOS程序员),所以我就自己来做咯,如果有错误的地方下面留言我们一起交流哈,要源码的记得回复留下地址哦

      大家都知道用APNS(个推那些都是基于这个的)只能推送一些不重要的消息(比如公告,推荐你买啥啥啥),但是我们项目有加圈子/发任务/会议等等非常重要的操作,这种是不能用APNS来做的,那么我们应该用什么呢?我们应该用聊天那种来推送;当然说起聊天我们技术就多了,你可以使用最裸奔的socket(https://github.com/robbiehanson/CocoaAsyncSocket)自己做协议,也可以使用封装了一下的websocket(https://github.com/facebook/SocketRocket)等等,甚至封装更深的socket.io(https://github.com/pkyeck/socket.IO-objc)等等;当然你也知道答案了,websocket最适合来做推送。我们先来看看最终效果吧,如果你觉得感兴趣,可以继续往下看:

    我们在我们的服务器上输入一个内容,点击按钮 模拟器上就会收到消息

      那么现在开始说下准备工作,1:你要会点H5,2:你要知道websocket是啥东西,3:你要有一个heroku账号(有免费的nodejs环境服务器),4:你要会点终端(包括解决神秘代码和常用命令);好的现在解释下为什么要用nodejs来做服务器,因为他天生就适合websocket;那么为什么要用heroku呢,因为我之前用新浪云,新浪云也有nodejs环境,但是要收费(土豪忽略),于是找了一个大家都拍手称快的heroku;那么我们开始做咯。

    第一步:本地先弄个简单的websocket服务器

    我们使用npm管理器来创建,首先自己在尽量没有中文路径的地方创建一个文件夹(名字就叫做hellowebsocket),然后我们用终端进入文件夹:

    进入文件夹

    创建一个基础项目:

    创建基础项目

    创建一个server.js(websocket服务器文件):

    创建服务器文件

    配置package.json文件,覆盖或者修改成这样:

    修改配置文件

    其中的scripts我们定义一个start为node server.js操作,也就是说你输入npm start相当于是执行node server.js,

    我们来安装一些工具,express(用来搭建http协议的网页,我们不是要做一个网页吗?这个网页是http协议的,我们肯定要搭建咯),ws(websocket的node封装),在命令行依次输入以下命令:1:npm install --save --save-exact express,2:npm install --save --save-exact ws bufferutil utf-8-validate,

    我们来创建一个网页,取名index.html,内容先简单点,点击按钮显示输入框的内容,还没有连接websocket服务器(server.js,以后不再注释):

    弹出文本框内容

    现在我们来编辑weboscket服务器咯,先简单点,搭建一个http协议让index.html可以本地浏览器输入localhost:3000/index.html访问,还没有创建websocket监听,等一下来:

    搭建http环境

    然后在终端中输入npm start,这时候你在浏览器中输入localhost:3000/index.html,就可以看到下面的效果了:

    HTTP搭建好了

    接下面我们修改一下index.html和server.js,让index.html连接websocket服务器,weboscket服务器收到连接后发送回调消息"device your connect!",然后index.html收到回调消息后弹窗,内容如下:

    server.js内容 index.html内容

    这时候我们终端输入npm start,浏览器中输入localhost:3000/index.html就会弹出来回调消息了:

    页面弹出连接成功的回调消息

    通过以上的几步,大家应该大致知道推送原理了把,就是通过websocket连接得到的标示符进行发送消息和接收消息

    第二步:网页输入内容点击按钮,websocket服务器响应并回调相同的内容,网页收到后弹窗

     通过第一步,大家可以暂定自己想一下这个怎么做,是这样的:我们index.html连接成功后我们通过标识符发送消息到websocket服务器,websocket服务器收到后得到内容并发送到index.html就可以了;那么同样的,我们修改一下内容:

    server.js内容 index.html内容

    同样的,执行npm start,浏览器中输入localhost:3000/index.html,然后输入框输入内容点击按钮就可以看到效果了:

    效果图

    现在我们越来越得心应手了,发现这么简单啊(好吧,下一篇我们才要开始做我们真正的目的呢,高兴啥)

    第三步:我们用iOS连接websocket服务器把发送的和收到的消息展示到表格视图

    经过以上的两步,我们终于揭开了神秘的websocket服务器面纱,我们决定要是一步一步实现iOS应用的推送,废话不对说,我们新建一个iOS工程并导入SRWebSocket库(这里没有教程,自己弄),然后写一个表格视图和数组,我们把发送消息和接收消息存到数组中用表格视图展示出来,重点代码如下:

    连接websocket服务器

    发送消息

    接收消息

    发送心跳,频率可设

    还是不要忘记了,我们执行npm start,然后我们用模拟器打开点击右上角的“+”号发送消息就能看到以下的效果了:

    效果图

    好的,离目标又近了,现在我们来点有意思的

    第四步:iOS端和index.html都连接到websocket服务器,index.html点击按钮发送输入内容到websocket服务器,web socket服务器发送消息到iOS端,iOS端收到消息并显示到表格视图

    大家应该猜到怎么做了,主要难点是遍历所有的websocket连接,依次发送消息,我们暂时去掉index.html收到消息弹窗的代码,iOS端代码不用修改,主要内容如下:

    index.html

    server.js

    然后依然,执行nam start,iOS启动模拟器,然后浏览器中输入localhost:3000/index.html,输入内容点击按钮,我们就可以看到下面的效果:

    发送消息

    模拟器收到消息

    大家发现是不是和我们的最终效果有点像呢?其实还差得远呢,我们下一篇开始好好写一下细节部分

    第五步:我们让每个连接的websocket有一个对应的标识符,以便单独的向某一个人发送消息

    细心的小伙伴发现了,我们用index.html连接websocket服务器时后面带了一个userId参数,好吧暴露了其实我们连接的时候url后面是可以加参数的,我们暂且就先用这个来和websocket连接做一个映射吧,我们这一步不使用index.html,我们用iOS端连接并带上参数userId,然后在终端打印出来userId参数的值;有人问了,userId我在iOS请求时加上,那么在websocket服务器那边怎么收到呢?这个问题问的很好,我们来做一下实验,首先我们先改造一下iOS连接的代码,如下:

    iOS连接websocket带上参数

    然后我们在websocket服务器收到连接后把socket连接打印出来,代码如下:

    websocket打印连接实例

    依然,npm start,iOS端启动,这时候终端会输出一大片东西(这就是实例咯),然后你会在中间位置看到这样的东西:

    参数位置

    没错,我们就是要取出来这个东西,然后和websocket绑定,我们先在weboscket服务器文件上建立一个字典,然后连接的地方取出userId然后dic[userId]=websocket就可以了,为了看到效果,我们就把userId打印到终端显示吧,代码如下:

    server.js内容

    老话题,npm start,然后启动iOS端,就会终端打印出来了:

    效果图

    转入正题,我们既然都知道谁的连接是哪个了,那么我们接下来要做的就是在websocket服务器中接收消息(我们用index.html发消息,充当"业务服务器");然后websocket服务器判断消息是要发给谁的,然后在字典中找到那个socket连接,调用send函数即可(当然还有其他很多的方法,可能我这个不标准),我们修改server.js为以下代码:

    给指定的userid发消息

    然后我们修改一下index.html文件,给指定的userId为10001的人发送消息,消息格式在websocket服务器中定义好了,所有我们index.html给websocet发消息时要遵从消息格式加上分隔符"^"等,代码如下:

    让web socket服务器给userId=10001的人发消息

    我们让iOS端的userId设置成10001,然后npm start,浏览器中输入localhost:3000/index.html,启动模拟器,浏览器中输入内容点击按钮,这时候会看到如下效果:

    发送消息

    iOSuserId=10001的用户收到消息

    当然了,你可以多建几个工程,设置连接不同的userId,然后 index.html也可以设置不限userId和限制多个userId发消息,你可以多测试一下效果。那么接下来的系列我们将把本地服务器部署到heroku上成为全局的,然后各地的个小伙伴都可以访问到了,你可以先自己折腾下,我先给个网址给你们https://devcenter.heroku.com/articles/node-websockets

    第六步:把websocket服务器部署到heroku服务器变为全局访问

    有的人有个好东西就想分(xuan)享(yao)(就是我),其实websocket服务器成为全局访问后,你发你女朋友这个网址(前面的index.html文件),让她在里面里输东西,点一下按钮;你就能施展"神通"知道她写的是什么,是不是很完(zhuang)美(bi)呢?那么现在就开始吧。上一步我最后留了一个网址,里面的内容是不是还是看不懂啊(反正我最开始没看懂,不然不会折腾这么几天),那么用我的方式来讲讲吧。

    首先,你要有个heroku的账号,然后安装heroku-toolbelt.pkg工具(我们假设完全终端里操作,不在heroku官网操作),地址在这里https://devcenter.heroku.com/articles/heroku-command-line,然后安装,然后终端进入我们的目录中(一直都是hellowebsocket文件夹哦),执行heroku login(输入密码时是没有回显的),然后初始化一个git工程,执行git init,创建一个heroku项目,执行heroku create hellowebsocket(后面的名字自己看着办,如果有错误回提示你的,重新想一个就是了)然后你会看到两个地址(前面的就是你的全局地址咯,现在还访问不了,慢慢来,后面的是你的git地址),这时候我们执行git remote add hellowebsocket https://git.heroku.com/hellowebsocket.git(第5个参数是你的git地址,用你自己的),

    其次,还有重要的东西,还记得我们之前安装了一些工具类吗?就是node_modules文件夹里面的东西,这些东西不用提交到git项目上去,所以我们建立一个.gitignore文件忽略掉,里面就写上node_modules就可以了;还有,我们本地服务器可以npm start执行nodejs环境,那heroku怎么去执行呢?我们应该建立一个Procfile文件,里面写上web: node server.js,这样目录里面就有这些内容了:

    hellowebsocket目录

    好了,现在可以提交了,git add .,git commit -m 'init',git push hellowebsocket master,然后等待部署吧,你会看到如下的信息表示成功部署:

    部署成功

    部署成功后heroku那边会自动启动nodejs环境服务器(相当于我们本地的npm start),然后我们在浏览器中输入上图黑色箭头的地址就会看到如下结果:

    地址可全局访问了

    第七步:实现最终效果,目标达成

    把我们的iOS端的websocket连接地址换掉,代码如下:

    iOS连接全局 websocket服务器

    然后我们启动iOS端,浏览器中输入地址hellowebsocket.herokuapp.com/index.html,文本框中输入内容,iOS端就会显示了,效果如下:

    输入推送内容

    iOS收到推送消息

    好了,这里面还有一个小问题留给你们,我们那个html文件没有发送心跳哦,你们去加上,还有就是可以设置心跳的频率,你们也可以研究研究;当然了,推送不仅仅是这样,我们的业务服务器(目前来说我们的index.html有点像)要考虑用户不在线的情况要把消息存起来同时发个APNS提醒用户,然后等用户上线后再取出消息发送出去,这部分的话我没有实现,交给你们啦;还有就是业务服务器和websocket服务器分工要明确,目前我的可能都是错误的(因为我的判断逻辑在websocket服务器,websocket服务器应该只负责发送,逻辑应该写在业务服务器),慢慢学习吧!

    相关文章

      网友评论

      • Lazyloading:请问 我现在要在手机做一个服务端 然后js做客户端进行通信 一直返回如下信息--->
        GET /socket.io/?EIO=3&transport=websocket HTTP/1.1

        Upgrade: websocket

        Connection: Upgrade

        Host: 127.0.0.1:端口号

        Origin: http:客户端ip

        Pragma: no-cache

        Cache-Control: no-cache

        Sec-WebSocket-Key: RqpneD607T5t44EZZQi9Qg==

        Sec-WebSocket-Version: 13

        Sec-WebSocket-Extensions: x-webkit-deflate-frame

        User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 12_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A404

        库用的GCDAsyncSocket 一直连接不成功 为什么呢请问
      • rick灬:大神有 demo 么 发下
        rick灬:@Thebloodelves 我订阅了5条 怎么把返回的 message 这五条加到数组里去呢 因为这个 message 一直在变
        Thebloodelves:@silence_c34b 只是一个连接、发收数据;很简单的
      • 萤火虫_629e:大神你好,我用你的方法服务器搭建成功了,能收发字符串,问题是在连接加userId时,js服务器报错 var parts = appws.upgradeReq.url.split("?")[1].split("&");
        ^
        TypeError: Cannot read property 'url' of undefined
        打印upgradeReq 也是 undefined
        萤火虫_629e:可以,得到自己想要的了,感谢!
        Dee_Das:你可以尝试打印`ws,确实是没有这个对象的,你可以在connection方法处加上一个req`参数,像这样 ``` wss.on('connection' , (ws,req)=>{ ... } ``` ,你会找到你想要的
        Thebloodelves:@萤火虫_629e 不知道,好久没搞过了,不过可以断定是少了库或者名字错误
      • l2en:楼主大神!膜拜! 目前刚接触websocket,遇到这样一个问题,自己用node搭建的一个服务,在A窗口发送一个消息(相当于本文在PC),想在B窗口接收消息,能链接服务,但是法接收到。(项目使用electron开发的桌面应用)。才接触到这个东西,请问下这是什么原因呢?期待楼主回复:grin: 谢谢!
        Thebloodelves:@l2en 不太懂了,现在在学习android知识
      • 88085c75a02a:个推有长连接及时推送及APNs通知。我们项目后台说不用个推了,前台就得配合不得不去掉个推。。。换sockect。谢谢
      • KorsJJ:iOS socket 支持直接传字符串吗???
      • LMGod:- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(nullable NSArray<NSString *> *)protocols
        我想问一下这个protocols是干什么用的
      • ShenYj:调用close方法后,关闭的回调并不一定会被调用,不知道这个楼主是否遇到,又是如何解决的?
        Thebloodelves:@ShenYj socket直连怎么会有延迟?
        ShenYj:@Thebloodelves 能否在详细指点一下呢? 我在源码基础上加了一句代码,现在算是偶尔能够调用了,但是会有个10s左右的延迟
        Thebloodelves:@ShenYj 客户端与服务器通信后才close
      • OnlyLoveYu:你好 .第一 二步中 Index.html onmessage 这个方法不执行 知道什么原因吗 ,我对H5不熟悉.
        Thebloodelves:@OnlyLoveYu 文章里面有链接的
        OnlyLoveYu:420681494@qq.com. 求demo
      • Y像梦一样自由:可以转载吗? 对我目前的项目用处比较大
      • 汾酒iOSer:能看看demo么? ios的,最近在找工作,需要学习一些websocket ,593173068@qq.com
      • 一叶菜:请问,websocket支持后台连接吗?就是app在后台,没有退出的情况下,还能收到消息吗?
        仁一:app最多保活10分钟,不知道要长时间连接有没什么好的办法
        Thebloodelves:@一叶菜 可以,你保活app就好
      • 经天纬地:一脸蒙逼.....不明觉厉.....
      • 我是Python小白:楼主的知识面覆盖的真广 Full Stack Developer :smile:
        Thebloodelves:@iOS_Reverse 安卓入门文章已经写好了哦,你可以看看
        Thebloodelves:@iOS_Reverse 谢谢,正在努力呢,到时候写篇安卓iOS对比,让你们更快入门,哈哈
      • 32fe93c44cd9:厉害了 我的哥
        Thebloodelves:@六度Crazy 谢谢,以后一起交流学习,希望多多指出不足
      • 丿丨丨:厉害了我的哥
        Thebloodelves:@丿丨丨 手打的
        丿丨丨:@Thebloodelves 一看就是复制粘贴的
        Thebloodelves:@丿丨丨 谢谢,以后一起交流学习,希望多多指出不足
      • iOS开发工程师Echo:厉害了我的哥 :eyes:
        Thebloodelves:@秋名山歌神 谢谢,以后一起交流学习,希望多多指出不足
      • Thebloodelves:第一步那里还是输入localhost:3000/index.html不是localhost/index.html哈,因为端口我们是定义的3000
      • Thebloodelves:大家可能没有注意到,我index.html连接的时候加了参数userId,你们可以先去掉,我系列三的时候会讲这个的作用

      本文标题:一步一步教你用WebSocket进行消息推送(iOS版本)

      本文链接:https://www.haomeiwen.com/subject/mlrclttx.html