XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2017/04/29

Xamarin.Forms 不同的View處理邏輯:Code Behind/INPC/Prism/Fody

對於第一次接觸 Xamarin.Forms 的開發者,或者從未使用過 XAML 來開發過的開發者,第一此要下的決策,那就是,對於頁面的處理邏輯之程式碼編寫,要使用哪種方法呢?
在網路上所看到的文章,或者 Xamarin 官方上看到的 Sample,大多使用 Code Behind + INPC 的方式來演練,不過,我自己是比較偏好使用 MVVM + Data Binding 的方式來進行設計每個頁面的處理邏輯。
在這篇文章中,將會說明不同的技術,如何用來寫出相同頁面的處理邏輯。
這個頁面中,將會有
  • 一個 Entry 控制項,可以讓使用輸入文字
  • 一個 Label 控制項,顯示出使用者輸入的文字
  • 一個按鈕,當使用者按下這個按紐之後,會將使用者輸入的文字,設定到 Label 控制項並顯示出來。
若要參考這篇文章的原始碼,可以參考這裡

使用 Code Behind 方式來開發

在這個方式,將僅需要使用 Page.xaml & Page.xaml.cs 這兩個檔案,進行開發。
您需要在頁面的 XAML 宣告中,對於需要處理的各個控制項、版面配置等等,使用 x:Name 延伸標記,標示出這個視覺項目(Visual Element)可以在 Code Behind 存取的物件名稱。
如此,您就可以在這個頁面中的 Code Behind (在這裡是 CodeBehindPage.xaml.cs) 內,使用這些 x:Name所標示的物件名稱,存取這些視覺項目。
當然,對於按鈕這類控制項,您需要使用該控制項的事件,設定當使用者按下這個按鈕之後,相對應的 Clicked 事件要做的事情。

CodeBehindPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFDataBinding.Views.CodeBehindPage"
             Title="使用 Code Behind">

    <StackLayout
        Margin="20,0"
        >
        <Entry x:Name="MyEntry"
            HorizontalOptions="FillAndExpand"
            Text=""/>

        <Label x:Name="MyLabel"
            HorizontalOptions="FillAndExpand"
            Text=""/>

        <Button x:Name="btn登入"
            Text="登入"/>
    </StackLayout>

</ContentPage>

CodeBehindPage.xaml.cs

    public partial class CodeBehindPage : ContentPage
    {
        public CodeBehindPage()
        {
            InitializeComponent();

            btn登入.Clicked += (s, e) =>
            {
                MyLabel.Text = MyEntry.Text;
            };
        }
    }

使用 自己實作 INPC 方式來開發

INPC = INotifyProPertyChanged
也就是底下的三個方法,都是使用 MVVM 的架構下來進行開發,因此,在您的專案中,就會有 View (宣告 XAML 標記的地方,也就是每個葉面要顯示的視覺項目)、ViewModel(用來撰寫這個頁面的所有處理邏輯程式碼地方)。
在 ViewModel 內的 .NET 屬性 (Property),將會透過 INPC 介面實作出來的事件,通知 View 綁定的控制項,更新最新的資料內容;當然,當 View 中的控制項屬性內容有異動的時候,當然,也會即時性的更新到 ViewModel 所綁定的 .NET 屬性物件。
在頁面中的 XAML 中,首先須要宣告一個命名空間,這裡是 ViewModel,指向這個頁面所在的 C# 命名空間位置。
接著,您需要透過 XAML 或者 Code Behind 程式碼,定義這個頁面 BindingContext 屬性值,也就是要指向到這個頁面的 ViewModel 物件上。
若您使用 XAML 的方式,需要使用底下方法,這裡將會產生一個 INPCPageViewModel 物件,並且設定給 ContentPage.BindingContext。
<ContentPage.BindingContext>
    <ViewModel:INPCPageViewModel/>
</ContentPage.BindingContext>
若您使用 Code Behind 的方式,您需要在這個頁面的建構式內,使用底下程式碼,來設定這個頁面的 BindingContext 屬性值。
這兩種方式,您可以任選其一來實作。
    public partial class INPCPage : ContentPage
    {
        public INPCPage()
        {
            InitializeComponent();

            //由於不是使用 Prism 框架,所以,BindingContext 要用到的 ViewModel,必須要自己來設定,當然,也可以在 Code Behind 端來設定
            BindingContext = new INPCPageViewModel();
        }
    }
對於按鈕控制項,我們將不再使用按鈕的事件來撰寫處理邏輯,而是使用這些控制項所提供的 Command 屬性。當我們將 .NET 的 ICommand 物件綁訂到這些 Command 屬性上之後,一旦使用者按下按鈕之後,就會執行這些命令。
而我們,僅需要在這些命令中,處理 ViewModel 內宣告的各個 .NET 屬性物件;只要您變更了這些 .NET 屬性物件值,就會透過了 INPC 機制,送出變動事件到 View 中,而所綁定這個 .NET 屬性的控制項之屬性值,也就會更著做出更新。

INPCPage.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:ViewModel="clr-namespace:XFDataBinding.ViewModels"
             x:Class="XFDataBinding.Views.INPCPage"
             Title="自己實作 INPC">

    <!--
    由於不是使用 Prism 框架,所以,BindingContext 要用到的 ViewModel,
    必須要自己來設定,當然,也可以在 Code Behind 端來設定
    -->
    <ContentPage.BindingContext>
        <ViewModel:INPCPageViewModel/>
    </ContentPage.BindingContext>

    <StackLayout
        Margin="20,0"
        >
        <Entry 
            HorizontalOptions="FillAndExpand"
            Text="{Binding MyEntry}"/>

        <Label
            HorizontalOptions="FillAndExpand"
            Text="{Binding MyLabel}"/>

        <Button Text="登入" Command="{Binding 登入Command}"/>
    </StackLayout>


</ContentPage>
在 ViewModel 類別中,您需要使用與實作這個 INotifyPropertyChanged 介面。
接著,您需要在每個 ViewModel 類別內,撰寫一個 OnPropertyChanged 方法,這個方法會用於,當您綁定於 View 中的 .NET 屬性有異動的時候,需要呼叫這個方法,發出一個事件,通知 View 中的視覺項目之屬性要更新其內容。
另外,您需要使用 Visual Studio 所提供的程式碼片段 propfull,產生一個完整的 .NET 屬性定義,這裡將會包含了屬性與儲存這個屬性的欄位物件。
接著,修改這個屬性的 set 存取子 (Accessor),判斷當該屬性值有異動的時候,需要呼叫 OnPropertyChanged 方法。
關於 C# 的屬性,可以參考 使用屬性 (C# 程式設計手冊)

INPCPageViewModel.cs

    public class INPCPageViewModel : INotifyPropertyChanged
    {
        #region Repositories (遠端或本地資料存取)

        #endregion

        #region ViewModel Property (用於在 View 中作為綁定之用)

        #region 基本型別與類別的 Property
        private string _MyEntry;

        public string MyEntry
        {
            get { return _MyEntry; }
            set
            {
                if (_MyEntry != value)
                {
                    _MyEntry = value;
                    OnPropertyChanged("MyEntry");
                }
            }
        }

        private string _MyLabel;

        public string MyLabel
        {
            get { return _MyLabel; }
            set {
                if (_MyLabel != value)
                {
                    _MyLabel = value;
                    OnPropertyChanged("MyLabel");
                }
            }
        }

        public ICommand 登入Command { get; set; }
        #endregion

        #region 集合類別的 Property

        #endregion

        #endregion

        #region Field 欄位

        #region ViewModel 內使用到的欄位
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

        #region 命令物件欄位
        #endregion

        #region 注入物件欄位
        #endregion

        #endregion

        #region Constructor 建構式
        public INPCPageViewModel()
        {

            #region 頁面中綁定的命令
            登入Command = new Command(() =>
            {
                MyLabel = MyEntry;
            });
            #endregion
        }

        #endregion

        #region 設計時期或者執行時期的ViewModel初始化
        #endregion

        #region 相關事件
        #endregion

        #region 相關的Command定義
        #endregion

        #region 其他方法

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                // 若 PropertyChanged 有被綁定,則將會執行這個事件,
                // 以進行頁面控制項的內容更新
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }

使用 Prism 的 BindableBase 類別 方式來開發

當您使用 Prism 作為您 MVVM 開發技術的框架,就可以大幅降低使用 INPC 方法的開發複雜度,最起碼不用每個頁面都要自己撰寫一個 OnPropertyChanged 方法與實作 INPC 介面。
Prism 使用了 BindableBase 類別,只要您的 ViewModel 繼承了這個類別,Prism 自動幫忙處理相關 INPC 需要實作的相關內容。
這個時候,當您要宣告一個用於綁定的 .NET Property,僅需要在set 存取子呼叫 BindableBase 類別的 SetProperty 方法即可。
不過,每個 .NET Property 都需要使用一個欄位來儲存這個 .NET 屬性的值,並且,需要修改 set 存取子的方法程式碼。
        private string _MyEntry;
        /// <summary>
        /// MyEntry
        /// </summary>
        public string MyEntry
        {
            get { return this._MyEntry; }
            set { this.SetProperty(ref this._MyEntry, value); }
        }
另外,由於 Prism 自動幫我們設定了這個頁面所需要用到的 ViewModel,並設定到這個頁面的 BindingContext 屬性內。
這歸咎於頁面 XAML 中,有了這個宣告
prism:ViewModelLocator.AutowireViewModel="True"
上面的宣告,使用了 Prism 提供的一個 ViewModelLocator 機制,自動依據現在 View 的名稱,找到相對應的 ViewModel 類別,並且使用這個類別產生出一個物件,最後,設定到這個頁面的 BindingContext 上。

PrismPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFDataBinding.Views.PrismPage"
             Title="使用 Prism 的 BindableBase 類別">

    <StackLayout
        Margin="20,0"
        >
        <Entry 
            HorizontalOptions="FillAndExpand"
            Text="{Binding MyEntry}"/>

        <Label
            HorizontalOptions="FillAndExpand"
            Text="{Binding MyLabel}"/>

        <Button Text="登入" Command="{Binding 登入Command}"/>
    </StackLayout>

</ContentPage>

PrismPageViewModel.cs

    public class PrismPageViewModel : BindableBase, INavigationAware
    {
        #region Repositories (遠端或本地資料存取)

        #endregion

        #region ViewModel Property (用於在 View 中作為綁定之用)

        #region 基本型別與類別的 Property

        #region MyEntry
        private string _MyEntry;
        /// <summary>
        /// MyEntry
        /// </summary>
        public string MyEntry
        {
            get { return this._MyEntry; }
            set { this.SetProperty(ref this._MyEntry, value); }
        }
        #endregion

        #region MyLabel
        private string _MyLabel;
        /// <summary>
        /// MyLabel
        /// </summary>
        public string MyLabel
        {
            get { return this._MyLabel; }
            set { this.SetProperty(ref this._MyLabel, value); }
        }
        #endregion

        #endregion

        #region 集合類別的 Property

        #endregion

        #endregion

        #region Field 欄位

        #region ViewModel 內使用到的欄位
        #endregion

        #region 命令物件欄位

        public DelegateCommand 登入Command { get; set; }

        #endregion

        #region 注入物件欄位
        private readonly INavigationService _navigationService;
        #endregion

        #endregion

        #region Constructor 建構式
        public PrismPageViewModel(INavigationService navigationService)
        {

            #region 相依性服務注入的物件

            _navigationService = navigationService;
            #endregion

            #region 頁面中綁定的命令
            登入Command = new DelegateCommand(() =>
            {
                MyLabel = MyEntry;
            });
            #endregion

            #region 事件聚合器訂閱

            #endregion
        }

        #endregion

        #region Navigation Events (頁面導航事件)
        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public async void OnNavigatedTo(NavigationParameters parameters)
        {
            await ViewModelInit();
        }
        #endregion

        #region 設計時期或者執行時期的ViewModel初始化
        #endregion

        #region 相關事件
        #endregion

        #region 相關的Command定義
        #endregion

        #region 其他方法

        /// <summary>
        /// ViewModel 資料初始化
        /// </summary>
        /// <returns></returns>
        private async Task ViewModelInit()
        {
            await Task.Delay(100);
        }
        #endregion

    }

使用 Fody 方式來開發

對於使用 Prism 的框架下,已經大幅簡化了資料綁定的程式碼做法,不過,還有一個方法,可以讓您的 ViewModel 程式碼更加的清爽。
您需要在核心 PCL 專案內,安裝這個 PropertyChanged.Fody NuGet 套件。
之後,您僅需要在您的 ViewMdoel 類別外,使用 C# 屬性 ImplementPropertyChanged,如此,當您需要宣告要綁定於 XAML 中的 .NET 屬性的時候,就可以使用底下的程式碼寫法(可以使用 Visual Studio 提供的 prop 程式碼片段來快速產生這些程式碼,這樣,是不是更加清爽與簡單了呢?
        public string MyEntry { get; set; }
        public string MyLabel { get; set; }

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFDataBinding.Views.FodyPage"
             Title="使用 Fody">

    <StackLayout
        Margin="20,0"
        >
        <Entry 
            HorizontalOptions="FillAndExpand"
            Text="{Binding MyEntry}"/>

        <Label
            HorizontalOptions="FillAndExpand"
            Text="{Binding MyLabel}"/>

        <Button Text="登入" Command="{Binding 登入Command}"/>
    </StackLayout>

</ContentPage>

#

    [ImplementPropertyChanged]
    public class FodyPageViewModel : INavigationAware
    {
        #region Repositories (遠端或本地資料存取)

        #endregion

        #region ViewModel Property (用於在 View 中作為綁定之用)

        #region 基本型別與類別的 Property
        public string MyEntry { get; set; }
        public string MyLabel { get; set; }
        #endregion

        #region 集合類別的 Property

        #endregion

        #endregion

        #region Field 欄位

        #region ViewModel 內使用到的欄位
        #endregion

        #region 命令物件欄位

        public DelegateCommand 登入Command { get; set; }

        #endregion

        #region 注入物件欄位
        private readonly INavigationService _navigationService;
        #endregion

        #endregion

        #region Constructor 建構式
        public FodyPageViewModel(INavigationService navigationService)
        {

            #region 相依性服務注入的物件

            _navigationService = navigationService;
            #endregion

            #region 頁面中綁定的命令
            登入Command = new DelegateCommand(() =>
            {
                MyLabel = MyEntry;
            });
            #endregion

            #region 事件聚合器訂閱

            #endregion
        }

        #endregion

        #region Navigation Events (頁面導航事件)
        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public async void OnNavigatedTo(NavigationParameters parameters)
        {
            await ViewModelInit();
        }
        #endregion

        #region 設計時期或者執行時期的ViewModel初始化
        #endregion

        #region 相關事件
        #endregion

        #region 相關的Command定義
        #endregion

        #region 其他方法

        /// <summary>
        /// ViewModel 資料初始化
        /// </summary>
        /// <returns></returns>
        private async Task ViewModelInit()
        {
            await Task.Delay(100);
        }
        #endregion

    }

2017/04/24

簡化 MVVM 的綁定屬性設計

當我們在進行 MVVM 開發設計的時候,在 ViewModel 內需要在 View 中綁定的屬性,都要實作 INotifyPropertyChanged 這個事件;當我們在使用 Prism 開發框架的時候,雖然,提供了一個 BindableBase 類別,來幫助我們實作出 INotifyPropertyChange 事件,可是,在宣告 ViewModel 的屬性時候,還是有些麻煩。

了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式

因此,PropertyChanged.Fody 這個 NuGet 套件出現了,它簡化了 ViewModel 的設計。在官方文件中舉個例子:
在這裡,我們僅需要在 ViewModel 類別中,使用了 ImplementPropertyChanged 這個屬性宣告,在整個 ViewModel 內,每個要綁定到 View 中的屬性,僅需要使用 .NET Property 的方式來宣告即可。
[ImplementPropertyChanged]
public class Person 
{        
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}
PropertyChanged.Fody 會在編譯時期,自動為我們產生出相對應的 INotifyPropertyChanged 事件實作,如同底下程式碼所示:
public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
傑克,這是不是太神奇了呀,看到這個套件,我立馬想要來在 Prism 框架中來實作、測試看看。
我建立了一個 View ,這個頁面中,有兩個資料綁定的屬性,與一個命令綁定屬性。
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="PrismUnityApp7.Views.MainPage"
             Title="MainPage">
    <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
        <Label Text="{Binding Title}" />
        <Entry Text="{Binding entry}" />
        <Button Text="Set" Command="{Binding SetCommand}"/>
    </StackLayout>
</ContentPage>
此時,我的 ViewModel 變得清爽多了;經過執行,還真的可以運作。
    [ImplementPropertyChanged]
    public class MainPageViewModel : INavigationAware
    {
        public string Title { get; set; }
        public string entry { get; set; }

        public DelegateCommand SetCommand { get; set; }

        public MainPageViewModel()
        {
            SetCommand = new DelegateCommand(() =>
            {
                Title = entry;
            });
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {
            if (parameters.ContainsKey("title"))
                Title = (string)parameters["title"] + " and Prism";
        }
    }
sharp
有興趣的人,可以參可 PropertyChanged.Fody

2017/04/22

Xamarin FAQ 2-28 : 使用 StackLayout, 控制項之間會有空白

問題

當您使用 StackLayout 版面配置,裡面設定了多個控制項,不論採用水平或者垂直排列方式,您都會發現到各控制項中,都會保留一定的空白空間,可是,我該如何移除這些空間呢?

解答

Xamarin.Forms 的 StackLayout 預設在各控制項間預留 6 個單位,因此,若您不想要這些保留空間,您可以在 StackLayout 內,使用 Spacing="0" 就可以消除這些預留空白了
Xamarin-跨平台手機應用程式設計入門-粉絲團

Xamarin FAQ 2-27 : 在XAML內,設定多個列舉值

問題

有些 XAML 的屬性是個列舉,可以設定多個列舉值,例如, FontAttributes 就是其中一列,可是,當我需要在 XAML 中定義多個列舉值的時候,我該如何定義呢?

解答

您可以參考底下用法,多個列舉值,可以使用逗號 , 將其分開即可
        <Label Text="多奇數位創意有限公司" FontAttributes="Italic,Bold"/>
Xamarin-跨平台手機應用程式設計入門-粉絲團

2017/04/21

使用 Xamarin + Azure 無法進行 Facebook 身分驗證

最近,公司有個專案需要提供 Facebook 身分驗證的機制,當然,就會想到使用 Xamarin.Auth 這個套件來使用;我之前在 Xamarin 工作紡電子書中,也有交代如何透過 Xamarin.Auth ,進行市面上一般社群網站的 oAuth2 的身分驗證開發方法。
可是,很不幸的,不論是依據電子書所交代的步驟,或者直接開啟墊子書中所提供的範例專案,都無法進行身分驗證。
問題發生在,當輸入完成 Facebook 的帳號與密碼之後,因為是第一次使用,需要需要同意使用 Facebook App,不過,此時,畫面是被凍結住的,在這個網頁中,您無法點選任何操作與按鈕。
這個時候,當然會想到,會不會是 Xamarin.Auth 這個套件出了問題,不過,我之前也寫過了使用 Azure Mobile App 的身分驗證電子書,理所當然的,就會打開該電子書的範例專案來測試看看;不幸的是,兩者的情況都是一樣,網頁被凍結住了。
經過一番調查,看到這篇文章:
原來又是 Facebook 動了手腳,只有在 iOS 的環境中,無法正常地進行 Facebook 的身分驗證,而同樣的程式,在 Android 平台下,卻是可以正常運作的。
因此,按照該篇文章的指示,進行調整 Azure Mobile 的 MOBILESERVICESDOTNET_EXTENSION_VERSION 服務,最後的情況,當然也是一樣的,畫面被凍結了。
Update the MOBILESERVICESDOTNET_EXTENSION_VERSION value from 1.0.478 to 1.0.479.
這個時候,突然想到9年以前處理的問題,便針對 iOS 的 WebKit 調整他的 User-Agent Webviews and User-Agent strings ,將 iOS 環境中的 WebKit 瀏覽器的 User-Agent 調整成為 Facebook for iOS User-Agent string : Mozilla/5.0 (iPhone; CPU iPhone OS 8_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12D508 [FBAN/FBIOS;FBAV/27.0.0.10.12;FBBV/8291884;FBDV/iPhone7,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/8.2;FBSS/3; FBCR/vodafoneIE;FBID/phone;FBLC/en_US;FBOP/5]
底下為設定 WebKit User-Agent 的方法
string userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 8_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12D508 [FBAN/FBIOS;FBAV/27.0.0.10.12;FBBV/8291884;FBDV/iPhone7,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/8.2;FBSS/3; FBCR/vodafoneIE;FBID/phone;FBLC/en_US;FBOP/5]";

NSDictionary dictionary = NSDictionary.FromObjectAndKey(NSObject.FromObject(userAgent), NSObject.FromObject("UserAgent"));
NSUserDefaults.StandardUserDefaults.RegisterDefaults(dictionary);
最後,當然是如期解決了問題,iOS 平台下,可以使用 Azure Mobile App 來進行 Facebook 的身分驗證了。

Xamarin應用程式,一執行就閃退的解決方案

在這個星期,遇到兩次這樣的問題,花了一些時間來處理這類問題,不過,其實這樣的問題,有一個比較簡潔的處理方式。

了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
當您的應用程式一啟動之後,就發現會自然的閃退,這個時候,若您有設定了中斷點,不論您設定在哪個地方(原生專案或者核心PCL專案內),似乎,您的程式都無法在這些中斷點停下來,還是會自動閃退。
通常來說,您會看到底下的錯誤訊息
Objective-C exception thrown.  Name: NSInternalInconsistencyException Reason: Application windows are expected to have a root view controller at the end of application launch
不論您的程式是剛剛開始進行開發,還是已經寫了很多內容了,這個時候,請都不要緊張,我強烈建議您採用 刪去法 開始進行這類問題除錯。
首先,請先建立一個空白的 ContentPage,並且在 App.xaml.cs 內,指定 MainPage 到這個 ContentPage;並且,再度執行一次,看看是否可以正常運作。
若您還是遇到不幸的情況,請在原生專案的進入點方法內,看看是否有執行甚麼初始化的方法,若有的話,請記得將其註解起來;接著再度執行一次,看看能否正常執行。
經過這樣幾次,不斷地將程式碼刪去之後,應該可以找到問題所在。
我遇到的兩個情況分別是:
  1. XAML 語法錯誤,導致執行時期,要顯示這個頁面的時候,造成執行時期的閃退。
  2. 有個靜態屬性,當進行物件值初始化的時候,發生了異常,導致程式直接閃退;當然,這個類別內的其他靜態屬性物件,也無法被存取了。

iOS 取消 ATS App Transport Security 限制

預設,Xamarin.iOS 的App,需要使用 Https 來進行網路存取,可是,有些時候,您期望還是要使用不加密的方式來存取網路;這個時候,您可以在 Info.plist 檔案內,加入底下的設定:
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
更多這方面的說明,可以參考 App Transport Security

如何清空 Mac 電腦中的 Provisioning Profile 快取資料

有些時候,若您修改的 Provisioning Profile 設定資訊後,發現到在 Windows 端的 Visual Studio 沒有辦法取得最新的 Provisioning Profile 設定資訊。
有個終極作法,那就是,在 Mac 電腦端,把這些快取的 Provisioning Profile 檔案先全部刪除掉,接著,再透過 Xcode 將其全部從 Apple Developer 網站中下載下來。
您可以切換到底下目錄,將這個目錄下的所有物件全部都刪除掉即可
~/Library/MobileDevice/Provisioning\ Profiles