博客園客戶端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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM