XAML in Xamarin.Forms 基礎篇 電子書

特別說明

2017/07/05

從網路下載 APK 檔案,並且於 Xamarin.Forms 專案內進行升級動作

在這份筆記中,將會進行如何透過 Xamarin.Forms 的 App,從網路上下載最新的 APK 檔案到手機上,接著,進行這個 APK 檔案的安裝與升級動作。
在這樣的需求中,我們需要解決與處理底下這些需求:
  • 如何從網路上,透過指定的 URL ,取得最新的 APK 檔案。
  • 當取得 APK 檔案之後,要能夠儲存到手機記憶卡中。
  • 最後,要能夠執行這個 APK 檔案,便可以進行 App 的升級。

如何從網路上,透過指定的 URL ,取得最新的 APK 檔案

這當然需要使用 .NET 的 HttpClient 類別所產生出來的物件,使用這個物件的 GetStreamAsync 方法,便可以透過非同步的方式,取得遠端 Web Server 上的這個 APK 檔案。
由於這個方法 GetStreamAsync 會回傳一個 Stream 物件,我們便可以將這個物件,傳遞到原生 Android 專案內,就可以使用原生 Android SDK API,將這些檔案內容,寫入到 Android 專案內。
            DownloadCommand = new DelegateCommand(async () =>
            {
                HttpClientHandler handle = new HttpClientHandler();
                HttpClient client = new HttpClient(handle);
                Title = "正在下載中";
                using (var fooStream = await client.GetStreamAsync("https://github.com/vulcanlee/test/raw/master/com.vulcanlab.task.apk"))
                {
                    _APK.GenApkFile(fooStream);
                }

                Title = "已經下載完成";
            });

取得 APK 檔案之後,要能夠儲存到手機記憶卡中

由於 PCLStorage 僅能夠提供讀寫 App 的沙箱儲存體內,寫入到這些沙箱內的檔案,任何人與相關程式,是無法存取這個檔案的;因此,我們需要把 APK 檔案寫入到一個公開的目錄下,在這裡,我們將會寫入到 下載 資料夾內。
要做到這樣的工作,我們需要透過相依性服務注入功能,將 Android 原生平台下實作的介面物件,注入到 核心PCL 專案內來使用。
我們需要先在核心PCL專案內,建立一個介面:
在這個介面內,宣告了兩個方法需要在原生 Android 平台下來實作,一個是將剛剛從網路上取 APK 檔案的 Stream 物件內容,寫入到 Android 裝置記憶卡內;另外一個是將剛剛下載下來的檔案,進行安裝。
    public interface IAPK
    {
        void InstallAPK();

        void GenApkFile(Stream downloadStream);
    }
IAPK 介面在 Android 平台下實作的類別如下所示:
  • GenApkFile
    這裡使用了 Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString(); 敘述,取得了手機中下載資料夾路徑,接著判斷該檔案是否存在,若不存在,則會產生出這個檔案,若已經存在,則會直接開啟,等候寫入這個檔案;最後,使用 CopyToAsnyc 方法,針對兩個 Stream 來複製,完成檔案寫入的需求。
[assembly: Xamarin.Forms.Dependency(typeof(SelfInstAPK.Droid.Infrastructures.APK_Droid))]
namespace SelfInstAPK.Droid.Infrastructures
{
    public class APK_Droid : IAPK
    {
        public string DownlaodPath = "";
        public string Filename = "new.apk";
        public string FullFilename = "";
        FileStream fooStream;

        public void GenApkFile(Stream downloadStream)
        {
            DownlaodPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString();
            FullFilename = Path.Combine(DownlaodPath, Filename);

            if (File.Exists(FullFilename) == false)
            {
                Directory.CreateDirectory(DownlaodPath);
                fooStream= File.Create(FullFilename);
            }
            else
            {
                fooStream= File.OpenWrite(FullFilename);
            }


            using (FileStream fs = fooStream)
            {
                downloadStream.CopyTo(fs);
            }
        }

        public void InstallAPK()
        {
            Intent setupIntent = new Intent(Intent.ActionView);
            setupIntent.SetDataAndType(Android.Net.Uri.FromFile(new Java.IO.File(FullFilename)), "application/vnd.android.package-archive");
            setupIntent.AddFlags(ActivityFlags.NewTask);

            var context = Android.App.Application.Context;
            context.StartActivity(setupIntent);
        }
    }
}

最後,要能夠執行這個 APK 檔案,便可以進行 App 的升級

這個實作介面的另外一個方法就是,InstallAPK,我們建立一個 Intent 物件,設定好相關參數,最後,使用 StartActivity 啟動安裝這個 APK 需求。

使用 Prism 自動注入這個介面實作物件

我們不需要使用 Xamarin.Forms 內建的 DependencyService 提供的靜態方法來注入實作物件,我們僅需要在 ViewModel 內的建構式,填入這個介面參數,Prism 便會自動幫您注入實作好的物件,這樣,您就可以在 PCL 專案內,將資料寫到 Android 的目錄下。
        IAPK _APK;

        public MainPageViewModel(IAPK apk)
        {
            _APK = apk;
            ...
        }

其他說明

若您沒有將 APK 檔案寫入到空開可以存取的目錄下,則當進行安裝 APK 檔案的時候,會出現如下圖錯誤訊息畫面。
Parse Error

There was a problem parsing the package.
而正常的情況下,會出現底下的畫面,讓您可以安裝這個 APK 檔案。

沒有留言:

張貼留言