XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2017/05/20

Pull 所有目錄的 Git Repository

因為工作需要,所以,使用了兩台電腦,可是,之前經常要把這兩台電腦上的 Git Repository 做同步,都是使用手動方式,一個目錄一個目錄的下 Pull 命令。
今天正好有空,根據網路上找到的參考資訊,修改成我自己需要的同步 Script。
我的狀況是,我都會把 Repositories 都放在同一個目錄下,透過底下的 PowerShell Script,便可以逐一針對每個目錄,執行 Pull 命令,對我來說,真的節省了太多時間了。
$git = $env:programfiles+"\Git\cmd\git.exe";
Write-Host $git
if (!$git) {
  Write-Host "Something went wrong. Please enter the path to git.cmd or git.exe:";
  $git = Read-Host;
  Set-Variable -Name git -Value $git;
}
ls -name -Exclude *.* | foreach {Write-Host $_;cd .\$_ ; & $git pull origin master  2> $null ; cd ..}
Write-Host "Done.";
cmd /c pause | out-null

2017/05/16

使用 Iconize 在螢幕上顯示字體圖示

若想要在您的 Xamarin.Forms 應用程式中顯示出字體圖示,例如, Font Awesome,在以往,您都需要每個專案內做關於這個字體的設定,並且需要根據平台需求,產生一個客製化的控制項。如今,想要做到這件事情,不再需要這麼麻煩的程序了,您只需要使用 Iconize Plugin 這個套件,就可以做到了。
在這篇文章中,將會測試如何在三個平台 Android/iOS/UWP,透過 Iconize Plugin 的幫助,設計出一個輸入帳號與密碼的頁面。
感謝 acaliaro 寫的這篇文章 How to create a nice rouded icon ,讓我可以順利測試出如何使用 Iconize 這個套件的使用方式。

安裝與設定相關套件

進行 Iconize 相關套件的安裝

在這裡,我們已經使用 Prism Template Pack 建立起一個支援 Android/iOS/UWP 的 Xamarin.Forms 方案,我們首先要做的事情,就是要安裝 Iconize Plugin 相關套件。
首先,請將這兩個套件,安裝到所有的專案內 Xam.Plugin.Iconize / Xam.FormsPlugin.Iconize
接著,可以依據您的喜好或者需求,選擇適合您的字體圖示,安裝相對應的套件
在這裡,我將會使用 Xam.Plugin.Iconize.FontAwesome 這個 Font Awesome 字型圖示作為展示範例,因此,請在您的方案中,除了核心PCL專案除外,各個原生專案都要安裝 Xam.Plugin.Iconize.FontAwesome這個套件。
若您在安裝相關自行套件 (Xam.Plugin.Iconize.FontAwesome)的時候,有勾選核心PCL專案,則會出現這個錯誤訊息: 無法安裝封裝 'Xam.Plugin.Iconize.FontAwesome 1.0.10'。您正嘗試將此封裝安裝到以 '.NETPortable,Version=v4.5,Profile=Profile259' 為目標的專案,但該封裝不包含任何與架構相容的組件參考或內容檔。如需詳細資訊,請連絡封裝作者。
這個時候,請取消核心PCL專案,勾選其他原生專案,重新安裝這個套件即可。
若想要進一步了解這些字體圖示有哪些內容,可以參考

進行 Iconize 的原生專案初始化設定

Android 專案的設定

請在 Android 原生專案內,打開 MainActivity.cs,找到 OnCreate 方法,將程式碼置換如下:
其中,使用 .With(new Plugin.Iconize.Fonts.FontAwesomeModule()) 方法來指定需要載入的字型圖示模組;而 FormsPlugin.Iconize.Droid.IconControls.Init 則是用來進行 Xamarin.Forms 需要用到的控制項初始化。
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.tabs;
            ToolbarResource = Resource.Layout.toolbar;

            base.OnCreate(bundle);

            #region 進行 Iconize 套件的初始化
            Plugin.Iconize.Iconize
                .With(new Plugin.Iconize.Fonts.FontAwesomeModule());
            FormsPlugin.Iconize.Droid.IconControls.Init(Resource.Layout.toolbar, Resource.Layout.tabs);
            #endregion

            global::Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication(new App(new AndroidInitializer()));
        }
您可以一次安裝多個字體套件,這個時候,僅需要連續呼叫 With 方法即可,類似這樣:
            Plugin.Iconize.Iconize
                      .With(new Plugin.Iconize.Fonts.FontAwesomeModule())
                      .With(new Plugin.Iconize.Fonts.IoniconsModule());

iOS 專案的設定

請在 iOS 原生專案內,打開 AppDelegate.cs,找到 FinishedLaunching 方法,將程式碼置換如下:
其中,使用 .With(new Plugin.Iconize.Fonts.FontAwesomeModule()) 方法來指定需要載入的字型圖示模組;而 FormsPlugin.Iconize.iOS.IconControls 則是用來進行 Xamarin.Forms 需要用到的控制項初始化。
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            #region 進行 Iconize 套件的初始化
            Plugin.Iconize.Iconize
                .With(new Plugin.Iconize.Fonts.FontAwesomeModule());
            FormsPlugin.Iconize.iOS.IconControls.Init();
            #endregion

            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App(new iOSInitializer()));

            return base.FinishedLaunching(app, options);
        }
另外,我們還需要修正 `Info.plist' 檔案內容,在這個檔案內,需要加入底下宣告。
  <key>UIAppFonts</key>
  <array>
    <string>iconize-fontawesome.ttf</string>
    <string>iconize-material.ttf</string>
    <string>iconize-meteocons.ttf</string>
    <string>iconize-typicons.ttf</string>
  </array>

UWP 專案的設定

請在 UWP 原生專案內,打開 App.xaml.cs,找到 OnLaunched 方法,將程式碼置換如下:
其中,使用 .With(new Plugin.Iconize.Fonts.FontAwesomeModule()) 方法來指定需要載入的字型圖示模組;而 FormsPlugin.Iconize.UWP.IconControls 則是用來進行 Xamarin.Forms 需要用到的控制項初始化。
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {

#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            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();

                rootFrame.NavigationFailed += OnNavigationFailed;

                #region 進行 Iconize 套件的初始化
                Plugin.Iconize.Iconize
                    .With(new Plugin.Iconize.Fonts.FontAwesomeModule());
                FormsPlugin.Iconize.UWP.IconControls.Init();
                #endregion


                Xamarin.Forms.Forms.Init(e);

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

Xamarin.Forms 的測試頁面

在這個範例中,我們需要設計一個使用者登入頁面,裡面需要讓使用者輸入帳號與密碼。我們利用 Grid Layout 將螢幕切割成四塊區域。
在核心PCL專案中,我們使用 MainPage 做為測試頁面;因為在這個頁面內,需要使用 Iconize 所提供的 IconLabel 控制項,因此,需要先加入可以參考到這個控制項的命名空間,我們需要在 ContentPage 內,加入 xmlns:iconize="clr-namespace:FormsPlugin.Iconize;assembly=FormsPlugin.Iconize" 這樣的宣告,如此,在這個頁面內,就可以使用 iconize 前置詞,之後就可以引用 Iconize 所提供的控制項。
當我們需要顯示 Font Awesome 字型圖示的時候,就可以使用這樣的方式 <iconize:IconLabel Text="fa-user" TextColor="Blue" /> 顯示出一個藍色使用者圖示在螢幕上。至於 Text 屬性內的文字,您可以在 Font Awesome 網站中,找到不同圖示所代表的文字。
<?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"
             xmlns:iconize="clr-namespace:FormsPlugin.Iconize;assembly=FormsPlugin.Iconize"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFIconize.Views.MainPage"
             Title="使用者登入">

    <Grid
        Margin="30"
        HorizontalOptions="Fill" VerticalOptions="Center"
        >
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <iconize:IconLabel
            Grid.Row="0" Grid.Column="0"
            HorizontalOptions="Center" VerticalOptions="Center"
            FontSize="60"
            Text="fa-user" TextColor="Blue" />
        <Entry
            Grid.Row="0" Grid.Column="1"
            HorizontalOptions="Fill" VerticalOptions="Center"
            Placeholder="請輸入帳號"/>

        <iconize:IconLabel
            Grid.Row="1" Grid.Column="0"
            HorizontalOptions="Center" VerticalOptions="Center"
            FontSize="60"
            Text="fa-keyboard-o" TextColor="Blue" />
        <Entry
            Grid.Row="1" Grid.Column="1"
            HorizontalOptions="Fill" VerticalOptions="Center"
            Placeholder="請輸入密碼"/>
    </Grid>
</ContentPage>

進行測試

Android

底下是我們在 Android 平台下執行結果螢幕截圖
Iconize Android

iOS

底下是我們在 iOS 平台下執行結果螢幕截圖
Iconize Android

UWP : Windows 10 Mobile

底下是我們在 UWP 平台下執行結果螢幕截圖
Iconize Android

範例專案原始碼

2017/05/15

使用 Xamarin.UIText 進行 Android 專案的UI自動化測試技巧

當我們需要使用 Xamarin.UITest 進行您所開發的 Xamarin.Android App 做到 UI 自動測試,當然,首先,我們需要先建立一個 UI 測試應用程式 專案,您可以參考下圖,選擇 Visual C# > Cross-Platform > UI 測試應用程式(Xamarin.UItest | 跨平台),接著輸入這個測試專案名稱,最後,點選 確定 按鈕。
UI 測試應用程式(Xamarin.UItest | 跨平台)
接著,我們需要在剛剛產生的專案之中,指定要測試的 Android 專案,這裡,您會遇到兩個情況。不論是哪種情況,都建議您要間 INTERNET 這個權限啟用。
今天是 2017.05.15,根據官方的文件,Running Android 6.0 Applications from the IDE 中的描述,若要在 Android 6.0 平台下進行 UI 自動化測試,必須要使用 ApkFile 與在這個方法內加入 APK 的路徑。不過,若我使用第一個方法,也就是使用:在測試專案內,把 Xamarin.Android 專案參考,加入到這個 UI 測試專案內,原則上,不論是在 Debug / Release 模式下,都可以正常進行 UI 自動化測試。(我這裡的環境是 Windows 10 專業版 + Visual Studio 2015 Enterprise 版本)
結論就是,只要將 Android 專案參考加入到 Xamarin UITest 專案內,無視您的 Android 版本,就可以直接進行 UI 自動測試了。
請您將 Xamarin.Android 專案設定成為預設起始專案

若您使用的是 Android 6.0 以下作業系統

例如 API Level 19 的手機或者模擬器,您可以在 AppInitializer.cs 檔案中,修改成為如下程式碼。
在這裡,我們將會使用預設的 PreferIdeSettings() 方法,也就是,總是使用 IDE 中的設定。另外,我們也使用了 EnableLocalScreenshots() 方法,啟用了 Xamarin.UITest 可以進行本地端裝置的螢幕截圖功能。
    public class AppInitializer
    {
        public static IApp StartApp(Platform platform)
        {
            if (platform == Platform.Android)
            {
                return ConfigureApp
                    .Android
                    .EnableLocalScreenshots()
                    .StartApp();
            }

            return ConfigureApp
                .iOS
                .StartApp();
        }
    }
之後,您需要將您的 Xamarin.Android 專案的加入到剛剛產生的 UI 測試應用程式(Xamarin.UItest | 跨平台)專案內的參考,如此,當您建置這個 UI 測試應用程式(Xamarin.UItest | 跨平台) 專案的時候,您的 Xamarin.Android 專案,則也會自動建置到最新版本。
至於 建置模式 您可以選擇 Release 或者是 Debug 模式皆可。
另外,請切換到您要測試的模擬器或者實體手機選項;為了方便做到 UI自動測試,若您是使用模擬器,建議您先將這個模擬器啟動,並且解開螢幕保護模式,而且,請將其他 Android 模擬器關閉起來。若您是要在實體手機上做 UI 自動測試,請將所有的 Android 模擬器都先關閉起來。
接著,請先滑鼠右擊 UI 測試應用程式(Xamarin.UItest | 跨平台) 專案,選擇 重建,當完成之後,您就可以在測試總管中,看到這些可以測試的選項。
此時,您可以使用滑鼠右擊您有興趣的測試名稱,接著,選取,執行選取的測試 項目。
最後,您會看到神奇的事情發生了,您的 Xamarin.Android 應用程式,便會佈署到您指定的 Android 裝置內,而且自動啟動,然後,就會根據您所設定測試腳本,進行 UI 自動化測試。
選擇與執行UITest
若您想要在這種模式下,啟用 Xamarin Test Recorder,此時,若您的建置模式為 Debug ,則,您會遇到這樣的錯誤訊息:Failed connecting to app: Mono Shared Runtime is not supported. This can be resolved by changing the project configuration or using a Release build. 。解決方式,就如何說明內容所述,請切換到 Release 模式下,就可以使用囉。

若您使用的是 Android 6.0 的作業系統

在這裡,我們將使用 Visual Studio for Android Emulator 中的 6.0 模擬器,做為測試標的。
請您將 AppInitializer.cs 檔案中,修改成為如下程式碼。
在這裡,我們將會使用 ApkFile() 方法,來指定我們要測試的專案來源,此時的來源,就是我們要測試的 APK 檔案。另外,我們也使用了 EnableLocalScreenshots() 方法,啟用了 Xamarin.UITest 可以進行本地端裝置的螢幕截圖功能。
        public static IApp StartApp(Platform platform)
        {
            if (platform == Platform.Android)
            {
                return ConfigureApp
                    .Android
                    .ApkFile("../../../XFUITest/XFUITest.Droid/bin/Release/com.vulcanlab.xfuitest.apk")
                    .EnableLocalScreenshots()
                    .StartApp();
            }

            return ConfigureApp
                .iOS
                .StartApp();
        }
關於 ApkFile() 方法的用法,有兩個要注意的地方。
首先,您需要切換建置模式到 Release 模式下,因為,在 Androd 6.0下, Xamarin.UITest 將必須關閉 使用共用執行階段 選項。
另外,您需要手動點選 Xamarin.Android 專案,選擇執行 封存 選項,將您的 Xamarin.Android 專案封存起來,如此,在您的 Xamarin.Android 專案目錄內,就會產生一個 APK檔案。
最後使用這樣的路徑 ../../../XFUITest/XFUITest.Droid/bin/Release/com.vulcanlab.xfuitest.apk,指定 APK 檔案的路徑。這個路徑的來源,您可以參考下圖:因為,Xmarin.UITest 的專案是位於標號1的位置,而封存起來的 APK 檔案是位於標號2的位置。所以,您有兩種選擇來輸入這個路徑,第一個就是使用絕對路徑,另外一個就是使用相對路徑,透過下圖,您就可以使用相對路徑指出封存起來的 APK檔案的相對路徑了。
UITestAPK路徑
若您沒有將 Xamarin.Android 執行封存,並且做 Code Sign 的動作,那麼,當您要進行所要進行的 UI 自動化測試,就會出現底下的錯誤訊息,Visual Studio 會告訴您,無法找到您所指定的 APK 檔案。
結果訊息:     SetUp : System.Exception : ApkFile does not exist: D:\Vulcan\GitHub\temp\XFUITest_LocalAndroid\XFUITest\XFUITest.Droid\bin\Release\com.vulcanlab.xfuitest.apk
接著,請先滑鼠右擊 UI 測試應用程式(Xamarin.UItest | 跨平台) 專案,選擇 重建,當完成之後,您就可以在測試總管中,看到這些可以測試的選項。
此時,您可以使用滑鼠右擊您有興趣的測試名稱,接著,選取,執行選取的測試 項目。
最後,您會看到神奇的事情發生了,您的 Xamarin.Android 應用程式,便會佈署到您指定的 Android 裝置內,而且自動啟動,然後,就會根據您所設定測試腳本,進行 UI 自動化測試。
選擇與執行UITest
最後,再度提醒您,根據最前面的說明,剛剛的操作部分,是根據官方文件說明,特別針對 Android 6.0 平台所作的相關設定與處理動作;不過,經過測試,似乎在 Android 6.0 平台下,也可以使用第一個步驟的方法來做到。