上回讲到,作为一个长期散播温暖,散播希望的小清新无公害WP开发者,继QQ SDK之后,又把UWP微信SDK这茬了结了,仅供学习交流。

1.安装微信SDK for UWP

微信官方此前明确说明短时间内暂不提供RT版和UWP版的微信SDK,但眼见UWP开发之势愈烈,微信分享也必然是许多应用的标配功能,那怎么办呢,自己移植成UWP版吧。拙者提供的微信SDK是基于官方silverlight版sdk反编译后重新打包封装成UWP版本的,对部分内容稍加修改,命名空间、使用方法基本与官方文档无异。

通过nuget下载并安装微信SDK,链接https://www.nuget.org/packages/WeChatSDK/

或者在控制台输入PM> Install-Package WeChatSDK

注意项目会引用依赖Google.ProtocolBuffersLite,如果安装完成之后该依赖未自动安装,建议您Unload后Reload一下项目,或者手动安装该依赖

PM> Install-Package Google.ProtocolBuffersLite

另外,本项目代码已放在github上,请高手帮忙改进https://github.com/zhxilin/WeChatSDK

2.申请微信开放平台应用Id

到微信开放平台官网https://open.weixin.qq.com/,创建应用获得AppId和AppSecret。

3.配置Package.appxmanifest文件

与QQ SDK不同,微信SDK仅使用文件关联协议进行应用间通信,为此需要对配置文件进行配置。打开Package.appxmanifest文件,在<Extensions>节点下添加windows.fileTypeAssociation的声明:

  1. <Extensions>
  2. <uap:Extension Category="windows.fileTypeAssociation">
  3. <uap:FileTypeAssociation Name="wechat">
  4. <uap:SupportedFileTypes>
  5. <uap:FileType>.[YOUR APP ID]</uap:FileType>
  6. </uap:SupportedFileTypes>
  7. </uap:FileTypeAssociation>
  8. </uap:Extension>
  9. </Extensions>

注意不要漏了appid前面的“.”

4.调用微信SDK进行分享

微信消息的基类是WXBaseMessage类,包含属性Title、Description和ThumbData,其中Title的最大长度为512B,Description最大长度为1K,ThumbData最大长度为32K,否则会引发WXException错误。根据不同场合消息又分为8种类型,均集成自WXBaseMessage类:

WXTextMessage,文本消息,Type = WXBaseMessage.TYPE_TEXT

WXImageMessage,图片消息,Type = WXBaseMessage.TYPE_IMAGE

WXMusicMessage,音乐消息,Type =  WXBaseMessage.TYPE_MUSIC

WXVideoMessage,视频消息,Type = WXBaseMessage.TYPE_VIDEO

WXWebpageMessage,网页消息,Type = WXWebpageMessage.TYPE_URL

WXFileMessage,文件消息,Type = WXWebpageMessage.TYPE_FILE

WXAppExtendMessage,App扩展消息,Type = WXWebpageMessage.TYPE_APPDATA

WXEmojiMessage,表情消息,Type = WXEmojiMessage.TYPE_EMOJI

根据常用性,这里列举文本、图片和网页三种消息的分享方法,直接列举代码说明。以下是消息分享均通过打包消息数据后,发送SendMessageToWX.Req类型的请求来呼起微信客户端。

(1)分享文本消息

  1. try
  2. {
  3. var scene = SendMessageToWX.Req.WXSceneTimeline;
  4. var message = new WXTextMessage
  5. {
  6. Title = "Sharing a text title!",
  7. Text = "This is text content",
  8. Description = "This is a text message.这是一个文本消息。",
  9. ThumbData = null
  10. };
  11. SendMessageToWX.Req req = new SendMessageToWX.Req(message, scene);
  12. IWXAPI api = WXAPIFactory.CreateWXAPI("[YOUR APP ID]");
  13. var isValid = await api.SendReq(req);
  14. }
  15. catch (WXException ex)
  16. {
  17. Debug.WriteLine(ex.Message);
  18. }

其中scene有3种类型可以选择:

  1. SendMessageToWX.Req.WXSceneChooseByUser // 用户自行选择
  2. SendMessageToWX.Req.WXSceneSession // 分享给好友
  3. SendMessageToWX.Req.WXSceneTimeline // 分享到朋友圈

其中Text属性是Text类型消息的专有属性,最大长度640K。

(2)分享图片消息

  1. try
  2. {
  3. var scene = SendMessageToWX.Req.WXSceneTimeline;
  4. var file = await Package.Current.InstalledLocation.GetFileAsync("1.png");
  5. using (var stream = await file.OpenReadAsync())
  6. {
  7. var pic = new byte[stream.Size];
  8. await stream.AsStream().ReadAsync(pic, , pic.Length);
  9. var message = new WXImageMessage
  10. {
  11. Title = "Sharing a picture!",
  12. Description = "This is a image message.这是一个图片消息",
  13. ThumbData = pic,
  14. ImageUrl = "http://tp3.sinaimg.cn/1882347990/180/5725518284/1"
  15. };
  16. SendMessageToWX.Req req = new SendMessageToWX.Req(message, scene);
  17. IWXAPI api = WXAPIFactory.CreateWXAPI("[YOUR APP ID]");
  18. var isValid = await api.SendReq(req);
  19. }
  20. }
  21. catch (WXException ex)
  22. {
  23. Debug.WriteLine(ex.Message);
  24. }

其中ImageUrl和ImageData只能设置一个,ImageData不能超过10M。

(3)分享网页消息

  1. try
  2. {
  3. var scene = SendMessageToWX.Req.WXSceneTimeline;
  4. var file = await Package.Current.InstalledLocation.GetFileAsync("1.png");
  5. using (var stream = await file.OpenReadAsync())
  6. {
  7. var pic = new byte[stream.Size];
  8. await stream.AsStream().ReadAsync(pic, , pic.Length);
  9. var message = new WXWebpageMessage
  10. {
  11. WebpageUrl = "http://www.baidu.com",
  12. Title = "Sharing a link!",
  13. Description = "This is a link message.这是一个链接消息",
  14. ThumbData = pic
  15. };
  16. SendMessageToWX.Req req = new SendMessageToWX.Req(message, scene);
  17. IWXAPI api = WXAPIFactory.CreateWXAPI("[YOUR APP ID]");
  18. var isValid = await api.SendReq(req);
  19. }
  20. }
  21. catch (WXException ex)
  22. {
  23. Debug.WriteLine(ex.Message);
  24. }

其中WebpageUrl不能超过10K。

(4)登录授权

登录授权向微信客户端发出的请求类型是SendAuth.Req

  1. try
  2. {
  3. SendAuth.Req req = new SendAuth.Req("[YOUR SCOPE]", "test");
  4. IWXAPI api = WXAPIFactory.CreateWXAPI("[YOUR APP ID]");
  5. var isValid = await api.SendReq(req);
  6. }
  7. catch (WXException ex)
  8. {
  9. Debug.WriteLine(ex.Message);
  10. }

其中[YOUR SCOPE]指的是在开放平台注册应用,开通登录授权后的权限范围。

(5)微信支付

SDK也提供了微信支付的请求类型SendPay.Req,由于支付权限申请比较困难,暂时没有测试,以后有实际场景再试。

5.回调结果处理

微信SDK提供了WXEntryBasePage类,继承自Page类,用来响应微信的回调。

如果你的页面基类仍然是Page,可以替换为WXEntryBasePage作为你的Page基类,直接重载各种Response方法即可得到回调结果;如果你已有自定义的Page基类,则通过另外的途径获取回调结果。

WXEntryBasePage类提供public void Handle(FileActivatedEventArgs e)方法来处理回调,我们仅需在App.xaml.cs中重载OnFileActivated方法,将参数传入Hadle方法即可进行结果解析,并将不同类型的消息结果通过不同的响应方法进行通知。

WXEntryBasePage类包含以下Response方法:

  1. public virtual void OnSendAuthResponse(SendAuth.Resp response)
  2. {
  3. }
  4.  
  5. public virtual void OnSendMessageToWXResponse(SendMessageToWX.Resp response)
  6. {
  7. }
  8.  
  9. public virtual void OnSendPayResponse(SendPay.Resp response)
  10. {
  11. }

以上三种Response方法分别对应登录授权、消息分享以及支付等操作的结果。

  • 如果你的Page基类已改成WXEntryBasePage,那么直接重载对应的这三个方法即可,如:
  1. public override async void OnSendMessageToWXResponse(SendMessageToWX.Resp response)
  2. {
  3. base.OnSendMessageToWXResponse(response);
  4. var dialog = new MessageDialog(response.ErrCode == ? "分享成功": "分享失败");
  5. await dialog.ShowAsync();
  6. }
  • 如果你的Page基类没有改成WXEntryBasePage,那么你需要自己实现一个Callback类,继承自WXEntryBasePage:
  1. public class WeChatCallback : WXEntryBasePage
  2. {
  3. }

并在App.xaml.cs的OnFileActivated方法中,创建该对象,并调用其Handle方法:

  1. protected override void OnFileActivated(FileActivatedEventArgs args)
  2. {
  3. base.OnFileActivated(args);
  4. try
  5. {
  6. var wechat = new WeChatCallback();
  7. wechat.Handle(args);
  8. }
  9. catch (Exception)
  10. {
  11. // ignored
  12. }
  13. }

对于消息分享的Response,参数类型是SendMessageToWX.Resp,ErrCode == 0时表示分享成功,否则分享失败;

对于登录授权的Response,参数类型是SendAuth.Resp,其中Code即OAuth授权第一步所需的code,通过这个code,调用微信的Open API换取AccessToken,之后才能得到用户的基本资料。微信SDK并不实现Open API,所以需要自行实现。我还写了一个WeChatSDK.Extensions类库,提供WeChatSns类,封装了部分Open API,直接调用封装好的接口即可完成整个OAuth:

  1. public override async void OnSendAuthResponse(SendAuth.Resp response)
  2. {
  3. base.OnSendAuthResponse(response);
  4. if (response.ErrCode == )
  5. {
  6. if (!string.IsNullOrEmpty(response.Code))
  7. {
  8. var token = await WeChatSns.GetAccessTokenAsync(response.Code);
  9. if (token != null)
  10. {
  11. var user = await WeChatSns.GetUserInfoAsync(token.AccessToken, token.OpenId);
  12. var dialog = new MessageDialog($"name:{user.Nickname}\r\nopenid:{user.OpenId}","授权成功");
  13. await dialog.ShowAsync();
  14. }
  15. }
  16. }
  17. else
  18. {
  19. var dialog = new MessageDialog("授权失败");
  20. await dialog.ShowAsync();
  21. }
  22. }

WeChatSDK.Extensions类库源码已贴在Github上,欢迎补充https://github.com/zhxilin/WeChatSDK/tree/master/UWP/WeChatSDK.Extensions

更多微信Open API请参考官方文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN

6.剖析微信SDK的原理

说完微信SDK的用法,下面谈谈它的实现原理。

要理解微信SDK的实现原理,首先要解决一个问题,理解什么是Protocol Buffers。可能很多人都注意到了微信SDK需要引用Google.ProtocolBuffersLite类库。

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前支持C++、Java、Python、C#等语言。

...

是Google 公司内部的混合语言数据标准

使用Protocol Buffers比XML的好处在于更简单、更快、更小,对于微信这种频繁数据序列化和反序列化的场景来说非常实用。微信的数据交换在设计之初必须考虑实现消息的跨平台传输,那么对于平台无关、可扩展性超高的Protocol Buffers技术来说,就有了很大的用武之地。

对Protocol Buffers有兴趣的朋友可以多查阅一下相关资料

http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/index.html

http://kb.cnblogs.com/page/77621/

http://www.cnblogs.com/wu-jian/archive/2011/02/22/1961104.html

简单来说,对于服务端,只需要传输定义好结构的序列化文件 .proto文件到不同平台的客户端,通过Google提供的工具,如protoc、ProtoGen等工具即可反序列化为对应平台的具体对象。可以通过一张图来理解:

.proto文件会转成二进制序列protobuf进行传输,客户端接收到二进制序列后,按照指定的格式读取到对应平台的结构类型中就可以了。整个解析过程需要 Protocol Buffers框架和Protobuf 编译器生成的代码共同完成。比如protoc将.proto文件转成二进制文件,再通过protogen读取二进制文件转成C#代码。

了解了以上知识之后,我们来看看微信SDK是怎么做的。

比如分享消息,SDK将每个消息的结构整理后填入TransactionData中,该类包含ToProto方法和FromProto方法,分别将数据结构序列化成.proto对象和将.proto对象反序列化成数据结构。ToProto方法调用了Goolge.ProtocolBuffersLite类库提供的GeneratedBuilderLite<TMessage, TBuilder>.Build()方法完成序列化;FromProto方法则调用了BuildParsed()方法,将二进制序列反序列化成数据结构。

  1. internal TransactDataP ToProto()
  2. {
  3. TransactDataP.Builder builder = TransactDataP.CreateBuilder();
  4. // ... 将TransactData中的属性填入builder后Build
  5. return builder.Build();
  6. }
  1. public static SendAuthResp ParseFrom(byte[] data)
  2. {
  3. return CreateBuilder().MergeFrom(data).BuildParsed();
  4. }

我们的应用将数据打包放入一个后缀为.wechat的文件中,通过Launcher启动这个文件,自然只有微信客户端能识别这个文件,所以微信被呼叫起来并通过protobuf机制处理这个文件,完成我们的请求。

至于文件关联协议,之前讲过,在Package.appxmanifest中使用AppId(如wx0123456789abcdef)填写的声明,就是为了保证微信在处理完分享或者完成登录授权后,生成数据并写入文件.wx0123456789abcdef中,通过FileTypeAssociation协议,这种后缀的文件,也只能由我们的应用来打开了,这样就保证了互调关系的唯一性。OnFileActivated接收到文件之后,把文件内的数据通过protobuf机制反序列出来就能得到结果了。

【Win10 UWP】微信SDK基本使用方法和基本原理的更多相关文章

  1. 微信sdk php签名方法整理

    <?php class JSSDK { private $appId; private $appSecret; public function __construct($appId, $appS ...

  2. 【Win10 UWP】QQ SDK(一):SDK基本使用方法

    每当开发一个应用需要社交分享的应用时,总是心里咯噔一下:到底什么时候分享能加上QQ和微信?除了WP8.0版本的微信SDK,官方似乎从未正面发布过适应时代发展的QQ SDK,就连后台,也没有一个可以创建 ...

  3. win10 uwp DataContext

    本文告诉大家DataContext的多种绑法. 适合于WPF的绑定和UWP的绑定. 我告诉大家很多个方法,所有的方法都有自己的优点和缺点,可以依靠自己喜欢的用法使用.当然,可以在新手面前秀下,一个页面 ...

  4. 【Win10 UWP】QQ SDK(二):SDK的回调处理

    上一讲,我们介绍了QQ SDK的使用方法,请看<[Win10 UWP]QQ SDK(一):SDK基本使用方法> 一. 回调的基本形式 从前面的介绍中我们知道,我们的应用和QQ客户端之间需要 ...

  5. Win10 UWP 开发系列:使用多语言工具包让应用支持多语言

    之前我在一篇blog中写过如何使用多语言工具包,见http://www.cnblogs.com/yanxiaodi/p/3800767.html 在WinEcos社区也发布过一篇详细的文章介绍多语言工 ...

  6. Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

    安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...

  7. Win10 UWP开发系列:实现Master/Detail布局

    在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档: ...

  8. Win10/UWP开发—使用Cortana语音与App后台Service交互

    上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比 ...

  9. 【Win10 UWP】后台任务与动态磁贴

    动态磁贴(Live Tile)是WP系统的大亮点之一,一直以来受到广大用户的喜爱.这一讲主要研究如何在UWP应用里通过后台任务添加和使用动态磁贴功能. 从WP7到Win8,再到Win10 UWP,磁贴 ...

随机推荐

  1. Java是如何读取和写入浏览器Cookies的

    首先我们认识下什么是cookies: cookie实际上是一个存在你硬盘里的数据,但是这些数据很特殊,只能由web应用提交给浏览器帮助存储,并且我们还能读取浏览器存在本地的cookie web应用一般 ...

  2. Retrofit源码分析(一)

    1.基本用法 创建接口 public interface GitHubService { @GET("users/{user}/repos") Observable<List ...

  3. windows环境下安装vue+webpack的开发环境

    本人最近在学习vue,在学习的过程中遇到对的问题和解决方法 1.我们首先要安装node.js.node.js的官方地址为:https://nodejs.org/en/download/,下载完毕,按照 ...

  4. effetive C++ 02 尽量以const,enum,inline替换#define

    #define ASPECT_RATIO=1.1const double AspectRatio=1.1 1. 使用宏会导致预处理器把程序代码中的ASPECT_RATIO无条件替换为1.1,编译器从未 ...

  5. APP审核被拒,原因总结

    今天早上,突然看到上周末提交的APP,审核被拒了.原以为是因为IPV6审核没过,后来查看原因后发现是,app的3张展示图里面,有些内容显示的有:测试XX等字眼.苹果说提交的版本不能是含有 test,t ...

  6. nginx url 重写

    rewrite ^([^\.]*)/platform/(.+)/(.+)-(.+)\.html$ $1/platform.php?mod=asklist&ym=$2&fl=$3& ...

  7. XAMARIN +VS2015 ANDROID 开发禁止屏幕自动转动 Portrait,Nosensor

    网上有很多java的写法,但是放在C#中都无法使用,其实有时候还是安下心来认真的去看官网文档比在百度或者google来的快的多 this.RequestedOrientation = Android. ...

  8. linux下搭建nagios

    配置环境:1)CentOS 6.5 作为监控主机,IP:10.0.0.30(根据自己公司需要改变) 2)客户机: windows server  2008R2 , windows 7, windows ...

  9. java的数据类型的转换

    一:java的数据类型转换除布尔类型boolean(不能转换)有两种:<一> 自动转换: <二> 强制转换 <一>.自动转换:就是将小的数据类型自动转换成大的数据类 ...

  10. while语句(1)

    <?php     for ($i=1; $i<=10  ; $i++) {        echo $i."-".($i*10)."<br>&q ...