XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2016/07/23

Xamarin.Forms Facebook 社群身分驗證

Facebook 社群身分驗證

這一章節,將會說明如何透過 Xamarin 提供的元件 Xamarin.Auth,進行社群身分驗證,在這裡,將會使用 Facebook 作為身分驗證的來源。
這個專案一開始執行,只會有一個按鈕,當按下這個按鈕,就會使用原生平台的功能,進行 OAuth2 的身分驗證;當驗證過程結束之後,會將取得的 Token 顯示在螢幕上。

建立社群身分驗證頁面方案

  1. 首先,開啟您的 Visual Studio 2015
  2. 接著透過 Visual Studio 2015 功能表,選擇這些項目 檔案 > 新增 > 專案 準備新增一個專案。
  3. 接著,Visual Studio 2015 會顯示 新增專案 對話窗,請在這個對話窗上,進行選擇 Visual C# >Cross-Platform > Blank Xaml App (Xamarin.Forms Portable)
  4. 接著,在最下方的 名稱 文字輸入盒處,輸入 XFAuth 這個名稱,最後使用滑鼠右擊右下方的 確定按鈕。
  5. 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到 Xamarin Mac Agent Instructions 對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。
  6. 接著會看到 新的通用Windows專案 對話視窗,此時,您只需要按下 確定 按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。
  7. 最後,整個新的 Xamarin.Forms 專案就建立完成了。

安裝所需 NuGet 套件

  1. 請在 XFAuth.Droid 專案的 參考 節點上,滑鼠右擊,接著點選 管理 NuGet 套件 選項,接著點選 瀏覽 標籤頁次,在搜尋文字輸入盒中,輸入 Xamarin.Auth 這個套件,當找到這個套件之後,請將這個套件安裝到這個專案裡面。
  2. 請在 XFAuth.iOS 專案的 參考 節點上,滑鼠右擊,接著點選 管理 NuGet 套件 選項,接著點選 瀏覽 標籤頁次,在搜尋文字輸入盒中,輸入 Xamarin.Auth 這個套件,當找到這個套件之後,請將這個套件安裝到這個專案裡面。

核心PCL頁面新增

OAuthMessage

這個檔案是用來作為訊息中心的指定型別之用
  1. 滑鼠右擊核心PCL XFAuth 專案,點選 加入 > 類別 > Visual C# > 類別
  2. 在底下名稱欄位內輸入 OAuthMessage,之後,點選 新增 按鈕
  3. 請將底下程式碼覆蓋掉這個檔案所有內容

OAuthMessage.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XFAuth
{
    public class OAuthMessage
    {
    }
}

LoginPage

現在要新增的檔案,是用於當要進行 Facebook 身分驗證的時候,所要顯示的頁面;雖然,這個頁面內沒有任何定義,不過,當執行時期,這個頁面將會由原生平台定義的視覺內容,注入到這個頁面中。
  1. 滑鼠右擊核心PCL XFAuth 專案,點選 加入 > 類別 > Visual C# > 類別
  2. 在底下名稱欄位內輸入 LoginPage,之後,點選 新增 按鈕
  3. 請將底下程式碼覆蓋掉這個檔案所有內容
  4. 這個建構式接受一個列舉參數,用來指名所要進行的身分驗證是要採用哪個社群,相關社群的驗證參數,都會儲存在 ProviderOAuthSettings 物件內。

LoginPage.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XFAuth
{
    public class LoginPage : ContentPage
    {
        public OAuthSettings ProviderOAuthSettings { get; set; }

        public LoginPage(Provider provider)
        {
            ProviderOAuthSettings = ProviderManager.GetProviderOAuthSettings(provider);
        }
    }
}

OAuthSettings

這個檔案將會定義 OAuthSettings 類別,裡面的屬性將會用來記錄要進行 OAuth2 身分驗證時,會用到的內容。
  1. 滑鼠右擊核心PCL XFAuth 專案,點選 加入 > 類別 > Visual C# > 類別
  2. 在底下名稱欄位內輸入 OAuthSettings,之後,點選 新增 按鈕
  3. 請將底下程式碼覆蓋掉這個檔案所有內容

.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XFAuth
{
    public class OAuthSettings
    {
        public string ClientId { get; set; }
        public string ClientSecret { get; set; }
        public string AuthorizeUrl { get; set; }
        public string RedirectUrl { get; set; }
        public string AccessTokenUrl { get; set; }
        public List<string> Scopes { get; set; }
        public string ScopesString
        {
            get
            {
                return Scopes.Aggregate((current, next) => string.Format("{0}+{1}", current, next));
            }
        }

        public OAuthSettings()
        {
            Scopes = new List<string>();
        }
    }
}

ProviderManager

這個類別提供一個靜態方法 GetProviderOAuthSettings,根據所指定的社群定義,傳回該社群已經定義好的相關參數
  1. 滑鼠右擊核心PCL XFAuth 專案,點選 加入 > 類別 > Visual C# > 類別
  2. 在底下名稱欄位內輸入 ProviderManager,之後,點選 新增 按鈕
  3. 請將底下程式碼覆蓋掉這個檔案所有內容
  4. 若要使用 Facebook 來進行身分驗證,您需要在 Facebook 中產生一個應用程式,並且取得該應用程式上的 應用程式編號應用程式密鑰;當然,要到到時候可以讓使用者充分識別這是哪個Facebook應用程式的身分驗證,可以在 顯示名稱 欄位輸入明確說明這個應用程式的文字。
    產生Facebook應用程式

ProviderManager.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XFAuth
{
    public enum Provider
    {
        Unknown = 0,
        Facebook,
        Google
    }

    public static class ProviderManager
    {
        private static OAuthSettings FacebookOAuthSettings
        {
            get
            {
                return new OAuthSettings
                {
                    ClientId = "1651918068462476",
                    ClientSecret = "b9e46e4c7257b8c6e108dad79df603d3",

                    AuthorizeUrl = "https://m.facebook.com/dialog/oauth/",
                    RedirectUrl = "http://www.facebook.com/connect/login_success.html",
                    AccessTokenUrl = "https://graph.facebook.com/v2.3/oauth/access_token",
                    Scopes = new List<string> {
                        ""
                    }
                };
            }
        }

        private static OAuthSettings GoogleOAuthSettings
        {
            get
            {
                return new OAuthSettings
                {
                    ClientId = "",
                    ClientSecret = "",
                    AuthorizeUrl = "https://accounts.google.com/o/oauth2/auth",
                    RedirectUrl = "https://www.googleapis.com/plus/v1/people/me",
                    AccessTokenUrl = "https://accounts.google.com/o/oauth2/token",
                    Scopes = new List<string> {
                        "openid"
                    }
                };
            }
        }

        public static OAuthSettings GetProviderOAuthSettings(Provider provider)
        {
            switch (provider)
            {
                case Provider.Facebook:
                    {
                        return FacebookOAuthSettings;
                    }
                case Provider.Google:
                    {
                        return GoogleOAuthSettings;
                    }
            }
            return new OAuthSettings();
        }
    }
}

MainPage

修改應用程式首頁頁面內容與 code behind 的程式碼
  1. 在核心PCL XFAuth 專案,打開 MainPage.xaml
  2. 請將底下程式碼覆蓋掉這個檔案所有內容
  3. 在這個 XAML 檔案內,定義了一個按鈕,按下後,會切換到 Facebook 的身分驗證頁面,而其他的Label 控制項,則是用來顯示身分驗證的成功與取消的內容。

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XFAuth"
             x:Class="XFAuth.MainPage">

  <ContentPage.Padding>30</ContentPage.Padding>

  <StackLayout
    Orientation="Vertical"
    VerticalOptions="Center" HorizontalOptions="Center"
  >
    <Button
      x:Name="button登入Facebook"
      Text="登入Facebook"
      />
    <Label
      x:Name="labelToken"
      Text="Token"
      IsVisible="False"
      />
    <Label
      x:Name="labelTokenValue"
      Text=""
      LineBreakMode="WordWrap"
      IsVisible="False"
      />
    <Label
      x:Name="labelTokenError"
      Text=""
      TextColor="Red"
      LineBreakMode="WordWrap"
      IsVisible="False"
      />

  </StackLayout>
</ContentPage>
  1. 在核心PCL XFAuth 專案,打開 MainPage.xaml.cs
  2. 請將底下程式碼覆蓋掉這個檔案所有內容
  3. 底下程式碼定義了一個按鈕處理事件,另外,也使用訊息中心的 MessagingCenter.Subscribe 訂閱了一個訊息事件,用來聆聽身分驗證的結果,並且做出相關處理。

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XFAuth
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            button登入Facebook.Clicked += async (s, e) =>
             {
                 await Navigation.PushModalAsync(new LoginPage(Provider.Facebook));
             };

            MessagingCenter.Subscribe<OAuthMessage, string>(this, "Authenticated", (sender, e) =>
            {
                var foo = new Button();
                button登入Facebook.IsVisible = false;

                labelToken.IsVisible = true;

                var fooResult = e as string;
                if (fooResult == "Canceled!" )
                {
                    labelToken.Text = "使用者中斷";
                    labelTokenError.Text = "使用者取消登入Facebook";
                    labelTokenError.IsVisible = true;
                    labelTokenValue.IsVisible = false;
                }
                else if (fooResult.Contains("Authentication Exception"))
                {
                    labelToken.Text = "Exception";
                    labelTokenError.Text = fooResult;
                    labelTokenError.IsVisible = true;
                    labelTokenValue.IsVisible = false;
                }
                else
                {
                    labelToken.Text = "Token";
                    labelTokenValue.Text = fooResult;
                    labelTokenValue.IsVisible = true;
                    labelTokenError.IsVisible = true;
                }
            });

        }
    }
}

Android 原生專案

您需要在原生專案內做些修正。

LoginPageRenderer

  1. 滑鼠右擊 XFAuth.Droid 專案,點選 加入 > 類別 > Visual C# > Class
  2. 在底下名稱欄位內輸入 LoginPageRenderer,之後,點選 新增 按鈕
  3. 請將底下程式碼覆蓋掉這個檔案所有內容
  4. 這個類別使用了 ExportRenderer 屬性,用來定在當 LoginPage 頁面要出現在 Android 平台的時候,需要客製化的相關畫面內容。
  5. 若需要使用 Xamarin.Auth 套件來進行 OAuth2 身分驗證,您需要產生 OAuth2Authenticator 這個物件,定義相關處理事件,最後,呼叫 auth.GetUI 方法,將驗證畫面顯示在螢幕上。
  6. 在不同驗證處理結果的事件上,將會透過訊息中心提供的 MessagingCenter.Send<OAuthMessage, string> 方法,將處理結果透過訊息中心傳送出去;而此時,在核心PCL專案內的首頁頁面內的 code behind 程式碼,就會接收到這個訊息事件。

LoginPageRenderer.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using XFAuth;
using Xamarin.Forms.Platform.Android;
using XFAuth.Droid;
using Xamarin.Auth;

[assembly: ExportRenderer(typeof(LoginPage), typeof(LoginPageRenderer))]
namespace XFAuth.Droid
{
    public class LoginPageRenderer : PageRenderer
    {
        LoginPage page;
        bool loginInProgress;

        public LoginPageRenderer()
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null ||
                Element == null)
                return;

            page = e.NewElement as LoginPage;

            if (page == null ||
                loginInProgress)
                return;

            loginInProgress = true;
            try
            {
                OAuth2Authenticator auth = new OAuth2Authenticator(
                    page.ProviderOAuthSettings.ClientId, // your OAuth2 client id
                    page.ProviderOAuthSettings.ClientSecret, // your OAuth2 client secret
                    page.ProviderOAuthSettings.ScopesString, // scopes
                    new Uri(page.ProviderOAuthSettings.AuthorizeUrl), // the scopes, delimited by the "+" symbol
                    new Uri(page.ProviderOAuthSettings.RedirectUrl), // the redirect URL for the service
                    new Uri(page.ProviderOAuthSettings.AccessTokenUrl));

                auth.AllowCancel = true;
                auth.Completed += async (sender, args) => {
                    if (args.IsAuthenticated)
                    {
                        var token = args.Account.Properties["access_token"];
                        MessagingCenter.Send<OAuthMessage, string>(new OAuthMessage(), "Authenticated", token);
                    }
                    else
                    {
                        MessagingCenter.Send<OAuthMessage, string>(new OAuthMessage(), "Authenticated", "Canceled!");
                    }
                    await page.Navigation.PopModalAsync();
                    loginInProgress = false;
                };

                auth.Error += (sender, args) =>
                {
                    Console.WriteLine("Error: {0}", args.Exception);
                };

                var activity = this.Context as Activity;
                activity.StartActivity(auth.GetUI(activity));
            }
            catch (Exception ex)
            {
                MessagingCenter.Send<OAuthMessage, string>(new OAuthMessage(), "Authenticated", $"Authentication Exception: {ex.Message}");
            }
        }
    }
}

iOS 原生專案

您需要在原生專案內做些修正。

LoginPageRenderer

  1. 滑鼠右擊 XFAuth.iOS 專案,點選 加入 > 類別 > Apple > 類別
  2. 在底下名稱欄位內輸入 LoginPageRenderer,之後,點選 新增 按鈕
  3. 請將底下程式碼覆蓋掉這個檔案所有內容

LoginPageRenderer.cs

using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Auth;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using XFAuth;
using XFAuth.iOS;

[assembly: ExportRenderer(typeof(LoginPage), typeof(LoginPageRenderer))]
namespace XFAuth.iOS
{
    public class LoginPageRenderer : PageRenderer
    {
        LoginPage page;
        bool loginInProgress;

        public LoginPageRenderer()
        {
        }

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null ||
                Element == null)
                return;

            page = e.NewElement as LoginPage;
        }

        public override async void ViewDidAppear(bool animated)
        {
            base.ViewDidAppear(animated);

            if (page == null ||
                loginInProgress)
                return;

            loginInProgress = true;
            try
            {
                OAuth2Authenticator auth = new OAuth2Authenticator(
                    page.ProviderOAuthSettings.ClientId, // your OAuth2 client id
                    page.ProviderOAuthSettings.ClientSecret, // your OAuth2 client secret
                    page.ProviderOAuthSettings.ScopesString, // scopes
                    new Uri(page.ProviderOAuthSettings.AuthorizeUrl), // the scopes, delimited by the "+" symbol
                    new Uri(page.ProviderOAuthSettings.RedirectUrl), // the redirect URL for the service
                    new Uri(page.ProviderOAuthSettings.AccessTokenUrl));

                auth.AllowCancel = true;
                // If authorization succeeds or is canceled, .Completed will be fired.
                auth.Completed += async (sender, args) => {
                    if (args.IsAuthenticated)
                    {
                        var token = args.Account.Properties["access_token"];
                        MessagingCenter.Send<OAuthMessage, string>(new OAuthMessage(), "Authenticated", token);
                    }
                    else
                    {
                        MessagingCenter.Send<OAuthMessage, string>(new OAuthMessage(), "Authenticated", "Canceled!");
                    }
                    await DismissViewControllerAsync(true);
                    await page.Navigation.PopModalAsync();
                    loginInProgress = false;
                };

                auth.Error += (sender, args) =>
                {
                    Console.WriteLine("Error: {0}", args.Exception);
                };

                await PresentViewControllerAsync(auth.GetUI(), true);

            }
            catch (Exception ex)
            {
                MessagingCenter.Send<OAuthMessage, string>(new OAuthMessage(), "Authenticated", $"Authentication Exception: {ex.Message}");
            }
        }
    }
}

實際執行畫面

Android 執行結果

請在方案總管內,滑鼠右擊 XFAuth.Droid 專案,選擇 設定為起始專案,接著按下 F5 開始執行。
Android執行結果1
Android執行結果2
Android執行結果3
Android執行結果2
Android執行結果2

iOS 執行結果

請在方案總管內,滑鼠右擊 XFAuth.iOS 專案,選擇 設定為起始專案,接著按下 F5 開始執行。

iOS執行結果1

iOS執行結果2

iOS執行結果1

iOS執行結果2
iOS執行結果1

沒有留言:

張貼留言