C#开发微信门户及应用(28)--微信“摇一摇·周边”功能的使用和接口的实现

”摇一摇周边“是微信提供的一种新的基于位置的连接方式。用户通过“摇一摇”的“周边”页卡,可以与线下商户进行互动,获得商户提供的个性化的服务。微信4月份有一个赠送摇一摇设备的活动,我们有幸获得赠送资格,取得一个摇一摇的设备用来测试这个新增的、很有潜力的功能。”摇一摇周边“是微信基于低功耗蓝牙技术的 O2O 入口级应用,与微信的其他线下连接能力一道,加速促成了微信 O2O 闭环的实现。本文主要介绍一摇设备的配置使用,以及如何在开发层面上,定义及实现微信摇一摇的功能接口。

1、IBeacon基础知识介绍

摇一摇周边是基于IBeacon来实现的。IBeacon是苹果公司开发的一种通过低功耗蓝牙技术进行一个十分精确的微定位技术。IBeacon设备通过蓝牙信号广播设备id, 手机等终端进入IBeacon设备的信号范围,可以收到该设备的id.



实现分如下四个步骤:
第一步. 服务提供者向微信后台申请服务,微信后台生成一个IBeaconId,并将其映射到服务提供者提供的服务,再将IBeaconId告诉服务提供者;
第二步. 服务提供者把第一步拿到的IBeaconId设置到IBeacon设备上,让IBeacon设备广播该IBeaconId;
第三步. 用户在该IBeacon设备的信号范围内打开微信摇一摇周边,微信App拿到该IBeaconId;
第四步. 微信通过第三步拿到的IBeaconId,向微信后台拉取相应的服务,展示在摇出来的结果上。
第五步. 用户点击摇出来结果,在微信内嵌的浏览器上,会带上用户信息跳转到服务提供者在第一步申请服务时填的url,进入应用页面
应用场景:


2、摇一摇设备的使用

摇一摇的beacon设备很小,底座可以用赠送的双面胶粘贴在墙面上,底面还可以贴一个微信的提示标签,挺有意思的效果。


同时可以下载这个beacon设备的App软件RealKit进行设置设备,设备界面管理界面如下所示。

根据官方摇一摇(https://zb.weixin.qq.com/)的配置说明,我们拥有设备后,需要配置设备响应的页面,流程如下所示。

由于是微信赠送的设备,默认情况下,微信后台已经给我们添加赠送的摇一摇设备记录了;
如果是自己购买这种摇一摇的设备,那么需要自己手工添加设备记录,并输入相关的参数即可。



添加设备后,我们需要配置摇一摇的页面,页面就是在摇动微信的时候,显示给微信用户的一个界面,页面管理界面如下所示。



最终配置完成后,我们就来试一下这个神秘的设备了,看看效果如何。这个设备的信号穿透力还是很不错,隔了10米,两堵墙摇一摇还是很快出来界面的。
这个摇一摇周边的功能,我在IPhone4S里面始终无法出现周边这个模块,在5、6plus里面倒是很正常的出现并响应处理,而IPAD则是在摇一摇后出现页面的,但是页面无法响应。

3、基于C#的微信摇一摇接口的实现

摇一摇和功能界面相呼应,提供了设备管理、页面管理、素材管理、关联关系绑定、设备及用户信息、数据统计等功能接口,如下所示。


1)设备管理
而其中设备管理部分,又分为了好几个API的处理。
1 申请设备ID2 编辑设备信息3 配置设备与门店的关联关系4 查询设备列表
申请设备ID
接口说明 申请配置设备所需的UUID、Major、Minor。申请成功后返回批次ID,可用返回的批次ID用“查询设备列表”接口拉取本次申请的设备ID。单次新增设备超过500个,需走人工审核流程,大概需要三个工作日;单次新增设备不超过500个的,当日可返回申请的设备ID。一个公众账号最多可申请99999个设备ID,如需申请的设备ID数超过最大限额,请邮件至zhoubian@tencent.com,邮件格式如下: 标题:申请提升设备ID额度 内容:1、公众账号名称及appid(wx开头的字符串,在mp平台可查看) 2、用途 3、预估需要多少设备ID。
接口调用说明

http请求方式: POST(请使用https协议)https://api.weixin.qq.com/shakearound/device/applyid?access_token=ACCESS_TOKEN
POST数据格式:json
POST数据例子:

{
   "quantity":3,    
   "apply_reason":"测试", 
   "comment":"测试专用",
   "poi_id":1234    
}

返回说明 正常时的返回JSON数据包示例:

当申请个数小于等于500时,
{
"data": {
       "apply_id": 123,
       "device_identifiers":[
            {
                "device_id":10100,  
                "uuid":"FDA50693-A4E2-4FB1-AFCF-C6EB07647825",      
                "major":10001,
                "minor":10002
            }
        ]
    },
    "errcode": 0,
    "errmsg": "success."
}
当申请个数大于500时,
{
"data": {
               "apply_id": 123,
        "audit_status": 0,  
        "audit_comment": "审核未通过"    
   },
   "errcode": 0,
   "errmsg": "success."
}

根据这些接口定义,我们可以创建一个摇一摇专用的接口类IShakeAround。

/// <summary>
/// 摇一摇周边的接口定义
/// </summary>
public interface IShakeAround
{
    #region 设备管理
    /// <summary>
    /// 申请设备ID。
    /// 接口说明 申请配置设备所需的UUID、Major、Minor。
    /// 若激活率小于50%,不能新增设备。单次新增设备超过500个,需走人工审核流程。审核通过后,可用返回的批次ID用“查询设备列表”接口拉取本次申请的设备ID。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="applyInfo">设备申请信息</param>
    ShakeDeviceApplyJson ApplyDevice(string accessToken, ShakeDeviceAddJson applyInfo);

    /// <summary>
    /// 编辑设备信息。
    /// 接口说明 编辑设备的备注信息。可用设备ID或完整的UUID、Major、Minor指定设备,二者选其一。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="info">设备信息</param>
    /// <param name="comment">设备的备注信息,不超过15个汉字或30个英文字母。</param>
    /// <returns></returns>
    CommonResult UpdateDevice(string accessToken, ShakeDeviceIdentifier info, string comment);

    /// <summary>
    /// 配置设备与门店的关联关系。接口说明 修改设备关联的门店ID、设备的备注信息。可用设备ID或完整的UUID、Major、Minor指定设备,二者选其一。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="info">设备信息</param>
    /// <param name="poi_id">待关联的门店ID</param>
    /// <returns></returns>
    CommonResult BindDevice(string accessToken, ShakeDeviceIdentifier info, int poi_id);

    /// <summary>
    /// 查询设备列表.
    /// 接口说明 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息。可指定设备ID或完整的UUID、Major、Minor查询,也可批量拉取设备信息列表。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="device_identifiers">设备列表信息</param>
    /// <returns></returns>
    ShakeDeviceSearchList SearchDevice(string accessToken, List<ShakeDeviceIdentifier> device_identifiers);

    /// <summary>
    /// 查询设备列表.
    /// 接口说明 查询已有的设备ID、UUID、Major、Minor、激活状态、备注信息、关联门店、关联页面等信息。可指定设备ID或完整的UUID、Major、Minor查询,也可批量拉取设备信息列表。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="data">分页查询条件。apply_id为批次ID,如果指定则以批次进行查询,否则以指定范围查询。</param>
    /// <returns></returns>
    ShakeDeviceSearchList SearchDevice(string accessToken, ShakeDeviceSearchPaging data);

    #endregion

接口定义好,我们增加对应的类实现即可,如下是申请设备的接口具体实现函数,其他遵循同样的规则就不再赘述。

/// <summary>
/// 申请设备ID。
/// 接口说明 申请配置设备所需的UUID、Major、Minor。
/// 若激活率小于50%,不能新增设备。单次新增设备超过500个,需走人工审核流程。审核通过后,可用返回的批次ID用“查询设备列表”接口拉取本次申请的设备ID。
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="applyInfo">设备申请信息</param>
public ShakeDeviceApplyJson ApplyDevice(string accessToken, ShakeDeviceAddJson applyInfo)
{
    var url = string.Format("https://api.weixin.qq.com/shakearound/device/applyid?access_token={0}", accessToken);
    string postData = applyInfo.ToJson();

    ShakeDeviceApplyJson data = null;
    ShakeDeviceApplyResult result = JsonHelper<ShakeDeviceApplyResult>.ConvertJson(url, postData);
    if (result != null)
    {
        data = result.data;
    }
    return data;
}

2)页面管理
同样页面管理也包含了几个不同的方法,用来创建、编辑、删除页面等处理操作
1 新增页面2 编辑页面信息3 查询页面列表4 删除页面
新增页面
新增摇一摇出来的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。其中,图片必须为用素材管理接口上传至微信侧服务器后返回的链接。
接口调用说明

http请求方式: POST(请使用https协议)https://api.weixin.qq.com/shakearound/page/add?access_token=ACCESS_TOKEN
POST数据格式:json
POST数据例子:

{
   "title":"主标题",   
   "description":"副标题", 
   "page_url":" https://zb.weixin.qq.com ", 
   "comment":"数据示例",
   "icon_url":"http://3gimg.qq.com/shake_nearby/dy/icon "
}

根据这些接口定义,同样我们可以为IShakeAround接口类增加对应的接口定义了。

    #region 页面管理

    /// <summary>
    /// 新增页面。
    /// 新增摇一摇出来的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
    /// 其中,图片必须为用素材管理接口上传至微信侧服务器后返回的链接。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="info">新增页面POST数据对象</param>
    /// <returns></returns>
    ShakePageResult AddPage(string accessToken, ShakePageJson info);

    /// <summary>
    /// 编辑页面信息。
    /// 编辑摇一摇出来的页面信息,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="info">编辑页面POST数据对象</param>
    /// <returns></returns>
    ShakePageResult UpdatePage(string accessToken, ShakePageJson info);
                    
    /// <summary>
    /// 查询页面列表。
    /// 查询已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
    /// 提供询方式:指定页面ID查询。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="begin">页面列表的起始索引值</param>
    /// <param name="count">待查询的页面个数</param>
    /// <returns></returns>
    ShakePageSearchJson SearchPage(string accessToken, int begin, int count);

    
    /// <summary>
    ///  查询页面列表。
    /// 查询已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
    /// 提供询方式:批量拉取页面列表
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="page_ids">指定页面的id列表</param>
    /// <returns></returns>
    ShakePageSearchJson SearchPage(string accessToken, List<int> page_ids);

    /// <summary>
    /// 查询页面列表。
    /// 查询已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
    /// 提供两种查询方式,可指定页面ID查询,也可批量拉取页面列表。
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="info"></param>
    /// <returns></returns>
    ShakePageSearchJson SearchPage(string accessToken, ShakePageSearchPaging info);

    /// <summary>
    /// 删除页面。
    /// 删除已有的页面,包括在摇一摇页面出现的主标题、副标题、图片和点击进去的超链接。
    /// 只有页面与设备没有关联关系时,才可被删除。 
    /// </summary>
    /// <param name="accessToken">调用接口凭证</param>
    /// <param name="page_ids">指定页面的id列表</param>
    /// <returns></returns>
    CommonResult DeletePage(string accessToken, List<int> page_ids);

    #endregion 页面管理

3)其他管理
当然除了上面设备、页面的管理,还有一些如
上传图片素材、配置设备与页面的关联关系、以设备为维度的数据统计接口、以页面为维度的数据统计接口等方法接口用来实现,根据上面的处理方式定义即可。
4)测试代码
增加相关的接口定义,以及完成对应的接口实现,我们就需要编写一些测试类来对我们的接口进行测试的,这些对设备、页面的测试代码如下所示。

/// <summary>
/// 摇一摇设备的申请、修改、绑定处理操作测试
/// </summary>
private void btnDevice_Click(object sender, EventArgs e)
{
    try
    {
        int poi_id = 275961135;
        ShakeDeviceApplyJson result = api.ApplyDevice(this.token, new ShakeDeviceAddJson() { quantity = 1, apply_reason = "测试", comment = "测试备注", poi_id = poi_id });
        if (result != null)
        {
            Console.WriteLine(result.ToJson());

            if (result.device_identifiers != null)
            {
                ShakeDeviceIdentifier device = result.device_identifiers[0];
                if (device != null)
                {
                    int device_id = device.device_id; //465123;
                    Console.WriteLine(device_id);

                    string comment = "修改的备注";
                    ShakeDeviceIdentifier info = new ShakeDeviceIdentifier(device.device_id, device.uuid, device.major, device.minor);
                    CommonResult comResult = api.UpdateDevice(this.token, info, comment);
                    MessageUtil.ShowTips(comResult.Success ? "操作成功" : "修改设备失败:" + comResult.ErrorMessage);

                    comResult = api.BindDevice(this.token, info, poi_id);
                    MessageUtil.ShowTips(comResult.Success ? "操作成功" : "修改设备失败:" + comResult.ErrorMessage);
                }
            }
        }
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex);
    }

}
/// <summary>
/// 增加摇一摇素材、增加页面、修改页面、删除页面的操作示例代码
/// </summary>
private void btnPage_Click(object sender, EventArgs e)
{
    string file = FileDialogHelper.OpenImage(false);
    if(string.IsNullOrEmpty(file))
    {
        return;
    }

    ShakeMaterialJson mediaJson = api.AddMaterail(this.token, file);
    if (mediaJson != null)
    {
        ShakePageJson json = new ShakePageJson()
        {
            title = "主标题",
            description = "副标题",
            comment = "备注说明",
            page_url = "https://www.iqidi.com",
            icon_url = mediaJson.pic_url
        };
        ShakePageResult result = api.AddPage(this.token, json);
        if (result != null)
        {
            Console.WriteLine(result.ToJson());
            if (result.data != null)
            {
                json.page_id = result.data.page_id;
                json.comment = "修改备注信息";

                result = api.UpdatePage(this.token, json);
                if (result != null)
                {
                    Console.WriteLine("修改页面");
                    Console.WriteLine(result.ToJson());
                }

                CommonResult comResult = api.DeletePage(this.token, new List<int>() { json.page_id.Value });
                MessageUtil.ShowTips(comResult.Success ? "删除页面操作成功" : "删除页面失败:" + comResult.ErrorMessage);
            }
        }
    }
}

个人认为,摇一摇设备,开启了一个更广阔的应用空间,随着越来越多设备商的支持,微信接口的完善和增加,可以迸发出更多有意思、实用的应用场景。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容