博客园客户端UAP开发随笔 -- 让自己的App连接世界:WinRT中的微博分享

近年来社交app可谓红红火火,大家每天发微博,分享到朋友圈也是不亦乐乎。我们的Universal应用自然也希望加入社交分享的功能。然而国内主流的社交平台微博和微信还没有推出适用于Universal应用的SDK,怎么办呢?当然敲碗等开饭也是办法,另一方面我们也可以自己做一些努力。今天我们就想分享一下我们在Universal应用中实现分享到微博功能上的探索。

准备

想要分享到微博,先得注册成为微博开发者。我们在http://open.weibo.com/上注册好开发者账号,建立个测试应用,就可以拿到我们的App key和App secret了,准备工作就是这样。

做一些努力

下面就是SDK的问题了,其实微博是有一个官方开源的for Windows 8 SDK的,还是基于Windows RunTime的。这个SDK的下载地址是http://weibowinrtsdk.codeplex.com/

我们的Universal 应用不也是基于Windows RunTime的吗?是不是通用呢?先把它的代码下载下来吧。在http://weibowinrtsdk.codeplex.com/SourceControl/latest 页面点download,下载下来的内容包括说明文档,SDK的源码,还有一个例子程序。

打开WeiboSDKForWinRT.sln,我们可以看到微博SDK原来是for Windows 8的:

点击一下 重定目标到Windows 8.1, 确定。好了,我们的SDK已经是for Windows 8.1的了:

那我们的Universal应用还有Windows Phone 8.1 怎么办呢?理想的情况是我们在目标里加上Windows Phone 8.1 就可以了,先这么做试试看:

点击 更改… ,勾选Windows Phone 8.1

确定

添加好了,SDK项目的后缀也变成了 可移植的。

马上就在 Universal应用里试一试吧。在解决方案里新建个Universal 应用,引用上我们的SDK。

先从Windows 8.1 应用开始吧,调用代码可以从例子程序里copy一些。

我们在空白的MainPage页面上加个button,点击可以调用微博SDK授权并发一条纯文字微博:

MainPage.xaml:

<Page

x:Class="App1.MainPage"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="using:App1"

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Button Content="Button" HorizontalAlignment="Left" Margin="252,140,0,0" VerticalAlignment="Top" Click="Button_Click"/>

<TextBlock x:Name="statusRun" HorizontalAlignment="Left" Margin="294,249,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Height="23" RenderTransformOrigin="0.5,0.5" Width="644">

</TextBlock>

<TextBlock x:Name="ResultRun" HorizontalAlignment="Left" Margin="280.991,346.281,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Height="123.454" UseLayoutRounding="False" Width="308.332" d:LayoutRounding="Auto">

</TextBlock>

</Grid>

</Page>

MainPage.xaml.cs:

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Runtime.InteropServices.WindowsRuntime;

using WeiboSDKForWinRT;

using Windows.Foundation;

using Windows.Foundation.Collections;

using Windows.UI.Xaml;

using Windows.UI.Xaml.Controls;

using Windows.UI.Xaml.Controls.Primitives;

using Windows.UI.Xaml.Data;

using Windows.UI.Xaml.Input;

using Windows.UI.Xaml.Media;

using Windows.UI.Xaml.Navigation;

// "空白页"项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上提供

namespace App2

{

/// <summary>

/// 可独立使用或用于导航至 Frame 内部的空白页。

/// </summary>

public sealed partial class MainPage : Page

{

public MainPage()

{

this.InitializeComponent();

InitData();

}

private void InitData()

{

// TODO:编译运行之前需要开放平台参数.

SdkData.AppKey = "132125341";

SdkData.AppSecret = "55cee081b74dabb1b53bf3b9a9bfa208";

SdkData.RedirectUri = "https://api.weibo.com/oauth2/default.html";

// prepare the pic to be shared.

}

/// <summary>

/// Invoked when this page is about to be displayed in a Frame.

/// </summary>

/// <param name="e">Event data that describes how this page was reached. The Parameter

/// property is typically used to configure the page.</param>

protected override void OnNavigatedTo(NavigationEventArgs e)

{

var oauthClient = new ClientOAuth();

// 判断是否已经授权或者授权是否过期.

if (oauthClient.IsAuthorized == false)

{

oauthClient.LoginCallback += (isSucces, err, response) =>

{

if (isSucces)

{

// TODO: deal the OAuth result.

this.statusRun.Text = "Congratulations, Authorized successfully!";

this.ResultRun.Text = string.Format("AccesssToken:{0}, ExpriesIn:{1}, Uid:{2}",

response.AccessToken, response.ExpriesIn, response.Uid);

}

else

{

// TODO: handle the err.

this.statusRun.Text = err.errMessage;

}

};

oauthClient.BeginOAuth();//异步方法,如果需要在之后执行代码,请加到上面的LoginCallback中

}

}

private async void Button_Click(object sender, RoutedEventArgs e)

{

var engine = new SdkNetEngine();

ISdkCmdBase cmdBase = new CmdPostMessage()

{

Status = "test for post message without picture"

};

var result = await engine.RequestCmd(SdkRequestType.POST_MESSAGE, cmdBase);

if (result.errCode == SdkErrCode.SUCCESS)

{

this.ResultRun.Text = result.content;

this.statusRun.Text = "Post a message without picture successed!";

}

else

{

// TODO: deal the error.

this.statusRun.Text = "Post a message without picture failed!";

}

}

}

}

中间这里注意填上我们之前得到的App key和App secret:

SdkData.AppKey = "";

SdkData.AppSecret = "";

SdkData.RedirectUri = "";

RedirectUri 也是个比较重要的参数,一般情况下填 https://api.weibo.com/oauth2/default.html ,填错了服务器会返回错误。参见http://open.weibo.com/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98 的faq:

Q:获取用户授权是出现 error :redirect_uri_mismatch 怎么解决?

A:这是由于回调地址填写错误造成的,解决办法:

  • 站内应用:redirect_uri等于应用信息中的"站内应用地址"而非"应用实际地址";
  • 其他应用:redirect_uri需与http://open.weibo.com/apps/30871*****/info/advanced (30871*****替换成你应用的AppKey)应用高级信息中的"应用回调页"完全匹配或在绑定的域名下。

注意:修改应用回调页或绑定域名后需要约半小时左右时间生效。

接下来就可以运行啦:

输入微博账号,就可以给我们的Windows 8.1应用授权了:(这里有点要注意的,如果我们的应用没有提交并通过审核的话,只能用自己的账号给应用授权)

现在可以点击一下button:

哈哈,成功了。看看我们的微博,是不是多了一条:

这样子Windows 8.1应用的分享到微博就基本搞定啦,下面我们看看Windows Phone 8.1应用的。

继续努力

先尝试一下在Windows Phone 8.1应用中照Windows 8.1应用的方法调用微博SDK:

出错咯。原来 WebAuthenticationBroker.AuthenticateAsync 这个方法在Windows Phone 8.1 上没有实现 -_-|||。赶紧查查资料,原来Windows Phone 8.1上要使用 WebAuthenticationBroker.AuthenticateAndContinue 这个方法。参见 https://code.msdn.microsoft.com/windowsapps/Web-Authentication-d0485122

简单的说就是调用 WebAuthenticationBroker.AuthenticateAndContinue 方法以后,会暂时跳出我们的Windows Phone 8.1 应用,在系统提供的一个专门的空间内得到WebAuthenticationResult,再通过我们的Windows Phone 8.1 应用的onActive事件将其传回应用,再根据WebAuthenticationResult的结果继续调用ContinueWebAuthentication进行下一步的认证工作。

这样一来我们的SDK代码为了适应Universal 应用的Windows 应用和Windows Phone 应用就有了分歧,这正是条件编译派上用场的时候了。

我们将ClientOAuth.cs中的 GetAuthorizeCode 方法替换为如下:

/// <summary>

/// 授权获取authorize_code.

/// </summary>

private async void GetAuthorizeCode()

{

string oauthUrl = string.Format("{0}/oauth2/authorize?client_id={1}&response_type=code&redirect_uri={2}&display=mobile"

, Constants.ServerUrl2_0, SdkData.AppKey, SdkData.RedirectUri);

Uri startUri = new Uri(oauthUrl, UriKind.Absolute);

Uri endUri = new Uri(SdkData.RedirectUri, UriKind.Absolute);

// 调出认证页面.

#if WINDOWS_PHONE_APP

WebAuthenticationBroker.AuthenticateAndContinue(startUri, endUri);

#else

var authenResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, startUri, endUri);

switch (authenResult.ResponseStatus)

{

case WebAuthenticationStatus.Success:

{

string authorize_code = string.Empty;

var data = authenResult.ResponseData;

authorize_code = SdkUility.GetQueryParameter(data, "code");

if (string.IsNullOrEmpty(authorize_code) == false)

{

Authorize(authorize_code);

}

}

break;

case WebAuthenticationStatus.UserCancel:

{

SdkAuthError err = new SdkAuthError();

err.errCode = SdkErrCode.USER_CANCEL;

err.errMessage = Constants.SdkMsg.OAuthUserCanceled;

if (null != LoginCallback)

LoginCallback(false, err, null);

}

break;

case WebAuthenticationStatus.ErrorHttp:

default:

{

SdkAuthError err = new SdkAuthError();

err.errCode = SdkErrCode.NET_UNUSUAL;

err.errMessage = Constants.SdkMsg.NetException;

if (null != LoginCallback)

LoginCallback(false, err, null);

}

break;

}

#endif

}

public void continueAuth(WebAuthenticationResult authenResult)

{

switch (authenResult.ResponseStatus)

{

case WebAuthenticationStatus.Success:

{

string authorize_code = string.Empty;

var data = authenResult.ResponseData;

authorize_code = SdkUility.GetQueryParameter(data, "code");

if (string.IsNullOrEmpty(authorize_code) == false)

{

Authorize(authorize_code);

}

}

break;

case WebAuthenticationStatus.UserCancel:

{

SdkAuthError err = new SdkAuthError();

err.errCode = SdkErrCode.USER_CANCEL;

err.errMessage = Constants.SdkMsg.OAuthUserCanceled;

if (null != LoginCallback)

LoginCallback(false, err, null);

}

break;

case WebAuthenticationStatus.ErrorHttp:

default:

{

SdkAuthError err = new SdkAuthError();

err.errCode = SdkErrCode.NET_UNUSUAL;

err.errMessage = Constants.SdkMsg.NetException;

if (null != LoginCallback)

LoginCallback(false, err, null);

}

break;

}

}

现在我们的SDK的条件编译还没有生效,我们需要新建一个For Windows Phone的SDK:

把我们原有SDK的文件添加为链接:

注意CmdModel 下的文件,以及RestSharp.winmd 的引用也要加进来。还有我们的程序集名称因为新建项目的原因变化了,也得改回去。

改为

现在把Windows Phone 8.1应用的引用替换成WeiboSDKForWinRTPhone的。

接下来就可以果断地借鉴例子程序Web authentication broker sample 了,把它的ContinuationManager.cs拷贝过来。参见 https://code.msdn.microsoft.com/windowsapps/Web-Authentication-d0485122

让 MainPage 实现 IWebAuthenticationContinuable 的接口:

public sealed partial class MainPage : Page, IWebAuthenticationContinuable

再给 MainPage 加上个实现 IWebAuthenticationContinuable 接口中 ContinueWebAuthentication进行下一步的方法:

public void ContinueWebAuthentication (WebAuthenticationBrokerContinuationEventArgs ex)

{

var oauthClient = new ClientOAuth();

oauthClient.LoginCallback += (isSucces, err, response) =>

{

if (isSucces)

{

// TODO: deal the OAuth result.

this.statusRun.Text = "Congratulations, Authorized successfully!";

this.ResultRun.Text = string.Format("AccesssToken:{0}, ExpriesIn:{1}, Uid:{2}",

response.AccessToken, response.ExpriesIn, response.Uid);

}

else

{

// TODO: handle the err.

this.statusRun.Text = " Authorized Failed!";

this.ResultRun.Text = err.errMessage;

}

};

oauthClient.continueAuth(ex.WebAuthenticationResult);

}

最后处理一下App.xaml.cs中的 事件:

#if WINDOWS_PHONE_APP

ContinuationManager continuationManager;

/// <summary>

/// Handle OnActivated event to deal with File Open/Save continuation activation kinds

/// </summary>

/// <param name="e">Application activated event arguments, it can be casted to proper sub-type based on ActivationKind</param>

protected override void OnActivated(IActivatedEventArgs e)

{

base.OnActivated(e);

continuationManager = new ContinuationManager();

Frame rootFrame = Window.Current.Content as Frame;

// Do not repeat app initialization when the Window already has content,

// just ensure that the window is active

if (rootFrame == null)

{

// Create a Frame to act as the navigation context and navigate to the first page

rootFrame = new Frame();

// Place the frame in the current Window

Window.Current.Content = rootFrame;

}

if(rootFrame.Content == null)

{

rootFrame.Navigate(typeof(MainPage));

}

var continuationEventArgs = e as IContinuationActivatedEventArgs;

if (continuationEventArgs != null)

{

// Call ContinuationManager to handle continuation activation

continuationManager.Continue(continuationEventArgs, rootFrame);

}

Window.Current.Activate();

}

#endif

赶紧运行看看:

好吧,又出错了。看起来是跳转到应用外失败了,是不是我们太早跳转了呢?把OnNavigatedTo中的授权的过程放到 Page 的 Loaded 事件里试试吧:

仍然不行,那只有采用延迟的办法了:

private async void Page_Loaded(object sender, RoutedEventArgs e)

{

await Task.Delay(1000);

var oauthClient = new ClientOAuth();

// 判断是否已经授权或者授权是否过期.

if (oauthClient.IsAuthorized == false)

{

oauthClient.LoginCallback += (isSucces, err, response) =>

{

if (isSucces)

{

// TODO: deal the OAuth result.

this.statusRun.Text = "Congratulations, Authorized successfully!";

this.ResultRun.Text = string.Format("AccesssToken:{0}, ExpriesIn:{1}, Uid:{2}",

response.AccessToken, response.ExpriesIn, response.Uid);

}

else

{

// TODO: handle the err.

this.statusRun.Text = err.errMessage;

}

};

oauthClient.BeginOAuth();

}

}

再看看行不行?

好了,终于大功告成。

结尾

我们这个修改过的微博SDK可以在https://code.msdn.microsoft.com/windowsapps/Share-To-Weibo-in-c99da5fa 找到。其中难免会有一些Bug,欢迎大家指正。

分享代码,改变世界!

Windows Phone Store App link:

http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc

Windows Store App link:

http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059

GitHub open source link:

https://github.com/MS-UAP/cnblogs-UAP

MSDN Sample Code:

https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab

时间: 2024-11-09 00:38:31

博客园客户端UAP开发随笔 -- 让自己的App连接世界:WinRT中的微博分享的相关文章

博客园客户端UAP开发随笔 – 让自己的App连接世界(2):WinRT中的内置分享

看到一篇眼前一亮的博文,是不是有一种希望其他小伙伴都能看到的感觉呢?有没有一种“不转不是程序员”的冲动呢?在 PC 浏览器上看到还好办,直接网址复制,另一边 IM 上就发过去了,但是如果是 App 中的内容,就没这么方便了,总不能那边 IM 上喊话:“隔壁老王,博客园上有篇叫‘博客园客户端(Universal App)开发随笔 – 为应用插上分享的翅膀’的博文超好看,要不你也瞅瞅?”.隔壁老王再去搜索就太麻烦了.可能你会说了,嗨,直接分享不就完了么.嗯,没错,就是分享功能.那么如何把分享功能引入

博客园客户端UAP开发随笔 -- 搭建App之间的桥梁

开发Windows Phone应用的同学们应该都注意到了,Windows Phone 为了安全性,对应用的限制还是比较多的.我记得一位360的同学很无奈的说:WP太安全了,我们这些做WP上360卫士的基本上没啥可做的.但是当WP360那个App出来后,还是有很多用户安装了呢,尽管真的对安全没什么太大的帮助,但是对用户了解自己的手机的使用情况还是有帮助的.其中一位用户的评价是:从android到PC,我一直用360, 所以在WP上我也用.呵呵,粉丝啊!具体有什么用其实他也不关心铁粉而已. 扯远了!

博客园客户端UAP开发随笔 -- App的心动杀手锏:动画

前言 在前面一篇“新年快乐”的随笔中,我们介绍了WinRT中的简单动画实现.其实在使用Windows/Windows Phone时,我们都会看到一些动画,最简单的比如按下一个button时,该button的状态变化就是动画的一种.再比如弹出式窗口或菜单,也是一种动画.WinRT中的动画种类很多,但是分类有点儿让初学者摸不着头脑:主题过渡,主题动画,视觉转换,情节提要动画.这些我们就不说了,这里主要说说自定义动画,或者说是情节提要动画(Storyboard Animation),因为这种动画是我们

博客园客户端UAP开发随笔 -- 奔跑吧,页面!

前言 页面导航,是App中的基本功,一般的App,一来一去,只需要简单的Navigate + Back就行了,一个复杂的App可能需要很多导航模式的混合才能实现最佳用户体验. SplashScreen 启动屏幕 我们先从最开始的SplashScreen说起吧.如果你把启动屏幕做成一个Page,启动时先显示一下,然后假装忙乎两秒,跳到下一个主页面开始进入正题,这个好像看上去也很美好.但是当用户玩命儿按Back键时,哦,露出马脚了,启动页面被唤出了.不过这个bug倒是不妨作为一个新奇的体验. MSD

博客园客户端UAP开发随笔 -- App连接云端内容的桥梁:WebView

当你辛苦的从网上爬下来一篇文章之后,怎么在你的应用内展示这些包含HTML标记的文章?如果你使用的是Javascript开发应用,恭喜你,直接塞进页面就可以了,同时说明你很熟悉页面开发,而现在windows也支持这种方式.但是对于使用XAML开发的应用怎么办呢?我们还有WebView控件可以用. 越来越多的服务器端API返回的数据使用HTML了,所以我们也不得不对WebView多了解一些. WebView有个Bug:放在Grid里时,最右侧有一个pixel缝隙时隐时现.要小心,别让PM抓住你的小辫

博客园客户端UAP开发随笔--自定义控件的左膀右臂

前言 我们上一次说到了App的精灵:自定义控件.这一次,我们接着这一话题,说说自定义控件的两个得力助手: 选择器 - TemplateSelector 转换器 – Converter 这两个东西能帮助自定义控件更为简单方便地被使用,所以必须掌握. 数值转换器 Converter 这个大家可能不陌生,因为在MSDN里,介绍到Data Binding时,总会顺带着介绍一下数据转换,比如这个网页: http://msdn.microsoft.com/library/windows/apps/xaml/

博客园客户端UAP开发随笔 -- App UI设计的三大纪律八项注意

前言 每一个页面都是这个App的门面,尤其是主页面,看上去干净整洁清爽宜人容易操作,那么你的App就成功了一半.这也反映出了你这个开发团队的基本审美素质和设计理念.如果你不是一个团队,而是一个个人开发者,建议你好好读读以下心得体会,相信会帮助你做出好看而实用的App.用一堆拥有丑陋UI的App充斥Window Store,不是我们高大上的程序员所为,被其他手机开发平台的开发者们耻笑. 三大纪律: 1)不乱用颜色.一个页面内不要超过3种颜色 2)不乱用大图片当背景.你是想让用户看你的背景图片呢,还

博客园客户端UAP开发随笔 -- 让你自己和你的App有国际范儿

大家是不是发现,在商店中看到的高大上的应用都有着多语言支持,可以根据操作系统的语言自动适配:或者可以通过用户的选择,显示对应的语言界面,确实很高大上呢.不过这个可不是什么难事,通过简单的几个步骤,让你的应用也高大上起来,支持多语言.这样在你以后的简历里,也可以写上:面向国际市场开发过多语言应用.听上去相当有底气! 0. 准备工作 在建立多语言支持前,首先要看一下 Manifest 文件中的默认语言选项,将它设置为你希望的默认显示语言. 接下来建立存放语言字符串的文件夹.如果是Universal

博客园客户端UAP开发随笔 -- 狡兔三窟:App内的三种通知消息的实现

使用应用时,总会有各种各样的交互,其中有些是需要和用户交互的,有些是仅仅告知用户某些信息的.对于前者,通常的解决方案都是弹出一个带有按钮(或其他控件)的对话框,上面有需要用户知晓的信息,以及需要用户通过按钮(或其他控件)做出的响应交互,这里就不再介绍.对于后者,那些不需要用户做出交互,仅仅是告知用户信息的,实现方式大家各有不同,本文将提出几种解决思路,抛砖引玉,希望通过交流,得到更好的人机交互解决方案. 1. 弹出窗口提示 这个方法比较简单粗暴,直接调用了系统的 MessageDialog 方法