メモ書きなのでしばらく更新が続くと思いますんで悪しからず
ローカルに落とす
- HTTPで落としてきてアプリ用ストレージに保存。
- それぞれAPIのリファレンスを見ればわかると思いますので……
HttpClient
-
System.Net.Http.HttpClient
でクロスプラットフォームで書ける。URLを打てばストリームが落ちてくる。細かい加工が必要な場合System.Net.Http.HttpClientHandler
を使う(参考)。 - キャッシュされるのを防ぐ場合、下記コードを追加
var httpClientHandler = new HttpClientHandler { };
var httpClient = new HttpClient(httpClientHandler);
httpClient.DefaultRequestHeaders.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue();
httpClient.DefaultRequestHeaders.CacheControl.NoCache = true;
httpClient.DefaultRequestHeaders.CacheControl.NoStore = true;
- 例外は適当に拾うこと
ストレージ
落としてきたHTTPストリームをファイルストリームに流す。System.IO.IsolatedStorage
(参考)を使うかPCLStorageを使う。個人的にはPCLStorageを使用。
WebViewに表示する
BaseUrl
- アプリに内包させる場合
-
PCLStorage
やSystem.IO.IsolatedStorage
を使って動的に落とす場合
その他ハマってた点
以下に列挙するのはいろいろ試してた部分で、OSによって必要かもしれないし必要ないかもしれない
XamarinのWebViewのカスタムビューで内部用のアクセス権限を与える
VS2017で動くコードは下記の通り(任意ファイル名のクラスを追加)。どれも完全に同じではないが、ほぼ正しく書いてあるのは公式のブログ記事とこちら。
yourcode.xaml.cs側でWebViewを継承したCustomWebViewが定義されていて、yourcode.xamlでの指定もYourProject.CustomWebViewで指定する必要あり
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(YourProject.CustomWebView), typeof(YourProject.Droid.CustomWebViewRenderer))]
namespace YourProject.Droid
{
public class CustomWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control == null) return;
//javascriptのfileスキームへのアクセス許可
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.Settings.AllowFileAccessFromFileURLs = true;
// 後述
Control.AddJavascriptInterface(new MyJSInterface(Context), "CSharp");
// チェック用
// System.Console.WriteLine("OnElementChanged CustomWebViewRenderer");
}
}
// 後述
class MyJSInterface : Java.Lang.Object
{
Context context;
public MyJSInterface(Context context)
{
this.context = context;
}
[Java.Interop.Export]
[Android.Webkit.JavascriptInterface]
public void ShowToast(string s)
{
System.Console.WriteLine("ShowToast:" + s);
}
}
}
androidでblobやmailto:が使えない
これらを使うというマニア向けの解説。これやこれやこれやこれを参考にしたが一向に埒が明かなかった。
→暫定的解決策:JS側からC#のコードを呼ぶ方法を使うことにした。サンプルの場合、JSにwindow.CSharp.ShowToastという関数が定義される(string型の引数をつけたければつけられる)ので、その存在確認をして、存在していればそちらを使い、そうでなければ通常のブラウザ用の処理を行うという分岐をつけた。サイト側にオフライン閲覧アプリ専用のコードを組み込む必要があり用途が限られてしまうが、今回はこれで事足りる。
ajaxのステータスコードが0である場合
ローカルリソースにfile://などでアクセスする場合、xmlhttprequestのステータスコードが成功時にも0で返ってくることがある(参考)。しかしdataのほうを見ると中身がしっかり返ってきているので、中身を見て判断するしかない。
HttpListenerを使って内部に疑似HTTPサーバを組む
(本格的に組んでるわけではないですが、AndroidとiOSでは機能することは確認しました。なぜか本家のほうのUWPでは動かない。Windows Phone 8では当然ダメ)