XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2019/04/13

使用 Xamarin.Essentials 進行檔案的同步或非同步存取

使用 Xamarin.Essentials 進行檔案的同步或非同步存取

Xamarin.Essentials 提供非常多豐富好用的功能,其中一個 [檔案系統協助程式] 功能,可以用於在應用程式所在的儲存空間內使用快取與資料目錄存取功能,一旦取得了該特定目錄下的檔案之後,就可以使用 .NET Framework 的 System.IO 命名空間下的 API,進行目錄的新增、建立或刪除,也可以針對檔案進行建立、寫入、刪除的功能。
當在開發一個行動應用 App 的時候,往往需要能夠將這個 App 當時的執行狀態寫入到裝置內,等到下次這個 App 再度重新啟動的時候,可以從裝置的儲存體中將資料讀取回來。絕大部分的行動開發者應該都會直接想使用到 SQLite 來做到這樣的事情,但是作者卻比較偏好輕巧的解決方案,那就是把程式中的 .NET 物件經過 Json.NET 序列化之後,把這些 JSON 文字寫入到檔案內;當想要取回的時候,只需要從檔案把這些字串讀取出來,接著透過 Json.NET 反序列化這些 JSON 字串,這樣,當初的 .NET 中使用的物件,就還原回來了。
由於 Xamarin.Forms 屬於一個 GUI 類型的應用程式,也就是說,所有要針對 UI 相關控制項變更的行為需求,都需要在 UI 執行緒 Thread 下來進行執行,否則會發生例外異常;因此,當要進行檔案存取的動作是在 UI 執行緒執行的時候,會有可能因為檔案存取的動作需要花費些時間,因此,會造成整個應用程式的畫面不太流暢;故,這個時候可以將這些檔案 I/O 相關的動作,以非同步的方式來使用,就可以解決這些問題。
在這個範例中,將會說明如何使用同步與非同步的方式來進行檔案的存取。

建立一個 使用 Xamarin.Essentials 進行檔案存取的 專案

  • 開啟 Visual Studio 2019 程式
  • 當 Visual Studio 2019 開始 視窗 出現之後,請點選左下角的 [建立新專案] 選項
  • 當 [建立新專案] 對話窗出現之後,請在中間最上方的搜尋文字輸入盒中輸入 [prism] 關鍵字,搜尋所有與 Prism 有關的專案樣板
  • 請選擇 [Prism Blank App (Xamarin.Forms)] 這個專案樣板
  • 當出現 [設定新的專案] 對話窗,請在 [專案名稱] 輸入 [FileAccess]
  • 最後點選該對話窗右下方的 [建立] 按鈕
  • 現在將會看到 [PRISM PROJECT WIZARD] 對話窗,請勾選 ANDROID, iOS, UWP 三個行動裝置平台,接著在底下 [Container] 下拉選單,選擇 Unity 項目
  • 最後,點選 [CREATE PROJECT] 按鈕,以便產生 Xamarin.Forms 專案

安裝需要用到的 PropertyChanged.Fody NuGet 套件

  • 當這個 Xamarin.Forms 專案建立成功之後,請在該方案中,找到 Xamarin.Forms 使用的專案,請在該專案中,使用滑鼠右擊 [相依性] 節點,選擇 [管理 NuGet 套件] 選項
  • 在 [NuGet: XXX] 視窗中,點選 [瀏覽] 標籤頁次,並且在下方的搜尋文字輸入盒中,輸入 [propertychanged.fody] 關鍵字,搜尋出這個 NuGet 套件
  • 當出現 [PropertyChanged.Fody] NuGet 套件,請點選該套件,並且點選右方的 [安裝] 按鈕,將這個套件安裝到 Xamarin.Forms 專案內
  • 請查看 Xamarin.Forms 專案內,並沒有 [FodyWeavers.xml] 這個檔案,因此,使用滑鼠右擊 Xamarin.Forms 專案節點,選擇 [建置] 選項
  • 當建置完成之後,在這個 Xamarin.Forms 專案內將會出現 [FodyWeavers.xml] 檔案

安裝需要用到的 Newtonsoft.Json NuGet 套件

  • 在 [NuGet: XXX] 視窗中,搜尋文字輸入盒中,輸入 [Newtonsoft.Json] 關鍵字,搜尋出這個 NuGet 套件
  • 當出現 [Newtonsoft.Json] NuGet 套件,請點選該套件,並且點選右方的 [安裝] 按鈕,將這個套件安裝到 Xamarin.Forms 專案內

安裝需要用到的 Xamarin.Essentials NuGet 套件

  • 在 [NuGet: XXX] 視窗中,搜尋文字輸入盒中,輸入 [Xamarin.Essentials] 關鍵字,搜尋出這個 NuGet 套件
  • 當出現 [Xamarin.Essentials] NuGet 套件,請點選該套件,並且點選右方的 [安裝] 按鈕,將這個套件安裝到 Xamarin.Forms 專案內

修正因為安裝 Xamarin.Essentials 帶來的錯誤

現在,可以從 Visual Studio 2019 的錯誤視窗中,看到底下的錯誤訊息
NU1107    偵測到 Xamarin.Android.Support.Compat 有版本衝突。請將 Xamarin.Android.Support.Compat 28.0.0.1 直接安裝/參考到專案 FileAccess.Android 來解決此問題。 
 FileAccess.Android -> FileAccess -> Xamarin.Essentials 1.1.0 -> Xamarin.Android.Support.Compat (>= 28.0.0.1) 
 FileAccess.Android -> Xamarin.Android.Support.Design 27.0.2.1 -> Xamarin.Android.Support.Compat (= 27.0.2.1).    FileAccess.Android    D:\Vulcan\GitHub\Xamarin2019\FileAccess\FileAccess\FileAccess.Android\FileAccess.Android.csproj    1
想要解決此一問題:
  • 使用滑鼠右擊方案節點,選擇 [管理方案的 NuGet 套件]
  • 點選 [更新] 標籤頁次
  • 勾選該標籤頁次內的所有項目
  • 點選右上方的更新按鈕,就可以升級這些套件到最新版本了

建立資料存取模型

  • 滑鼠右擊 Xamarin.Forms 專案,選擇 [加入] > [新增資料夾]
  • 將新增資料夾的名稱設定為 [DataModels]
  • 滑鼠右擊 [DataModels] 資料夾,選擇 [加入] > [類別]
  • 在 [新增項目] 對話窗下方的 [名稱] 欄位中,輸入 [UserInfo]
  • 點選右下方的 [新增] 按鈕
  • 將底下程式碼填入到這個新建立的類別檔案內
C Sharp / C#
using System;
using System.Collections.Generic;
using System.Text;

namespace FileAccess.DataModels
{
    public class UserInfo
    {
        public string Account { get; set; }
        public string Password { get; set; }
    }
}

修正 View 與 ViewModel

  • 在 Xamarin.Forms 專案內的 [Views] 資料夾內,找到 MainPage.xaml 檔案,並且打開它
  • 使用底下 XAML 語言替換掉這個檔案內的 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="FileAccess.Views.MainPage"
             Title="檔案存取之開發">

    <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"
                 Margin="20">
        <Label Text="帳號" />
        <Entry Text="{Binding Account}" Placeholder="請輸入帳號"/>
        <Label Text="密碼" />
        <Entry Text="{Binding Password}" Placeholder="請輸入密碼"/>
        <Label Text="檔案路徑" />
        <Button Text="清空輸入" Command="{Binding CleanCommand}"/>
        <Label Text="{Binding FilePath}" FontSize="14" />
        <StackLayout Orientation="Horizontal">
            <Button Text="同步讀取" Command="{Binding SyncFileReadCommand}"/>
            <Button Text="同步寫入" Command="{Binding SyncFileWriteCommand}"/>
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Button Text="簡易非同步讀取" Command="{Binding AsyncSimpleFileReadCommand}"/>
            <Button Text="簡易非同步寫入" Command="{Binding AsyncSimpleFileWriteCommand}"/>
        </StackLayout>
        <StackLayout Orientation="Horizontal">
            <Button Text="非同步方法讀取" Command="{Binding AsyncFileReadCommand}"/>
            <Button Text="非同步方法寫入" Command="{Binding AsyncFileWriteCommand}"/>
        </StackLayout>
    </StackLayout>

</ContentPage>
  • 在 Xamarin.Forms 專案內的 [ViewModels] 資料夾內,找到 MainPageViewModel.cs 檔案,並且打開它
  • 使用底下 C# 敘述替換掉這個檔案內的 C# 敘述
C Sharp / C#
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FileAccess.ViewModels
{
    using System.ComponentModel;
    using System.IO;
    using System.Threading.Tasks;
    using FileAccess.DataModels;
    using Newtonsoft.Json;
    using Prism.Events;
    using Prism.Navigation;
    using Prism.Services;
    using Xamarin.Essentials;

    public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Account { get; set; }
        public string Password { get; set; }
        public string FilePath { get; set; }
        public DelegateCommand CleanCommand { get; set; }
        public DelegateCommand SyncFileReadCommand { get; set; }
        public DelegateCommand SyncFileWriteCommand { get; set; }
        public DelegateCommand AsyncSimpleFileReadCommand { get; set; }
        public DelegateCommand AsyncSimpleFileWriteCommand { get; set; }
        public DelegateCommand AsyncFileReadCommand { get; set; }
        public DelegateCommand AsyncFileWriteCommand { get; set; }
        string filename = "User.txt";
        private readonly INavigationService navigationService;

        public MainPageViewModel(INavigationService navigationService)
        {
            this.navigationService = navigationService;
            CleanCommand = new DelegateCommand(() =>
            {
                Account = ""; Password = "";
            });
            SyncFileReadCommand = new DelegateCommand(() =>
            {
                string path = Path.Combine(FileSystem.AppDataDirectory, "Datas");
                if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
                FilePath = Path.Combine(path, $"Sync{filename}");
                if (File.Exists(FilePath))
                {
                    var content = File.ReadAllText(FilePath);
                    var userInfo = JsonConvert.DeserializeObject<UserInfo>(content);
                    Account = userInfo.Account;
                    Password = userInfo.Password;
                }
            });
            SyncFileWriteCommand = new DelegateCommand(() =>
            {
                string path = Path.Combine(FileSystem.AppDataDirectory, "Datas");
                if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
                FilePath = Path.Combine(path, $"Sync{filename}");
                var userInfo = new UserInfo()
                {
                    Account = Account,
                    Password = Password,
                };
                var content = JsonConvert.SerializeObject(userInfo);
                File.WriteAllText(FilePath, content);
            });
            AsyncSimpleFileReadCommand = new DelegateCommand(async () =>
            {
                string path = Path.Combine(FileSystem.AppDataDirectory, "Datas");
                if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
                FilePath = Path.Combine(path, $"AsyncSimple{filename}");
                if (File.Exists(FilePath))
                {
                    var content = await Task.Run(() =>
                    {
                        return File.ReadAllText(FilePath);
                    });
                    var userInfo = JsonConvert.DeserializeObject<UserInfo>(content);
                    Account = userInfo.Account;
                    Password = userInfo.Password;
                }
            });
            AsyncSimpleFileWriteCommand = new DelegateCommand(async () =>
            {
                string path = Path.Combine(FileSystem.AppDataDirectory, "Datas");
                if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
                FilePath = Path.Combine(path, $"AsyncSimple{filename}");
                var userInfo = new UserInfo()
                {
                    Account = Account,
                    Password = Password,
                };
                var content = JsonConvert.SerializeObject(userInfo);
                await Task.Run(() =>
                {
                    File.WriteAllText(FilePath, content);
                });
            });
            AsyncFileReadCommand = new DelegateCommand(async () =>
            {
                string path = Path.Combine(FileSystem.AppDataDirectory, "Datas");
                if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
                FilePath = Path.Combine(path, $"Async{filename}");
                if (File.Exists(FilePath))
                {
                    using (var fileStream = File.Open(FilePath, FileMode.Open))
                    {
                        using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
                        {
                            var content = await streamReader.ReadToEndAsync();
                            var userInfo = JsonConvert.DeserializeObject<UserInfo>(content);
                            Account = userInfo.Account;
                            Password = userInfo.Password;
                        }
                    }
                }
            });
            AsyncFileWriteCommand = new DelegateCommand(async () =>
            {
                string path = Path.Combine(FileSystem.AppDataDirectory, "Datas");
                if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
                FilePath = Path.Combine(path, $"Async{filename}");
                using (var fileStream = File.Create(FilePath))
                {
                    using (var streamWriter = new StreamWriter(fileStream, Encoding.UTF8))
                    {
                        var userInfo = new UserInfo()
                        {
                            Account = Account,
                            Password = Password,
                        };
                        var content = JsonConvert.SerializeObject(userInfo);
                        await streamWriter.WriteAsync(content);
                    }
                }
            });
        }

        public void OnNavigatedFrom(INavigationParameters parameters)
        {
        }

        public void OnNavigatedTo(INavigationParameters parameters)
        {
        }

        public void OnNavigatingTo(INavigationParameters parameters)
        {
        }

    }
}

同步檔案讀寫的程式碼用法

當要寫入 .NET 物件到檔案內,在這裡範例中,將會把使用者輸入的帳號與密碼寫入到 UserInfo 類別物件內,接著使用 JsonConvert.SerializeObject(userInfo) 敘述將這個 .NET 物件轉換成為 JSON 字串表示內容。
然後透過 Xamarin.Essentinals 的 檔案系統協助程式 所提供的 API,取得該應用程式專屬的檔案存取沙箱目錄,這裡使用 FileSystem.AppDataDirectory 來取得,在這個沙箱目錄下所建立的檔案,僅僅提供該應用程式來存取,其他的應用程式、甚至該手機的使用者,無法看到與讀寫這些存在於沙箱目錄內的檔案。
在 Android 平台下,這個沙箱目錄會類似這樣的字串:/data/user/0/com.companyname.appname/files/Datas/SyncUser.txt
在 iOS 平台下,這個沙箱目錄會類似這樣的字串:/Users/vulcan/Library/Developer/CoreSimulator/Devices/EED56A19-C96E-4AF5-A5FA-83E07AB7E2A3/data/Containers/Data/Application/177E5C36-AC6F-450E-97EF-DA1AF562D29F/Library/Datas/SyncUser.txt
有了一個檔案系統下的目錄,接著便可以使用 System.IO 命名空間所提供的 File.WriteAllText API 來將剛剛產生的 JSON 字串寫入到指定的目錄下,而想要讀取特定檔案,可以使用 File.ReadAllText API 來讀取該檔案內的所有字串內容,再取得這些內容之後,便可以使用 JsonConvert.DeserializeObject(content) 這個敘述,將原先的 JSON 內容,還原成為 .NET 物件。
不過,在 .NET Standard 2.0 下,對於 System.IO 命名空間下的 File.WriteAllText / File.ReadAllText 這兩個 API,僅提供了同步呼叫的使用方式,若想要使用非同步方式來讀寫文字檔案內容,可以參考底下兩種做法;至於為什麼要使用非同的方式來進行檔案的讀寫工作呢?這一切都是要保持該 Xamarin.Forms 應用程式的 GUI 以最佳流暢的狀態下來執行。

簡單將同步檔案讀寫的程式碼轉換成為 Task 物件之用法

首先,最簡單的做法就是把這些同步運作的程式碼,指定到 Task.Run(() =>{}) 這個靜態方法內的委派方法內,因此,就會得到一個 Task 的物件,代表一個非同步的工作。現在,可以在這個方法內使用 await 關鍵字來等候剛剛取得的 工作 Task 類別物件,不過,要再方法函式內使用 await 關鍵字,需要在該方法回傳型別前,加入 async 這個修飾詞,並且該函式的迴船型別僅能為 Task, Task, void 這三種而已,若指定了其他型別,會造成編譯時期的錯誤。

非同步檔案讀寫的程式碼用法

當然 System.IO 命名空間內還提供了其他的關於檔案存取的非同步 API,在此,可以透過 File.Creeate 方法建立一個 FileStream 的物件,準備針對這個產生的檔案進行寫入的動作;有了這個 FileStream 物件,接著使用 StreamWriter 類別,使用剛剛的 FileStream 物件來建立起一個 StreamWriter 物件,如此,便可以使用 await streamWriter.WriteAsync 這樣的敘述來將文字內容,以非同步呼叫方式來寫入到檔案內。
反之,若要使用非同步方式讀取出檔案內的內容,可以使用 File.Open API,開啟指定的檔案(當然,最好還是事先檢查一下該檔案是否存在於該裝置的檔案系統內),便可以得到一個 FileStream 的物件,然後使用該物件來建立起一個 StreamReader 物件,如此,便可以使用 await streamReader.ReadToEndAsync() 這樣的非同步程式碼寫法,將檔案內的字串讀取出來,接著,使用 JsonConvert.DeserializeObject() 方法,把剛剛讀取出來的字串,還原成為 .NET 中的物件。

建置與執行和測試結果

現在,可以分別在不同的行動平台下來執行這個專案,只要將內容寫入到應用程式沙箱目錄下的檔案,除非該應用程式移除後又重新安裝起來,否則,該檔案會持續存在於這個裝置內,就算該應用程式進行升級動作,這些檔案也同樣的會持續存在。因此,可以嘗試將已經啟動的 App,強制進行關閉,讓這個 App 不再存在於裝置記憶體中,接著重新再度啟動,將會發現到,還是可以看到剛剛寫入的檔案內容。

在 Android 上進行測試

  • 請設定預設起始專案為 Android 的專案
  • 指定要在哪個模擬器或者實體裝置下來執行這個專案
  • 在工具列上點選率色三角形按鈕,執行這個 Android 專案
  • 底下是在 Android 平台下執行結果

在 iOS 上進行測試

  • 請設定預設起始專案為 iOS 的專案
  • 在工具列視窗中,在平台方案之下拉選單中,選擇 [iPhoneSimulator] 這個選項
  • 在平台方案右方綠色三角形之啟動按鈕,點選該按鈕右方的下拉選單的黑色三角形符號,現在可以看到該 Mac 電腦上所有可用的模擬器,在此選擇 [iPhone 8 iOS 12.2] 這個選項
  • 現在可以直接點選剛剛的綠色按鈕,啟動這個專案在 iOS 模擬器上來執行
  • 底下是在 iOS 平台下執行結果




2019/04/12

Visual Studio 2019 for Xamarin 之安裝與設定 Part5 - 測試與確認開發環境可以進行 Xamarin.Forms 專案開發與結論

Visual Studio 2019 for Xamarin 之安裝與設定 Part5 - 測試與確認開發環境可以進行 Xamarin.Forms 專案開發與結論

Visual Studio 2019 for Xamarin 之安裝與設定 Part5 - 測試與確認開發環境可以進行 Xamarin.Forms 專案開發與結論

對於已經具備擁有 .NET / C# 開發技能的開發者,可以使用 Xamarin.Forms Toolkit 開發工具,便可以立即開發出可以在 Android / iOS 平台上執行的 App;對於要學習如何使用 Xamarin.Forms & XAML 技能,現在已經推出兩本電子書來幫助大家學這這個開發技術。
這兩本電子書內包含了豐富的逐步開發教學內容與相關觀念、各種練習範例,歡迎各位購買。
Xamarin.Forms 電子書
想要購買 Xamarin.Forms 快速上手 電子書,請點選 這裡

想要購買 XAML in Xamarin.Forms 基礎篇 電子書,請點選 這裡

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


您必須要確實進行這些檢查與測試工作,確保您的 Xamarin.Forms 開發環境可以正常運作。
  • 測試可以建立 Xamarin.Forms 專案
  • 建置與執行 Android 專案
  • 建置與執行 iOS 專案
  • 建置與執行 UWP 專案

測試可以建立 Xamarin.Forms 專案

  • 請在開啟 Visual Studio 2019 程式,並且,點選功能表
    檔案 > 新增 > 專案
    Visual Studio 2019 建立新的專案
  • 在 新增專案 對話窗中,請在中間上方的文字輸入盒中輸入 Prism 搜尋出所有與 Prism 有關的專案範本
    在中間選項中,點選 Prism Blank App (Xamarin.Forms),最後點選對話窗右下方的 下一步 按鈕
    新增專案 對話窗
  • 當 設定新的專案 對話窗出現後,在該對話窗的相關欄位,填入適當的文字,最後點選對話窗右下方的 建立 按鈕
    設定新的專案 對話窗
  • 出現了 PRISM PROJECT WIZARD 對話窗
    請依照需求,勾選需要支援的行動狀裝置平台,並且,在下方的 Container 下拉選單欄位,選 Unity
    完成後,請點選該對話窗下方的 CREATE PROJECT 按鈕
    New Cross Platform App 對話窗
  • 此時卻出現了 檢閱方案動作 對話窗,其內容為
    需要 Visual Studio 更新
    下列專案需要平台 SDK (UAP, Version=10.0.16299.0),但其未安裝,或為 Visual Studio 日後更新的一部分
    請安裝平台 SDK,已開啟這些檔案。
    您也可以更新您的專案,指定需要安裝的 SDK:
    Target version: Windows 10, version 1809 (10.0; 組建 17763)
    所以,請點選 安裝 按鈕,進行安裝所需要的 SDK
    New Cross Platform App 對話窗
    此時,Visual Studio 2019 對話窗將會出現,請點選右下方的 安裝 按鈕
    New Cross Platform App 對話窗
    現在,Windows 10 SDK (10.0.16299.0) 將會進行安裝
    New Cross Platform App 對話窗

建置與執行 Android 專案

  • 當 Xamarin.Forms for Prism 專案建立完成後,請使用滑鼠右擊 Android 專案
    選擇 設定為起始專案
    在方案總管中設定預設起始專案
  • 此時,您會在 Visual Studio 2019 中間上方區域,看到 啟動專案已經設定為 Android 專案,並且要執行的裝置為 VS Emulaor 5.2-inch Marshmallow (6.0.0) XXHDPI Phone (Android 6.0 API 23) 這個模擬器
    請點選有綠色三角形的模擬器項目,開始建置與在這個模擬器上來執行
    執行 Android 專案
  • 由於第一次進行專案建置,需要下載許多 NuGet 套件,因此,需要花費一些時間,請耐心等候一下,底下是成功執行完成的畫面
    Xamarin.Forms 的 Android 專案成功執行結果
  • 停止這個 Android 專案的執行 (點選工具列上的紅色正方形按鈕)

建置與執行 iOS 專案

  • 滑鼠右擊 iOS 專案
    選擇 設定為起始專案
  • 建議顯示 iOS 工具列
    請點選功能表 [檢視] > [工具列] ,請勾選 [iOS] 這個功能表項目
    顯示 iOS 輔助工具列圖示
    現在,可以在 Visual Studio 2019 最上方的工具列中,看到 iOS 使用的相關工具圖示
    Pair to Mac 圖示
  • 點選上方圖片中,紅色箭頭指向的圖示, [Pair to Mac - Disconnected]
    當然,這個操作也是可以從功能表中點選 [工具] > [iOS] > [與 Mac 配對]
    從功能表中來啟用 與 Mac 配對 功能
  • 現在 與 Mac 配對 對話窗將會出現
    然而,Visual Studio 將會搜尋網路上是否有可以遠端存取的 Mac 電腦,若有存在的話,該台 Mac 電腦就會出現在清單中
    自動掃描網路並且是有開啟遠端存取的 Mac 電腦
  • 在 Select a Mac 清單內,找到您的 Mac 電腦,並且使用滑鼠雙擊這個項目,此時,將會出現 [連線到 Mac] 對話窗,請在這個對話窗中,輸入遠端登入 Mac 電腦的使用者名稱與密碼,完成後,點選 [Login] 按鈕
    輸入要遠端登入到 Mac 電腦的使用者帳號與密碼
    不過,在這裡強烈建議在 Visual Studio 的 [輸出] 視窗中,切換 [顯示輸出來源] 清單項目成為 [Xamarin],因為,接下來要對遠端 Mac 電腦進行各種登入、更新等動作,都可以在這裡看到相關日誌訊息,最重要的是,當您無法連線到遠端的 Mac 電腦或著覺得連線速度有些緩慢,便可以從這些輸出日誌內容,找到真正發生的原因。
    Windows 電腦與 Mac 電腦存取的日誌
    像是底下的為一個登入 Mac 電腦失敗的情境,在這裡顯示出 嘗試存取通訊端被拒絕,因為存取權限不足 錯誤訊息,此時,可以從 Visual Studio 輸出視窗中,看到更加詳細的資訊。
Checking host configuration for connecting to '李進興的 MacBook Air'...
Checking SSH configuration...
正在檢查可用的磁碟空間...
正在檢查 Mono 安裝...
正在檢查 Xamarin iOS 安裝...
Checking host configuration for connecting to '李進興的 MacBook Air'...
Host '李進興的 MacBook Air' is configured correctly
Starting connection to '李進興的 MacBook Air'...
Starting connection to '李進興的 MacBook Air'...
Starting disconnection from 李進興的 MacBook Air...
Starting disconnection from 李進興的 MacBook Air...
The connection to '李進興的 MacBook Air' has been finished
Couldn't connect to 李進興的 MacBook Air. Please try again.
與 Mac 電腦連線失敗範例
  • 當與遠端 Mac 電腦連線成功之後,工具列上的 [Pair to Mac] 圖示將會變成綠色螢幕,而且在 [與 Mac 配對] 對話窗中,剛剛連線的 Mac 電腦項目的右方,也會出現一個已經連線的圖示,也就是說,現在可以開始建置與執行 iOS 的專案了。
    與 Mac 電腦連線成功的畫面
  • 請點選功能表的 [工具] > [選項],當 選項 對話窗顯示之後,請在左邊清單,展開 [Xamarin] 節點,找到 [iOS 設定] 項目,請確認右方的 [遠端 Simulator 到 Windwos] 選項要有勾選,最後點選右下方的 [確定] 按鈕
    啟用 遠端 Simulator 到 Windwos
  • 請在 Visual Studio 2019 最上方的工具列中,找到 [方案平台] 下拉選項,請在這裡選擇 [iPhoneSimulator] 這個選項,此時,右方下拉選項就會顯示出遠端 Mac 電腦中的各式模擬器清單,選擇一個適合您的模擬器項目,接著點選該項目的綠色按鈕,開始建置與執行 iOS 專案。
    切換使用 iOS 模擬器來進行除錯
  • 底下將會是成功執行 iOS 專案的畫面,也就是說,當要模擬器來進行 iOS 專案執行或除錯的時候,iOS 模擬器將會直接顯示在 Windows 電腦中,如此,就不需要在進行開發過程,同時關注兩個系統螢幕上出現的內容了。
    Xamarin.Forms 的 iOS 專案成功執行結果
  • 停止 iOS 專案的執行

建置與執行 UWP 專案

  • 使用滑鼠右擊 UWP 專案
    選擇 設定為起始專案
  • 點選 Visual Studio 2019 最上方工具列綠色三角形的本機電腦
    底下將會是成功執行 UWP 專案的畫面
    Xamarin.Forms 的 UWP 專案成功執行結果
  • 停止 UWP 專案的執行

結論

若您的 Visual Studio 2019 可以成功建立 Xamarin.Forms 專案,可以建置在 Android / iOS / UWP 平台下執行,那麼,恭喜您,您的 Visual Studio 2019 開發環境,已經可以正常進行 Xamarin.Forms 跨平台專案開發了




2019/04/11

Visual Studio 2019 for Xamarin 之安裝與設定 Part4 - 安裝 Android 使用的模擬器


Visual Studio 2019 for Xamarin 之安裝與設定 Part1 - 安裝前的準備工作

Visual Studio 2019 for Xamarin 之安裝與設定 Part1 - 安裝前的準備工作
Visual Studio 2019 for Xamarin 之安裝與設定 Part2 - Visual Studio 2019 安裝與相關相關設定 1
Visual Studio 2019 for Xamarin 之安裝與設定 Part3 - Visual Studio 2019 安裝與相關相關設定 2
Visual Studio 2019 for Xamarin 之安裝與設定 Part4 - 安裝 Android 使用的模擬器
Visual Studio 2019 for Xamarin 之安裝與設定 Part5 - 測試與確認開發環境可以進行 Xamarin.Forms 專案開發與結論




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


在 Xamarin 開發工具下,可以選擇使用 Visual Studio 內建的 Visual Studio for Android Emulator 模擬器 與 Google Android 原生模擬器 這兩個模擬器的其中一個,當然,也可以選擇其他類型的 Android 模擬器,不過,對於無法在電腦上執行模擬器的情境下,是可以選擇使用實體裝置來進行開發和測試;不過,前面提到的兩者差異在於前者比較不耗用 CPU 資源,但是,卻沒有預設安裝 Google Play Server,這對於有些開發應用上會比較麻煩,因為這些應用程式需要裝置上有運行 Google Play Server。
由於這裡將會使用 Google Android 原生模擬器與搭配 Intel HAXM 虛擬化技術,所以在安裝 Visual Studio 2019 的過程中,將會都安裝起來了,現在可以直接來使用與設定這個模擬器。
  • 安裝與啟動 Google Android 原生模擬器

安裝與啟動 Google Android 原生模擬器

  • 開啟 Visual Studio 2019 程式
  • 點選啟動後的視窗右下方的 不使用程式碼繼續 連結
  • 請在 Visual Studio 程式中,點選功能表 工具 > Android > Android Device Manager
  • 接著會出現 使用者帳戶控制 對話窗,請點選 是 按鈕
    使用者帳戶控制 對話窗
  • 當 Android Device Manager 視窗出現後,請在第一個項目 VisualStudio_android-25_x86_phone ,使用滑鼠右擊這個項目,接著選擇 編輯選項
    修改 Android Device Manager 的模擬器項目
  • 此時會出現一個新的對話視窗,顯示這個模擬器之相關設定內容
    VisualStudio_android-25_x86_phone 對話窗
  • 請點選左下方的 基本設備 下拉選單,選擇 Nexus 6 項目,現在將會看到一個警告對話窗,請點選 更改和重置 按鈕
    更改基本設備將重置所有屬性
  • 在 VisualStudio_android-25_x86_phone 對話窗的左下方,勾選 Google Play Store 選項,最後點選該對話視窗右下方的保存按鈕。
    VisualStudio_android-25_x86_phone 對話窗
  • 當出現 接受授權 對話窗,請點選 接受 按鈕。
    若沒有出現這個對話窗,可以跳過,繼續下一個設定動作
    接受授權 對話窗
  • 當模擬器下載完成之後,請點選 啟動 按鈕。
    模擬器下載完成
  • 接著會出現 未安裝模擬器程式實用工具 對話窗,請點選 是 按鈕。
    未安裝模擬器程式實用工具 對話窗
  • 當 接受授權 對話窗出現之後,請點選右下角的 接受 按鈕
    接受授權 對話窗
  • 當 Android Emulator 軟體安裝完成之後,請重新點選 啟動 按鈕
  • 現在可以開始使用 Google Android 所提供的模擬器,該模擬器中已經預設安裝了 Google Paly 服務應用程式
    Google Android 所提供的模擬器成功啟動