以前、Silverlight の Out of Browser で動くアプリ作っていたのですが、xapファイルをWEBサーバー上に置いて動的に機能の追加をしたりしてました。
そういったことが Xamarin でも可能なのか試してみました。
調べたらだいぶ前に既に試された方いるようですけど、せっかく試したので投稿します → https://forums.xamarin.com/discussion/2294/assembly-load-is-it-possible
結論
最初に結論です。
iOSは無理です
Androidは条件により可能です
とりあえず、業務で利用されるのはお勧めはしません。
作ってみる
こんなコードになりました。
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
Device.BeginInvokeOnMainThread(async () =>
{
try
{
await Task.Delay(1000);
var file = await LoadDLL("https://dllを置いてるサーバー/SampeClassLibrary.dll");
var assembly = Assembly.LoadFrom(file.FullPath);
// 読み込みたいクラスを読み込む
dynamic instance = assembly.CreateInstance("SampeClassLibrary.Flash");
// 今回のサンプルクラスはShowというメソッドを持っている
instance.Show(1000, Root);
}
catch (Exception e)
{
await DisplayAlert("Error", e.ToString(), "OK");
}
});
}
public static async Task<IFile> LoadDLL(string url)
{
// NetStandardStorageを使ってdllをローカルに1回保存
var folder = CrossStorage.FileSystem.LocalStorage;
var file = folder.CreateFile("dynamictest.dll", Plugin.NetStandardStorage.Abstractions.Types.CreationCollisionOption.ReplaceExisting);
HttpClient client = new HttpClient();
var response = await client.GetAsync(url);
byte[] body = new byte[1024 * 1024];
using (var stream = await response.Content.ReadAsStreamAsync())
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
var length = stream.Read(body, 0, body.Length);
if (length > 0)
{
ms.Write(body, 0, length);
}
else
{
break;
}
}
file.WriteAllBytes(ms.ToArray());
}
return file;
}
検証してみる
実際に動かしてみます
iOS
iOSはシミュレーターでは動きましたが実機では無理でした。
理由は iOS は AOT(Ahead-Of-Time) のためです。
中途半端な知識で書くと嘘になるかもしれないので、ここでは AOT については説明しません。
詳しくは検索してみてください。
Android
私の環境のシミュレーターが起動できなかったのでシミュレーターでは試していませんが、実機で動くことを確認しました。
ストア経由で配布した場合でも動くかどうかは不明です。
最初に「条件により」と書いたのは、Android でも AOT コンパイルのオプションがあるので AOT の場合は無理なんじゃないかと予想してます。
Visual Studio がエンタープライズ版じゃないと試せないので今回は確認していません。
諸々バージョンや依存関係等考えると、実際にこれを運用するのは大変そうだなと思います。
まとめ
動的に機能追加/修正したい場合は、おとなしく WebView 使うとか、ReactNative+Expo 使うとかを検討した方が良いかと思いました。