在這份筆記中,將會進行如何透過 Xamarin.Forms 的 App,從網路上下載最新的 APK 檔案到手機上,接著,進行這個 APK 檔案的安裝與升級動作。
在這樣的需求中,我們需要解決與處理底下這些需求:
- 如何從網路上,透過指定的 URL ,取得最新的 APK 檔案。
- 當取得 APK 檔案之後,要能夠儲存到手機記憶卡中。
- 最後,要能夠執行這個 APK 檔案,便可以進行 App 的升級。
這份筆記的測試專案是在 https://github.com/vulcanlee/xamarin-forms-develop-notes-example/tree/master/SelfInstAPK
如何從網路上,透過指定的 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 檔案。
沒有留言:
張貼留言