しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

UP by Jawbone のライフログを Windows アプリで取得する(3)

UP by Jawbone のライフログWindows アプリで取得する(2)の続きです

OAuth 2.0 の処理の流れはわかりましたが、途中のリダイレクト後の Uri 取得をどうするかが未解決でした

とりあえずリダイレクト前までの処理を進めてみます

設定チャームからデバイス連携の OAuth 認証を通すため、646 px の設定ポップアップを作成します

中身は下記のような WebView があるだけの単純なものです

<SettingsFlyout x:Class="LifelogViewer.Views.Flyout.OAuthFlyout"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="using:LifelogViewer.Views.Flyout"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                Title="UP 連携設定"
                Width="646"
                IconSource="Assets/SmallLogo.png"
                d:DesignWidth="646"
                mc:Ignorable="d">

    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

        <StackPanel Style="{StaticResource SettingsFlyoutSectionStyle}">

            <TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="Jawbone とこのアプリの連携設定が必要です" />

            <TextBlock Margin="0,0,0,25"
                       Style="{StaticResource BodyTextBlockStyle}"
                       TextWrapping="Wrap">
                <TextBlock.Text>UP アカウントでサインイン後、このアプリが Jawbone のライフログにアクセスすることを許可してください</TextBlock.Text>
            </TextBlock>

            <WebView x:Name="webView" Height="500" />

        </StackPanel>

    </StackPanel>
</SettingsFlyout>

次に通信がらみの処理を行うサービスクラスを下記のように作りました

/// <summary>
/// Jawbone アクセスサービス
/// </summary>
public class JawboneService
{
    /// <summary>
    /// トークン要求 Uri
    /// </summary>
    private static readonly string RequestTokenBaseUri = @"https://jawbone.com/auth/oauth2/auth?response_type=code&client_id={0}&scope={1}&redirect_uri={2}";

    /// <summary>
    /// Client ID
    /// </summary>
    private static readonly string ClientId = @"登録アプリの値を設定";

    /// <summary>
    /// トークン要求用 Uri を構成する
    /// </summary>
    /// <returns>トークン要求用 Uri</returns>
    public string GetRequestTokenUri()
    {
        return string.Format(RequestTokenBaseUri, Uri.EscapeDataString(ClientId), Uri.EscapeDataString(Scopes), Uri.EscapeDataString(RedirectUri));
    }
}

あとは設定ポップアップ遷移時の処理を記載します

/// <summary>
/// OAuth 認証用ポップアップ
/// </summary>
public sealed partial class OAuthFlyout : SettingsFlyout
{
    /// <summary>
    /// コンストラクタ
    /// </summary>
    public OAuthFlyout()
    {
        this.InitializeComponent();

        this.Loaded += this.OnLoaded;
        this.Unloaded += this.OnUnloaded;
    }

    /// <summary>
    /// 破棄時の処理
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private void OnUnloaded(object sender, RoutedEventArgs e)
    {
        this.Unloaded -= this.OnUnloaded;
        this.Loaded -= this.OnLoaded;
        this.webView.NavigationCompleted -= this.OnNavigationCompleted;
    }

    /// <summary>
    /// 読み込み時の処理
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        this.webView.NavigationCompleted += this.OnNavigationCompleted;
        this.webView.Navigate(new Uri(App.JawboneService.GetRequestTokenUri()));
    }

    /// <summary>
    /// WebView 遷移完了時の処理
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private async void OnNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
    {
        // 遷移前の画面がアクセス許可画面だった場合
        if (args.Uri.ToString().StartsWith("https://jawbone.com/auth/oauth2/auth_permission"))
        {
            // WebView の読み込みが完了するまでウェイト
            await Task.Delay(500);

            // WebView 内で JavaScript を経由して Uri を取得
            var uri = await this.webView.InvokeScriptAsync("eval", new string[] { "location.href" });
        }
    }
}

ポイントは最後の OnNavigationCompleted の部分

    /// <summary>
    /// WebView 遷移完了時の処理
    /// </summary>
    /// <param name="sender">イベント発行者</param>
    /// <param name="e">イベント引数</param>
    private async void OnNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
    {
        // 遷移前の画面がアクセス許可画面だった場合
        if (args.Uri.ToString().StartsWith("https://jawbone.com/auth/oauth2/auth_permission"))
        {
            // WebView の読み込みが完了するまでウェイト
            await Task.Delay(500);

            // WebView 内で JavaScript を経由して Uri を取得
            var uri = await this.webView.InvokeScriptAsync("eval", new string[] { "location.href" });
        }
    }

途中で https://localhost:5555 にリダイレクトされると画面遷移に失敗した状態でこちらのイベントハンドラにやってきます

このとき WebView の args.Uri を見ても遷移に失敗したので、遷移前の Uri しか取得できないのですが、JavaScript で強引に location.href を取得しています

実行して動作を確かめてみます

設定ポップアップでまずサインイン画面が表示され

f:id:matatabi_ux:20140612072744p:plain

サインインするとアクセス許可画面に遷移、ここで「同意する」を選ぶと

f:id:matatabi_ux:20140612072757p:plain

リダイレクトされて code のクエリストリング付きの Uri がとれました!

f:id:matatabi_ux:20140612072901p:plain

Web アプリじゃなくても OAuth 認証が通せそうです

次回はこの code からアクセストークンを取得しようと思います