微信公众平台开发(110) 微信连Wi-Fi
微信连Wi-Fi是为商家的线下场所提供一套完整和便捷的微信连Wi-Fi的方案。商家接入微信连Wi-Fi后,顾客无需输入繁琐的Wi-Fi密码,通过微信扫二维码等方式即可快速上网。微信连Wi-Fi还帮助商家打造个性化服务,如提供微信顶部常驻入口、商家主页展示、连网后公众号下发消息等。因此,微信连Wi-Fi既可以极大的提升用户体验,又可以帮助商家提供精准的近场服务。
微信连Wi-Fi具有以下特性
在这篇微信公众平台开发教程中,我们将介绍如何实现微信连Wi-Fi的功能。
本文分为以下二个部分:
- 创建公众账号门店
- 添加微信连Wi-Fi设备
- 改造Portal型路由器设备
- 开发移动端Portal页面
使用微信连Wi-Fi需要在“添加功能插件”中添加“门店管理”和“微信连Wi-Fi”两项。
微信连Wi-Fi设备分为密码型设备和Portal型设备,本教程介绍Portal型设备。
一、创建公众账号门店
登录微信公众平台,在左侧边栏点击“门店管理“
点击右上角“新建门店”按钮,进入门店新建页面;
手工填写各类信息,完成后提交门店,然后进入审核流程,审核结果将会在5个工作日内反馈。
审核通过后,门店新建完成。
二、添加微信连Wi-Fi设备
在微信公众平台,在左侧边栏点击“微信连Wi-Fi“
在“设备管理”中点击“添加设备”按钮,
完成后提交,获得门店Wi-Fi设备改造信息,包括:appId,shop_id,ssid,secretkey。
三、改造Portal型路由器设备
以下是某路由器设备支持连接SSID: A01-S001-R04时,查看到的路由状态表,
root@OpenWrt:~# ubus call privoxy get_client {"client_array": [{"mac": "3c9157c5ccaf","ip": "192.168.4.25","last_active": "Wed Dec 16 14:29:31 2015\n","ref_cnt": 0,"ssid": "A01-S001-R04","extra_infos": {"browser_name": "safari","userAgent": "android"},"state_array": [{"name": "auth","duration": 0,"mode": 1,"created": "Wed Dec 16 12:17:24 2015\n"}]},{"mac": "0c153969563f","ip": "192.168.4.73","last_active": "Wed Dec 16 14:31:41 2015\n","ref_cnt": 1,"ssid": "A01-S001-R04"}] } root@OpenWrt:~#
该AC/AP在移动设备连接上SSID,弹出portal页后,能够临时放行用户的上网请求。
详细实现一般由Wi-Fi硬件设备商来完成。
四、开发移动端Portal页面
微信连Wi-Fi流程
顾客在手机上点选ssid后唤起portal页,点击页面上“微信连Wi-Fi”按钮进入连接前页,展示公众号logo和名称,点击“立即连网”按钮后开始连WiFi,连接成功后跳转到成功连接页,默认勾选关注商家公众号。
微信连Wi-Fi时序图
1. 用户手动选择SSID,手机浏览器弹出Portal页面
2. Portal页面初始化时,向AC/AP请求移动端和AC/AP的MAC地址
苹果手机需要开放 http://captive.apple.com/连接
3. 用户点击微信连Wi-Fi按钮,浏览器请求AC/AP临时放行
4. AC/AP临时放行移动端所有上网请求
5. 浏览器生成ticket,发向微信Server
移动设备在portal页中引用下述微信JSAPI,让原有Wi-Fi portal页具备呼起微信的能力:
<script type="text/javascript" src="https://wifi.weixin.qq.com/resources/js/wechatticket/wechatutil.js" ></script>
调用JSAPI触发呼起微信客户端:
Wechat_GotoRedirect(appId, extend, timestamp, sign, shop_id, authUrl, mac, ssid, bssid );
具体示例如下
<script type="text/javascript">var appId = "wx1b7559b818e3c33e";var secretkey = "9cf2e6e5af383b068178d313270c237a";var extend = "fangbei"; //开发者自定义参数集合var timestamp = new Date().getTime(); //时间戳(毫秒)var shop_id = "8191752"; //AP设备所在门店的IDvar authUrl = "http://www.fangbei.org/wifigw/auth.xhtml?httpCode=200"; //认证服务端URLvar mac = "3c:91:57:c2:cc:af"; //用户手机mac地址 安卓设备必需var ssid = "A01-S001-R044"; //AP设备信号名称,非必须var bssid = "00:a0:b1:4c:a1:c5"; //AP设备mac地址,非必须function callWechatBrowser(){var sign = hex_md5(appId + extend + timestamp + shop_id + authUrl + mac + ssid + bssid + secretkey);Wechat_GotoRedirect(appId, extend, timestamp, sign, shop_id, authUrl, mac, ssid, bssid);} </script>
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
appId | 是 | 商家微信公众平台账号 |
extend | 是 | extend里面可以放开发者需要的相关参数集合,最终将透传给运营商认证URL。extend参数只支持英文和数字,且长度不得超过300个字符。 |
timestamp | 是 | 时间戳使用毫秒 |
sign | 是 | 请求参数签名,具体计算方法见下方说明 |
shop_id | 是 | AP设备所在门店的ID(微信公众平台门店) |
authUrl | 是 | 认证服务端URL,微信客户端将把用户微信身份信息向此URL提交并获得认证放行 |
mac | 安卓设备必需 | 用户手机mac地址,格式冒号分隔,字符长度17个,并且字母小写,例如:00:1f:7a:ad:5c:a8 |
ssid | 否 | AP设备的信号名称 |
bssid | 否 | 无线网络设备的无线mac地址,格式冒号分隔,字符长度17个,并且字母小写,例如:00:1f:7a:ad:5c:a8 |
签名的计算方法:
sign = MD5(appId + extend + timestamp + shop_id + authUrl + mac + ssid + bssid + secretkey); #注意这里timestamp为毫秒单位的当前时间戳
获得签名后,Portal将生成如下URL并发送到微信Server
https://wifi.weixin.qq.com/operator/callWechat.xhtml?appId=wx1b7559b818e3c223&extend=fangbei×tamp=1450260747171&sign=c9847fdf18209a760891b8de653fa71c&shopId=8191751&authUrl=http%3A%2F%2Fwifi.weixin.qq.com%2Fassistant%2Fwifigw%2Fauth.xhtml%3FhttpCode%3D200&mac=3c:91:57:c5:cc:af&ssid=A01-S001-R04&bssid=00:e0:61:4c:a7:c5
6. 微信服务器返回URL Scheme
微信服务器将返回如下链接
jsonpCallback({'success':true,'data':'weixin://connectToFreeWifi/?apKey=http%3A%2F%2Fmp.weixin.qq.com%2Fmp%2Fwifi%3Fq%3D47b33c80e2910d51&ticket=ba21685ba44144dc988fa02ec8254053'})
其中的data数据解码如下
weixin://connectToFreeWifi/?apKey=http://mp.weixin.qq.com/mp/wifi?q=47b33c80e2910d51&ticket=ba21685ba44144dc988fa02ec8254053
此处为一个URL Scheme
weixin://connectToFreeWifi/
7. 调起微信连Wi-Fi前置页面
该URL Scheme将调起微信APP,并向微信服务Server核对连WiFi注册信息及获取用户微信身份,微信Server返回用户身份信息(OpenId, tid),微信打开微信连Wi-Fi前置页面
8. 连接Wi-Fi
用户点立即连接 按钮,微信自动向authUrl(JSAPI的传入参数)发起请求,提交认证所需的用户微信身份信息参数,包括extend、openId、tid。
http://www.fangbei.org/wifigw/auth.xhtml?httpCode=200&extend=fangbei&openId=oiPuduCHIBb2aHvZoqSm1t7KbXtw&tid=010002d1eb4ee298934a7d44c1ece599ed57c4c010119bb23028b8
参数说明如下
参数 | 说明 |
---|---|
extend | 为上文中调用呼起微信JSAPI时传递的extend参数,这里原样回传给商家主页 |
openId | 用户的微信openId |
tid | 为加密后的用户手机号码(仅作网监部门备案使用) |
云端Auth URL 返回AC认证结果
authUrl所对应的后台认证服务器必须能识别这些参数信息,并向微信客户端返回AC认证结果,微信客户端将根据http返回码,提示用户连网成功与否。
若http返回码为200,则认为服务认证成功,微信客户端跳转到成功连接页,并默认勾选关注公众号,用户点击“完成”按钮后,将跳转到商家主页;若认证服务器需要转移认证请求,请返回302和下一跳地址,微信客户端将向下一跳地址再发起一次请求,302跳转仅支持一次;对于非200和302,或者超过次数的302返回码,视为认证失败,此次连网失败,微信客户端跳转到连接失败页。
注意:微信客户端一次请求的等待时间为10s,请确保后台认证服务器在微信客户端向authUrl发送请求10s之内返回AC认证结果,即http返回码。超过10s未返回认证结果将视为认证失败。
9. 连接成功
当http返回码为200时,将转入微信连WiFi连接成功页
成功页面中,显示公众账号,并且默认勾选关注选项
10. 跳转商家主页
点击““完成”,再跳转到商家模版或自定义链接
11. 路由表中可以查看到放行状态如下
root@OpenWrt:~# ubus call privoxy get_client {"client_array": [{"mac": "3c9157c5ccaf","ip": "192.168.4.25","last_active": "Wed Dec 16 14:58:13 2015\n","ref_cnt": 0,"ssid": "A01-S001-R04","extra_infos": {"browser_name": "safari","userAgent": "android"},"state_array": [{"name": "auth","duration": 0,"mode": 1,"created": "Wed Dec 16 12:17:24 2015\n"}]},{"mac": "0c153969563f","ip": "192.168.4.73","last_active": "Wed Dec 16 15:08:18 2015\n","ref_cnt": 3,"ssid": "A01-S001-R04","extra_infos": {"browser_name": "safari","userAgent": "ios"},"state_array": [{"name": "auth","duration": 0,"mode": 1,"created": "Wed Dec 16 14:44:38 2015\n"}]}] } root@OpenWrt:~#
五、Portal页面代码
Portal页面代码实例
<!DOCTYPE HTML> <html> <head lang="zh-CN"><meta charset="UTF-8"><title>微信连Wi-Fi</title><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="format-detection" content="telephone=no"><script type="text/javascript">/*** 微信连Wi-Fi协议3.1供运营商portal呼起微信浏览器使用*/var loadIframe = null;var noResponse = null;var callUpTimestamp = 0;function putNoResponse(ev){clearTimeout(noResponse);}function errorJump(){var now = new Date().getTime();if((now - callUpTimestamp) > 4*1000){return;}alert('该浏览器不支持自动跳转微信请手动打开微信\n如果已跳转请忽略此提示');}myHandler = function(error) {errorJump();};function createIframe(){var iframe = document.createElement("iframe");iframe.style.cssText = "display:none;width:0px;height:0px;";document.body.appendChild(iframe);loadIframe = iframe;}//注册回调函数function jsonpCallback(result){if(result && result.success){alert('WeChat will call up : ' + result.success + ' data:' + result.data);var ua=navigator.userAgent;if (ua.indexOf("iPhone") != -1 ||ua.indexOf("iPod")!=-1||ua.indexOf("iPad") != -1) { //iPhonedocument.location = result.data;}else{if('false'=='true'){alert('[强制]该浏览器不支持自动跳转微信请手动打开微信\n如果已跳转请忽略此提示');return;}createIframe();callUpTimestamp = new Date().getTime();loadIframe.src=result.data;noResponse = setTimeout(function(){errorJump();},3000);}}else if(result && !result.success){alert(result.data);}}function Wechat_GotoRedirect(appId, extend, timestamp, sign, shopId, authUrl, mac, ssid, bssid){//将回调函数名称带到服务器端var url = "https://wifi.weixin.qq.com/operator/callWechatBrowser.xhtml?appId=" + appId+ "&extend=" + extend+ "×tamp=" + timestamp+ "&sign=" + sign;//如果sign后面的参数有值,则是新3.1发起的流程if(authUrl && shopId){url = "https://wifi.weixin.qq.com/operator/callWechat.xhtml?appId=" + appId+ "&extend=" + extend+ "×tamp=" + timestamp+ "&sign=" + sign+ "&shopId=" + shopId+ "&authUrl=" + encodeURIComponent(authUrl)+ "&mac=" + mac+ "&ssid=" + ssid+ "&bssid=" + bssid;}//通过dom操作创建script节点实现异步请求var script = document.createElement('script');script.setAttribute('src', url);document.getElementsByTagName('head')[0].appendChild(script);}</script><link rel="stylesheet" href="https://wifi.weixin.qq.com/resources/css/style-simple-follow.css"/> </head> <body class="mod-simple-follow"> <div class="mod-simple-follow-page"><div class="mod-simple-follow-page__banner"><img class="mod-simple-follow-page__banner-bg" src="https://wifi.weixin.qq.com/resources/images/background.jpg" alt=""/><div class="mod-simple-follow-page__img-shadow"></div><div class="mod-simple-follow-page__logo"><img class="mod-simple-follow-page__logo-img" src="https://wifi.weixin.qq.com/resources/images/t.weixin.logo.png" alt=""/><p class="mod-simple-follow-page__logo-name"></p><p class="mod-simple-follow-page__logo-welcome">欢迎您</p></div></div><div class="mod-simple-follow-page__attention"><p class="mod-simple-follow-page__attention-txt">欢迎使用微信连Wi-Fi</p><a class="mod-simple-follow-page__attention-btn" οnclick="callWechatBrowser()">一键打开微信连Wi-Fi2</a></div> </div> </body> <script type="text/javascript" src="md5.js"></script> <script type="text/javascript">var appId = "wx1b7559b818e3c223";var secretkey = "9cf2e6e5af387b068178d313270c737a";var extend = "www.fangbei.org"; //开发者自定义参数集合var timestamp = new Date().getTime(); //时间戳(毫秒)var shop_id = "8191751"; //AP设备所在门店的IDvar authUrl = "http://www.fangbei.org/wifigw/auth.xhtml?httpCode=200"; //认证服务端URLvar mac = "3c:91:57:c5:cc:af"; //用户手机mac地址 安卓设备必需var ssid = "A01-S001-R044"; //AP设备信号名称,非必须var bssid = "00:e0:61:4c:a7:c5"; //AP设备mac地址,非必须function callWechatBrowser(){var sign = md5(appId + extend + timestamp + shop_id + authUrl + mac + ssid + bssid + secretkey);Wechat_GotoRedirect(appId, extend, timestamp, sign, shop_id, authUrl, mac, ssid, bssid);} </script><script type="text/javascript">document.addEventListener('visibilitychange', putNoResponse, false); </script> </html>
六、其他常见问题
1. 部分安卓手机的web浏览器无法自动呼起微信客户端
6.2.5以上的Android版微信已经支持手动打开客户端后继续进行连接流程的功能,为保证此流程顺畅进行,开发者需注意以下几点:
1.保证微信客户端版本为6.2.5以上的Android版微信; 2.参考示例demo中jsapi的写法,在无法自动跳转微信客户端时弹出提示,让用户手动切换到微信; 3.在portal页面中调用微信jsapi时,需保证AP设备的bssid、ssid、和手机mac这三个参数真实有效; 4.测试过程请从切换到目标ssid动作开始(例如:原来为3G或4G网络然后手动选择目标ssid,原来为非目标ssid的wifi信号然后手动选择目标ssid,等等)。
2. IOS从portal页面跳转到微信后如何保证手机仍保持在目标ssid下?
IOS系统为了保证Wi-Fi是可用的,在用户选择完一个ssid后不会马上切换过去,而是会嗅探通过该ssid是否能触达公网上的预设服务,如果能嗅探到才真正显示连接该ssid。在弹portal的AP环境中,这点正好被用来弹出portal页面,如果在portal页面上完成了认证,则在portal右上方的提示会由“取消”变为“完成”,如果在“取消”状态下离开这个界面,那么刚刚选择的ssid将会被断开,回到上一个可用的连接,而如果在“完成”状态下离开这个界面则不会断开。
由于通过微信认证时,会由portal界面跳转到微信,所以确保portal右上角的“完成”状态是个前提。开发者需要注意以下几点:
1.确保弹出portal后,临时放行手机的所有流量; 2.临时放行手机的所有流量后,局部或整体刷新portal页面触发IOS再次进行嗅探; 3.IOS嗅探可以正常触达公网上的预设服务后“取消”变为“完成”; 4.以上动作完成后,再调用跳转微信的JSAPI,继而跳转微信完成认证连接流程。
七、设备类型说明
密码型设备 | portal型设备 | |
---|---|---|
设备类型 |
|
|
注册加入 微信连WiFi方式 |
|
有两种方式:
|
可获取的微信连WiFi能力 |
|
不同的接入方式具备的能力不同:
|
能力类型 | 微信连WiFi能力 | 能力说明 |
---|---|---|
微信方式联网能力 | 微信方式连WiFi | 接入微信帐号验证体系,用户可扫一扫或通过公众号菜单一键连接WiFi,不需输入密码或通过手机号码验证。 |
默认关注公众号 | 微信方式连WiFi过程与商家公众号关联,连WiFi后默认关注商家公众号,帮助商家零边际成本获得线下顾客粉丝 | |
商户品牌持续曝光 | 微信方式连WiFi过程中,会持续展示商户品牌信息,为品牌提供更多曝光机会 | |
联网后近场服务能力 | 微信顶部常驻入口 | 设备添加成功后、顾客到店连上WiFi,即可在微信首页顶部看到欢迎光临的商家主页入口 |
连网后自定义消息推送 | 设备添加成功后、顾客到店连上WiFi,即可收到此店公众号下发的联网成功通知消息。此消息支持文字和卡券两种格式。 | |
开放式商家主页 | 从微信顶部常驻入口点击可进入商家主页,此页面开放给商家自行定义内容、可配置商家自有网站链接。 |
微信公众平台开发(110) 微信连Wi-Fi相关推荐
- 视频教程-微信公众平台开发入门-微信开发
微信公众平台开发入门 订阅后,请点击此处观看大牛全套视频课程:课程播放页链接 价格可能因活动略有浮动 刘运强 ¥39.00 立即订阅视频课 订阅后:请点击此处观看视频课程 视频教程-微信公众平台开发入 ...
- 微信公众平台开发[2] —— 微信端分享功能
背景 初次尝试微信公众号的开发,对于学习方法的探索都是来源于网上的博客.问答,对于参差不齐的信息,自己也是有苦说不出,抽出一点时间写点文章,既是对自己的学习总结,也希望给予同是菜鸟的小白一点帮助. 今 ...
- php 微信公众平台开发之微信群发信息
这篇文章主要为大家详细介绍了php微信公众平台开发之微信群发信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 1.目的 完成在微信公众号中群发消息.这里只是完成简单的文字发送.也可以发送语音图片 ...
- 微信公众平台开发(121) 微信二维码海报
关键字:微信公众平台 二维码 海报 作者:方倍工作室 原文: http://www.cnblogs.com/txw1958/p/weixin-poster.html 本文介绍微信公众平台下二维码海报的 ...
- java获取微信用户源码_Java微信公众平台开发(十)--微信用户信息的获取
前面的文章有讲到微信的一系列开发文章,包括token获取.菜单创建等,在这一篇将讲述在微信公众平台开发中如何获取微信用户的信息,在上一篇我们有说道微信用户和微信公众账号之间的联系可以通过Openid关 ...
- 微信公众平台开发 mysql_微信公众平台开发数据库操作
一.简介 前面讲解的功能开发都是简单的调用API 完成的,没有对数据库进行操作.在接下来的高级功能开发中,需要使用到数据库,所以在这一篇中,将对MySQL 数据库的操作做一下简单的介绍,以供读者参考. ...
- java 配置微信js sdk_Java微信公众平台开发(十一)--微信JSSDK中Config配置
JSSDK曾经引爆前端以及后端的工程师,其魔性的力量毋庸置疑,在我们的技术眼里它的实现原理和根本是不能够被改变的,这篇文章就不对其js的实现做任何评价和解说了(因为我也不是很懂,哈哈),这里要说的是它 ...
- Java微信公众平台开发(十)--微信自定义菜单的创建实现
转自:http://www.cuiyongzhi.com/post/48.html 自定义菜单这个功能在我们普通的编辑模式下是可以直接在后台编辑的,但是一旦我们进入开发模式之后我们的自定义菜单就需要自 ...
- 微信公众平台开发之微信access_token如何有效长期保存
随着微信使用越来越广泛,微信公众平台开放了许多接口以提供更多个性化的服务,包括自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等,开发者在调用这些接口时,都需要传入一个相同的参数ac ...
最新文章
- 独家 | 避免神经网络过拟合的5种技术(附链接)
- Fill in blank -Thermal experiment theory and technology2018-01-06
- 【百度地图API】如何制作可拖拽的沿道路测距
- JAVA 串口编程(二)
- nodejs --inspect-brk结合Chrome开发者工具的调试
- 浅析Java内存模型
- 【Flink】Flink 清理过期 Checkpoint 目录的正确姿势
- 会议管理SaaS平台Social Tables融资1300万美元
- python 读取xlsx特定页_python 读取 Excel
- Windows10 地平线4支持PS4手柄有线连接
- Windows10C盘文件简单介绍
- 计算机论文选题背景,毕业设计选题背景意义.docx
- 带宽与码元的关系_带宽和传输速率的关系是什么?
- 排除AP无法上线原因
- unity上传头像_Unity用户自定义圆角头像
- 模拟影像射击设备在室内靶场安装过程分享
- 手机搜狐 html5,手机搜狐欲改版推全新域名及LOGO 着力Html5技术
- vscode 文件格式化
- 2021年新手做seo怎么做,几大绝招快速上排名收录
- R语言作业:样本容量与好样本概率的关系
热门文章
- iOS cocoapods的版本升级更新
- 笨笨图片批量抓取下载 V0.2 beta[C# | WinForm | 正则表达式 | HttpWebRequest | Async异步编程]...
- JAVA方式对接FIL节点钱包(也有离线)
- stm32h7内存分配_【STM32H7教程】第9章 STM32H7重要知识点数据类型,变量和堆栈...
- 用hook android 微信,【第一篇】【安卓微信】HOOK微信发消息,当HOOK遇上HOOK。
- 【ESP 保姆级教程】疯狂传感器篇 —— 案例:ESP8266 + MQ3酒精传感器 + webserver(局域网内曲线变化图)
- 自定义ListView实现任意View跑马灯效果
- 专科计算机网络技术综述,高职高专计算机系列教材:计算机网络技术
- python实现运动模糊图像_OpenCV+Python实现图像运动模糊和高斯模糊!它是编程界的PS!...
- PDF格式转换WPS格式如何实现