2017-12-11

在 Visual Studio for Android Emulator 6.0 模擬器上安裝 Google Play Services GApps

在這裡,將會說明如何在 Visual Studio for Android Emulator 6.0 模擬器上,安裝與使用 Google Play Service,經過這樣的程序,您就可以在這個模擬器上,使用 Google Play Service 的相關服務與軟體了。
我們在這裡新下載與安裝了一個新的 Visual Studio for Android Emulator
Visual Studio for Android Emulator

下載與安裝 Genymotion-ARM-Tran

slation_v1.1.zip
我們需要先下載 Genymotion-ARM-Translation_v1.1.zip 這個檔案,下載完成後,請使用檔案總管拖拉到模擬器上,並且放開,這樣就會在模擬器上開始進行安裝這個 ARM 指令集轉換工具了。在這裡,您只需要點選 [Install and shut down] 按鈕,即會開始進行安裝了。
Genymotion ARM Tran
當安裝完成後,點選 [OK] 按鈕,就會關閉模擬器,此時,我們就可以重新再度啟動模擬器即可。
Genymotion ARM Tran reboot
Genymotion ARM Tran reboot

下載與安裝 gapps-L-4-21-15.zip

接著,您需要下載這個檔案 gapps-L-4-21-15.zip 這個檔案,下載完成後,請使用檔案總管拖拉到模擬器上,並且放開,這樣就會在模擬器上開始進行安裝這個 Google Play Service 了。在這裡,您只需要點選 [Install and shut down] 按鈕,即會開始進行安裝了。
安裝 GApps
當安裝完成後,點選 [OK] 按鈕,就會關閉模擬器,此時,我們就可以重新再度啟動模擬器即可。
安裝 GApps reboot
安裝 GApps reboot
當重新開機之後,您可以看到模擬器會正在進行相關軟體的最佳化設定工作。
安裝 GApps reboot

設定 GApps

一旦我們安裝好 GApps 軟體之後,請開啟 Google Play 軟體
開啟 Google Play 軟體
接著,請進行登入與驗證您的 Google 帳號,便可以在模擬器上啟用 Google Play 服務了。
開啟 Google Play 軟體
啟用帳號完成好了,就會看到 Google Play 軟體,畫面如下。
開啟 Google Play 軟體
此時,您會看到這樣的錯誤訊息 [Unfortunately, Google Play Service has stopped] ,您可以先忽略掉這個錯誤訊息,等下我們會修正。
開啟 Google Play 軟體
點選漢堡按鈕,將會看到底下的畫面,此時,若您點選 [Settings]
開啟 Google Play 軟體
在 [Setting] 畫面中,找到最後面的 [Build Versio] 這個欄位,點選它
開啟 Google Play 軟體
將會看到 [A new version of Google Play Store will be downloaded and installed] 訊息,點選 [OK] 按鈕。
開啟 Google Play 軟體
一旦 Google apps 都完成更新 (您可以選擇重新啟動模擬器,或者將 Google Play Server 應用程式強制停止運行(使用長按 Option 實體按鍵)),這個時候,進入到程式集中,您會看到 [Play Store] 的圖示已經更新了,這表示,Google Play Service 已經升級到最新版本。
開啟 Google Play 軟體
進入到 Google Paly 應用程式內,將會看到最新版本的 Google Play 應用程式畫面。
開啟 Google Play 軟體
開啟 Google Play 軟體

修正 Google Play 服務異常當掉的問題

為了要修正這個問題,我們需要下載 benzo-gapps-M-20151011-signed-chroma-r3.zip 這個檔案,並且安裝到模擬器上;因此,當下載完成這個檔案之後,請使用檔案總管拖拉到模擬器上,並且放開,這樣就會在模擬器上開始進行安裝。在這裡,您只需要點選 [Install and shut down] 按鈕,即會開始進行安裝了。
benzo-gapps-M-20151011-signed-chroma-r3.zip
benzo-gapps-M-20151011-signed-chroma-r3.zip
當安裝完成後,點選 [OK] 按鈕,就會關閉模擬器,此時,我們就可以重新再度啟動模擬器即可。
benzo-gapps-M-20151011-signed-chroma-r3.zip

完成安裝與設定

若您看到這裡,則表示您已經完成 Google Play 服務的安裝與設定工作了。
現在,您可以啟動 Google Play 應用程式,進入到設定頁面,點選 [Play Store version] 項目,就會看到現在使用的是最新版本而且再也不會看到錯誤訊息了。
GApps Google Play Service on Visual Studio for Android Emulator

2017-11-22

Xamarin.Forms / .NET Standard 體驗之旅 4 : QR Code 條碼掃描

在 Xamarin.Forms / .NET Standard 體驗之旅 4 的文章中,我們將要來測試每次進行 Xamarin.Forms 實戰課程,大家最想要學習與使用的這個 NuGet 套件:ZXing.Net.Mobile,也就是要開發出具有跨平台的條碼掃描程式。
我們從這個套件在 NuGet 官網上的內容可以看的出來,這個 NuGet 套件尚未支援 .NET Standard 標準類別庫,而是之前的可攜式 PCL 類別庫,不過,因為 .NET Standard 2.0 類別庫也支援可以使用 PCL 類別庫,因此,我們來測試看看,這個套件可否用於 Prism Template Pack 2.0.7 產生的 Xamarin.Forms 跨平台專案,並且進行一維條碼或者二維條碼 QR Code。
Realm NuGet

測試範例專案原始碼

這篇文章中的測試範例專案原始碼,您可以從這裡取得 https://github.com/vulcanlee/xamarin-forms-develop-notes-example/tree/master/XFQRCode

開始建立專案

請點選功能表 [檔案] > [新增] > [專案],此時,您會看到底下的 [新增專案] 對話視窗。
我們點選 Prism Template Pack 提供的 Xamarin.Forms 專用的專案樣板,請點選 [已安裝] > [Visual C#] > [Prism] > [Prism Blank App (Xamarin.Forms)]。
接著在名稱欄位輸入該專案名稱後,點選 [確定] 按鈕,以建立此練習專案。
然後,在 [PRISM PROJEC WIZAD] 對話窗中,選擇您要跨平台的作業系統,容器 (Container) 這裡,我個人喜歡與習慣使用 Prism,您可以選擇您自己要用的容器,最後,點選 [CREATE PROJECT] 按鈕。
.NET Standard Xamarin.Forms Project

安裝 ZXing.Net.Mobile.Forms NuGet 套件

在這裡,請使用滑鼠右建,點選剛剛建立好的共用類別庫(也就是 .NET Standard 標準類別庫)節點,選擇 [管理方案的 NuGet 套件] 項目。
在 [瀏覽] 標籤頁次上,輸入 ZXing.Net.Mobile 這個關鍵字,搜尋出這個套件。請選擇 ZXing.Net.Mobile.Forms 這個套件,要來安裝到 .NET Standard 專案內。
從下圖中,我們可以看到這個套件並不支援 .NET Standard,不過,我們還是要把這個套件安裝到 .NET Standard 專案內。
ZXing.Net.Mobile.Forms
當我們點選 [安裝] 按鈕之後,會看到 Visual Studio 會提示您這樣會安裝那些相依性的套件。
.NET Standard Xamarin.Forms Project

修正首頁頁面

我們對於這個應用程式的設計構想是這樣的,當這個應用程式一旦啟動,會在螢幕上顯示一個按鈕,和一些 Label 欄位,這些 Label 欄位是要用來顯示掃描到的條碼資訊。因此,當使用者按下 Scan... 按鈕之後,就會切換到另外一個頁面,這個頁面將會使用 ZXingScannerView 用來進行協助我們做到條碼掃描的工作。
安裝好套件之後,讓我們打開 MainPage.xaml 檔案,修改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"
             x:Class="XFQRCode.Views.MainPage"
             Title="ZXing.Net.Mobile 條碼掃描">

    <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
        <Label Text="Welcome to Xamarin Forms and Prism!" />
        <Label
            Text="條碼類型"/>
        <Label
            Text="{Binding BarcodeFormatType}"/>
        <Label
            Text="{Binding BarcodeResult}"/>
        <Button
            Text="Scan..."
            Command="{Binding ScanCommand}"/>
    </StackLayout>

</ContentPage>
接著我們打開 MainPageViewModel.cs 檔案,修正 ViewModel 的商業邏輯程式碼。
這裡特別說明的是,當掃描條碼的頁面有掃描到結果,我們是透過頁面導航機制提供的相關事件,進行讀取來自掃描頁面的掃描結果。因此,您可以觀察 OnNavigatingTo 方法,我們將會透過比對 parameters.ContainsKey("Result")表示式,確認該事件可以讀取掃描結果內容。
namespace XFQRCode.ViewModels
{

    public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string BarcodeFormatType { get; set; }
        public string BarcodeResult { get; set; }

        public DelegateCommand ScanCommand { get; set; }

        private readonly INavigationService _navigationService;

        public MainPageViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;

            ScanCommand = new DelegateCommand(() =>
            {
                _navigationService.NavigateAsync("ScanPage");
            });
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {
            if(parameters.ContainsKey("Result"))
            {
                var fooReslut = parameters["Result"] as Result;
                BarcodeFormatType = fooReslut.BarcodeFormat.ToString();
                BarcodeResult = fooReslut.Text;
            }
        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }

}

新增條碼頁面

接下來,我們需要新建立一個頁面,ScanPage,我們將會在這個頁面上使用 ZXingScannerView 用來進行協助我們做到條碼掃描的工作。
當新增完成 ScanPage 頁面,讓我們打開 ScanPage.xaml 檔案,修改XAML內容。
首先我們先宣告一個新的命名空間,xmlns:Zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms",這樣,我們就可以使用這個命名空間前置詞參考到這個 ZXingScannerView 控制項。
<?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:Zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFQRCode.Views.ScanPage"
             Title="進行條碼掃描中..."
             >

    <Grid
        >
        <Zxing:ZXingScannerView
            HorizontalOptions="Fill"
            IsAnalyzing="{Binding IsAnalyzing}"
            IsScanning="{Binding IsScanning}"
            Result="{Binding ScanResult, Mode=TwoWay}" 
            ScanResultCommand="{Binding ScanResultCommand}"
             />
        <Zxing:ZXingDefaultOverlay Opacity="0.9" ShowFlashButton="False" />
    </Grid>
</ContentPage>
接著我們打開 ScanPageViewModel.cs 檔案,修正 ViewModel 的商業邏輯程式碼。
一旦條碼有掃描到之後,將會執行 ScanResultCommand 的委派方法,不過,您需要特別注意,我們需要使用 Device.BeginInvokeOnMainThread 方法,將您要執行的程式碼,全部都指定在 UI (Main) Thread 上運行。
namespace XFQRCode.ViewModels
{

    public class ScanPageViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public bool IsAnalyzing { get; set; } = true;
        public bool IsScanning { get; set; } = true;
        public Result ScanResult { get; set; }
        private readonly INavigationService _navigationService;

        public DelegateCommand ScanResultCommand { get; set; }

        public ScanPageViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;


            ScanResultCommand = new DelegateCommand(async () =>
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    IsAnalyzing = false;
                    IsScanning = false;
                    var fooPara = new NavigationParameters();
                    fooPara.Add("Result", ScanResult);
                    // 回到上頁,並且把掃描結果帶回去
                    await _navigationService.GoBackAsync(fooPara);
                });
            });
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}

進行測試

最後,設定預設起始專案為 Android 專案,並且需要使用實體手機來進行測試。

Acr.UserDialogs 執行結果 Acr.UserDialogs 執行結果

2017-11-15

Xamarin.Forms / .NET Standard 體驗之旅 3 : 使用 PCLStorage 元件進行檔案的讀取與寫入

在 Xamarin.Forms / .NET Standard 體驗之旅 3的文章中,我們將要來測試這個最常用的 NuGet 套件:PCLStorage。
我們從這個套件在 NuGet 官網上的內容可以看的出來,這個 NuGet 套件本身是支援 PCL 可攜式類別庫的,那麼,這樣的 PCL 套件,是否可以能夠在 .NET Standard 標準類別庫,並且提供給 Xamarin.Android / Xamarin.iOS / UWP 平台系統來使用,我們來測試看看。
PCLStorage NuGet

測試範例專案原始碼

這篇文章中的測試範例專案原始碼,您可以從這裡取得 https://github.com/vulcanlee/xamarin-forms-develop-notes-example/tree/master/NETStdPCLStorage

開始建立專案

請點選功能表 [檔案] > [新增] > [專案],此時,您會看到底下的 [新增專案] 對話視窗。
我們點選 Prism Template Pack 提供的 Xamarin.Forms 專用的專案樣板,請點選 [已安裝] > [Visual C#] > [Prism] > [Prism Blank App (Xamarin.Forms)]。
接著在名稱欄位輸入該專案名稱後,點選 [確定] 按鈕,以建立此練習專案。
然後,在 [PRISM PROJEC WIZAD] 對話窗中,選擇您要跨平台的作業系統,容器 (Container) 這裡,我個人喜歡與習慣使用 Prism,您可以選擇您自己要用的容器,最後,點選 [CREATE PROJECT] 按鈕。
.NET Standard Xamarin.Forms Project

安裝 PCLStorage NuGet 套件

在這裡,請使用滑鼠右建,點選剛剛建立好的方案節點,選擇 [管理方案的 NuGet 套件] 項目。
在 [瀏覽] 標籤頁次上,輸入 PCLStorage 這個關鍵字,搜尋出這個套件。這個 PCLStorage 套件圖示為一個綠色瓶子樣子。
從下圖中,PCLStorage 套件本身僅支援 PCL Profile259,並且不支援 .NET Standard 標準類別庫,不過,沒有關係,我們嘗試繼續安裝下去,因此,在右方區域,勾選 [NETStdPCLStorage] 這個 .NET Standard 專案(您可以不用勾選原生專案)
.NET Standard Xamarin.Forms Project
.NET Standard Xamarin.Forms Project
當我們點選 [安裝] 按鈕之後,會看到 Visual Studio 會提示您這樣會安裝那些相依性的套件。
.NET Standard Xamarin.Forms Project

修正 View / ViewModel 開始使用 Acr.UserDialogs

安裝好套件之後,讓我們打開 MainPage.xaml 檔案,修改XAML內容。
這裡,我們僅在 StackLayout 版片配置內,加入3個按鈕項目,並且設定 Command 屬性,要綁定 ViewModel 內類型為 DelegateCommand 的特定物件,這三個按鈕分別會將文字輸入盒輸入的文字進行儲存到指定檔案中、清空文字輸入盒、從檔案中將內容讀取出來,並且置換掉文字輸入盒的內容。
透過這三個按鈕,我們可以確認資料是否真的有擁有儲存在手機檔案中,當然,您也可以於儲存到檔案中之後,關閉這個程式,接著重新啟動,看看是否可以從檔案中讀取出來。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="NETStdPCLStorage.Views.MainPage"
             Title="{Binding Title}">

    <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
        <Label Text="Welcome to Xamarin Forms and Prism!" />
        <Entry Text="{Binding MyEntry}"/>
        <Button Text="Save" Command="{Binding SaveCommand}"/>
        <Button Text="Clean" Command="{Binding CleanCommand}"/>
        <Button Text="Load" Command="{Binding LoadCommand}"/>
    </StackLayout>

</ContentPage>
接著我們打開 MainPageViewModel.cs 檔案,修正 ViewModel 的商業邏輯程式碼。
這裡進行檔案文字內容的讀取與寫入的程式碼,全部都是從 PCLStorage 官方網站上複製下來的,我們在此就不再多做說明。
namespace NETStdPCLStorage.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {


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

        public DelegateCommand SaveCommand { get; set; }
        public DelegateCommand CleanCommand { get; set; }
        public DelegateCommand LoadCommand { get; set; }

        public MainPageViewModel(INavigationService navigationService)
            : base(navigationService)
        {
            Title = "Main Page";

            SaveCommand = new DelegateCommand(async () =>
            {
                IFolder rootFolder = FileSystem.Current.LocalStorage;
                IFolder folder = await rootFolder.CreateFolderAsync("MySubFolder",
                    CreationCollisionOption.OpenIfExists);
                IFile file = await folder.CreateFileAsync("answer.txt",
                    CreationCollisionOption.ReplaceExisting);
                await file.WriteAllTextAsync(MyEntry);
            });
            CleanCommand = new DelegateCommand(() =>
            {
                MyEntry = "";
            });
            LoadCommand = new DelegateCommand(async () =>
            {
                IFolder rootFolder = FileSystem.Current.LocalStorage;
                IFolder folder = await rootFolder.CreateFolderAsync("MySubFolder",
                    CreationCollisionOption.OpenIfExists);
                IFile file = await folder.GetFileAsync("answer.txt");
                MyEntry = await file.ReadAllTextAsync();
            });
        }
    }
}

修正 Android 專案,進行 UserDialogs 的初始化

在這個文件中,並沒有提到需要在原生平台做任何初始化的工作,因此,我們也就不任何原生專案的修正。

進行測試

最後,設定預設起始專案為 Android 專案,並且選擇適當的模擬器或者實體手機,開始進行測試。
Acr.UserDialogs 執行結果