Xamarin.Forms WebView

Download Sampleサンプルのダウンロード

WebView は、アプリで Web および HTML コンテンツを表示するためのビューです。

In App Browser

Content

WebView では、次の種類のコンテンツがサポートされています。

  • HTML および CSS Web サイト – WebView では、JavaScript のサポートを含め、HTML と CSS を使用して記述された Web サイトが完全にサポートされています。
  • ドキュメント – WebView は各プラットフォームのネイティブ コンポーネントを使用して実装されるため、WebView は基になるプラットフォームでサポートされている形式でドキュメントを表示できます。
  • HTML 文字列 – WebView ではメモリからの HTML 文字列を表示できます。
  • ローカル ファイル – WebView では、アプリに埋め込まれた上記の種類のコンテンツのいずれかを提示できます。

Note

Windows 上の WebView では、そのプラットフォーム上の Internet Explorer でサポートされている場合でも、Silverlight、Flash、ActiveX コントロールはサポートされません。

Web サイト

インターネットから Web サイトを表示するには、WebViewSource プロパティを文字列 URL に設定します。

var browser = new WebView
{
  Source = "https://dotnet.microsoft.com/apps/xamarin"
};

Note

URL は、指定されたプロトコルで完全に形成されている必要があります (つまり、"http://" または "https://" を先頭に付ける必要があります)。

iOS と ATS

バージョン 9 以降、iOS では、既定でベスト プラクティス セキュリティを実装するサーバーとアプリケーションとの通信のみが許可されます。 セキュリティで保護されていないサーバーとの通信を有効にするには、Info.plist で値を設定する必要があります。

Note

アプリケーションでセキュリティ保護されていない Web サイトへの接続が必要な場合は、NSAllowsArbitraryLoads を使用して ATS を完全にオフにするのではなく、常に NSExceptionDomains を使って例外としてドメインを入力する必要があります。 NSAllowsArbitraryLoads は極端な緊急時にのみ使用する必要があります。

特定のドメイン (この場合は xamarin.com) で ATS 要件をバイパスできるようにする方法を次に示します。

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>xamarin.com</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <key>NSTemporaryExceptionMinimumTLSVersion</key>
                <string>TLSv1.1</string>
            </dict>
        </dict>
    </dict>
    ...
</key>

一部のドメインのみが ATS をバイパスできるようにすることをお勧めします。これにより、信頼されていないドメインで追加のセキュリティを利用しながら、信頼済みサイトを使用できます。 次に、アプリの ATS を無効にする安全性の低い方法を示します。

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads </key>
        <true/>
    </dict>
    ...
</key>

iOS 9 のこの新機能の詳細については、「アプリケーション トランスポート セキュリティ」を参照してください。

HTML 文字列

コードで動的に定義された HTML の文字列を提示する場合は、HtmlWebViewSource のインスタンスを作成する必要があります。

var browser = new WebView();
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = @"<html><body>
  <h1>Xamarin.Forms</h1>
  <p>Welcome to WebView.</p>
  </body></html>";
browser.Source = htmlSource;

WebView Displaying HTML String

上記のコードでは、@ を使用して HTML を逐語的文字列リテラルとしてマークします。つまり、ほとんどのエスケープ文字は無視されます。

Note

WebView が子であるレイアウトによっては、WebViewWidthRequest および HeightRequest プロパティを設定して HTML コンテンツを表示することが必要な場合があります。 たとえば、これは StackLayout で必要です。

ローカル HTML コンテンツ

WebView では、アプリ内に埋め込まれた HTML、CSS、JavaScript のコンテンツを表示できます。 次に例を示します。

<html>
  <head>
    <title>Xamarin Forms</title>
  </head>
  <body>
    <h1>Xamarin.Forms</h1>
    <p>This is an iOS web page.</p>
    <img src="XamarinLogo.png" />
  </body>
</html>

CSS:

html,body {
  margin:0;
  padding:10;
}
body,p,h1 {
  font-family: Chalkduster;
}

上記の CSS で指定されたフォントは、プラットフォームごとにカスタマイズする必要があることに注意してください。すべてのプラットフォームに同じフォントがあるわけではありません。

WebView を使用してローカル コンテンツを表示するには、他と同様に HTML ファイルを開き、そのコンテンツを文字列として HtmlWebViewSourceHtml プロパティに読み込む必要があります。 ファイルを開く方法の詳細については、ファイルの処理に関するページを参照してください。

次のスクリーンショットは、各プラットフォームでローカル コンテンツを表示した結果を示しています。

WebView Displaying Local Content

最初のページは読み込まれていますが、WebView では HTML の取得元が認識されません。 これは、ローカル リソースを参照するページを処理するときの問題です。 このような場合の例としては、ローカル ページが相互にリンクされている場合、ページで別の JavaScript ファイルが利用されている場合、ページが CSS スタイルシートにリンクされている場合などがあります。

これを解決するには、ファイルシステム上のファイルを見つける場所を WebView に指示する必要があります。 これを行うには、WebView で使用される HtmlWebViewSourceBaseUrl プロパティを設定します。

各オペレーティング システム上のファイルシステムは異なるため、各プラットフォームでその URL を決定する必要があります。 Xamarin.Forms では、各プラットフォームで実行時に依存関係を解決するための DependencyService が公開されます。

DependencyService を使用するには、まず、各プラットフォームに実装できるインターフェイスを定義します。

public interface IBaseUrl { string Get(); }

各プラットフォームでインターフェイスが実装されるまで、アプリは実行されないことに注意してください。 一般的なプロジェクトでは、DependencyService を使用して BaseUrl を必ず設定してください。

var source = new HtmlWebViewSource();
source.BaseUrl = DependencyService.Get<IBaseUrl>().Get();

その後、各プラットフォームのインターフェイスの実装を提供する必要があります。

iOS

iOS では、次に示すように、Web コンテンツはプロジェクトのルート ディレクトリまたは Resources ディレクトリにビルド アクション BundleResource を使用して配置する必要があります。

BaseUrl は、メイン バンドルのパスに設定する必要があります。

[assembly: Dependency (typeof (BaseUrl_iOS))]
namespace WorkingWithWebview.iOS
{
  public class BaseUrl_iOS : IBaseUrl
  {
    public string Get()
    {
      return NSBundle.MainBundle.BundlePath;
    }
  }
}

Android

Android では、次に示すように、ビルド アクション AndroidAsset を使用して、HTML、CSS、画像を Assets フォルダーに配置します。

Android では、BaseUrl"file:///android_asset/" に設定する必要があります。

[assembly: Dependency (typeof(BaseUrl_Android))]
namespace WorkingWithWebview.Android
{
  public class BaseUrl_Android : IBaseUrl
  {
    public string Get()
    {
      return "file:///android_asset/";
    }
  }
}

Android では、Assets フォルダー内のファイルには、MainActivity.Instance プロパティによって公開される現在の Android コンテキストを介してアクセスすることもできます。

var assetManager = MainActivity.Instance.Assets;
using (var streamReader = new StreamReader (assetManager.Open ("local.html")))
{
  var html = streamReader.ReadToEnd ();
}

ユニバーサル Windows プラットフォーム

ユニバーサル Windows プラットフォーム (UWP) プロジェクトでは、Content に設定されたビルド アクションを使用してプロジェクト ルートに HTML、CSS、画像を配置します。

BaseUrl"ms-appx-web:///" に設定する必要があります。

[assembly: Dependency(typeof(BaseUrl))]
namespace WorkingWithWebview.UWP
{
    public class BaseUrl : IBaseUrl
    {
        public string Get()
        {
            return "ms-appx-web:///";
        }
    }
}

WebView では、使用できるいくつかのメソッドとプロパティのナビゲーションがサポートされています。

  • GoForward()CanGoForward が true の場合、GoForward を呼び出すと、次にアクセスしたページに進みます。
  • GoBack()CanGoBack が true の場合、GoBack を呼び出すと、最後にアクセスしたページに移動します。
  • CanGoBack – 戻るページがある場合は true、ブラウザーが開始 URL にある場合は false
  • CanGoForward – ユーザーが後方に移動し、既にアクセスされたページに進むことができる場合は true

ページ内では、WebView でマルチタッチ ジェスチャはサポートされません。 コンテンツがモバイルに最適化され、ズームを必要とせずに表示されるようにすることが重要です。

アプリケーションでは、デバイスのブラウザーではなく、WebView 内にリンクが表示されるのが一般的です。 このような状況では、通常のナビゲーションを許可すると便利ですが、ユーザーが開始リンク上にいる間にヒット バックすると、アプリは通常のアプリ ビューに戻る必要があります。

このシナリオを有効にするには、組み込みのナビゲーション メソッドとプロパティを使用します。

まず、ブラウザー ビューのページを作成します。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="WebViewSample.InAppBrowserXaml"
             Title="Browser">
    <StackLayout Margin="20">
        <StackLayout Orientation="Horizontal">
            <Button Text="Back" HorizontalOptions="StartAndExpand" Clicked="OnBackButtonClicked" />
            <Button Text="Forward" HorizontalOptions="EndAndExpand" Clicked="OnForwardButtonClicked" />
        </StackLayout>
        <!-- WebView needs to be given height and width request within layouts to render. -->
        <WebView x:Name="webView" WidthRequest="1000" HeightRequest="1000" />
    </StackLayout>
</ContentPage>

コードビハインドで次のようにします。

public partial class InAppBrowserXaml : ContentPage
{
    public InAppBrowserXaml(string URL)
    {
        InitializeComponent();
        webView.Source = URL;
    }

    async void OnBackButtonClicked(object sender, EventArgs e)
    {
        if (webView.CanGoBack)
        {
            webView.GoBack();
        }
        else
        {
            await Navigation.PopAsync();
        }
    }

    void OnForwardButtonClicked(object sender, EventArgs e)
    {
        if (webView.CanGoForward)
        {
            webView.GoForward();
        }
    }
}

これで完了です。

WebView Navigation Buttons

イベント

WebView では、状態の変化に対応するのに役立つように、次のイベントが発生します。

  • Navigating – WebView で新しいページの読み込みが開始されたときに発生するイベント。
  • Navigated – ページが読み込まれ、ナビゲーションが停止したときに発生するイベント。
  • ReloadRequested – 現在のコンテンツを再読み込みする要求が行われたときに発生するイベント。

Navigating イベントに付随する WebNavigatingEventArgs オブジェクトには、次の 4 つのプロパティがあります。

  • Cancel – ナビゲーションを取り消すかどうかを示します。
  • NavigationEvent - 発生したナビゲーション イベント。
  • Source - ナビゲーションを実行した要素。
  • Url – ナビゲーション先。

Navigated イベントに付随する WebNavigatedEventArgs オブジェクトには、次の 4 つのプロパティがあります。

  • NavigationEvent - 発生したナビゲーション イベント。
  • ResultWebNavigationResult 列挙メンバーを使用して、ナビゲーションの結果について説明します。 有効な値は、CancelFailureSuccess、および Timeout です。
  • Source - ナビゲーションを実行した要素。
  • Url – ナビゲーション先。

読み込みに時間がかかる Web ページの使用が予想される場合は、Navigating および Navigated イベントを使って状態インジケーターを実装することを検討してください。 次に例を示します。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="WebViewSample.LoadingLabelXaml"
             Title="Loading Demo">
    <StackLayout>
        <!--Loading label should not render by default.-->
        <Label x:Name="labelLoading" Text="Loading..." IsVisible="false" />
        <WebView HeightRequest="1000" WidthRequest="1000" Source="https://dotnet.microsoft.com/apps/xamarin" Navigated="webviewNavigated" Navigating="webviewNavigating" />
    </StackLayout>
</ContentPage>

2 つのイベント ハンドラー:

void webviewNavigating(object sender, WebNavigatingEventArgs e)
{
    labelLoading.IsVisible = true;
}

void webviewNavigated(object sender, WebNavigatedEventArgs e)
{
    labelLoading.IsVisible = false;
}

この結果、次の出力が得られます (読み込み)。

Screenshot shows WebView Navigating Event while loading.

読み込みが完了:

Screenshot shows WebView Navigating Event after loading.

コンテンツの再読み込み

WebView には、現在のコンテンツを再度読み込むために使用できる Reload メソッドがあります。

var webView = new WebView();
...
webView.Reload();

Reload メソッドが呼び出されると、現在のコンテンツを再読み込みする要求が行われていることを示す ReloadRequested イベントが発生します。

パフォーマンス

一般的な Web ブラウザーでは、ハードウェア アクセラレータ レンダリングや JavaScript コンパイルなどのテクノロジが採用されています。 Xamarin.Forms 4.4 より前では、Xamarin.FormsWebViewUIWebView クラスによって iOS に実装されていました。 しかし、これらのテクノロジの多くはこの実装では使用できませんでした。 したがって、Xamarin.Forms 4.4 以降、Xamarin.FormsWebView は、より高速なブラウズをサポートする WkWebView クラスによって iOS に実装されます。

Note

iOS では、WkWebViewRenderer には、WkWebViewConfiguration 引数を受け入れるコンストラクター オーバーロードがあります。 これにより、作成時にレンダラーを構成できます。

アプリケーションは、互換性上の理由から、Xamarin.FormsWebView を実装するために iOS UIWebView クラスを使用するように戻すことができます。 これは、アプリケーションの iOS プラットフォーム プロジェクトの AssemblyInfo.cs ファイルに次のコードを追加して実現できます。

// Opt-in to using UIWebView instead of WkWebView.
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(Xamarin.Forms.Platform.iOS.WebViewRenderer))]

Note

Xamarin.Forms 5.0 では、WebViewRenderer クラスは削除されました。 したがって、Xamarin.Forms 5.0 には、UIWebView コントロールへの参照は含まれません。

Android のWebView は、既定では、組み込みのブラウザーと同じくらい高速です。

UWP WebView では、Microsoft Edge レンダリング エンジンが使用されます。 デスクトップおよびタブレット デバイスでは、Edge ブラウザー自体を使用する場合と同じパフォーマンスが見られるはずです。

アクセス許可

WebView を動作させるには、プラットフォームごとにアクセス許可が設定されていることを確認する必要があります。 一部のプラットフォームでは、WebView はデバッグ モードで動作しますが、リリース用にビルドされた場合は動作しないことに注意してください。 これは、Android 上のインターネット アクセス用のアクセス許可など、一部のアクセス許可は、デバッグ モードの場合に Visual Studio for Mac によって既定で設定されるためです。

  • UWP – ネットワーク コンテンツを表示するときに、インターネット (クライアントとサーバー) の機能が必要です。
  • Android – ネットワークからコンテンツを表示する場合にのみ、INTERNET が必要です。 ローカル コンテンツには特別なアクセス許可は必要ありません。
  • iOS – 特別なアクセス許可は必要ありません。

Layout

他のほとんどの Xamarin.Forms ビューとは異なり、WebView では、StackLayout または RelativeLayout に含まれるときに HeightRequestWidthRequest を指定する必要があります。 これらのプロパティを指定しないと、WebView はレンダリングされません。

次の例は、WebView が動作し、レンダリングされるレイアウトを示しています。

WidthRequest と HeightRequest を使用した StackLayout:

<StackLayout>
    <Label Text="test" />
    <WebView Source="https://dotnet.microsoft.com/apps/xamarin"
        HeightRequest="1000"
        WidthRequest="1000" />
</StackLayout>

WidthRequest と HeightRequest を使用した RelativeLayout:

<RelativeLayout>
    <Label Text="test"
        RelativeLayout.XConstraint= "{ConstraintExpression
                                      Type=Constant, Constant=10}"
        RelativeLayout.YConstraint= "{ConstraintExpression
                                      Type=Constant, Constant=20}" />
    <WebView Source="https://dotnet.microsoft.com/apps/xamarin"
        RelativeLayout.XConstraint="{ConstraintExpression Type=Constant,
                                     Constant=10}"
        RelativeLayout.YConstraint="{ConstraintExpression Type=Constant,
                                     Constant=50}"
        WidthRequest="1000" HeightRequest="1000" />
</RelativeLayout>

WidthRequest と HeightRequest を "使用しない" AbsoluteLayout:

<AbsoluteLayout>
    <Label Text="test" AbsoluteLayout.LayoutBounds="0,0,100,100" />
    <WebView Source="https://dotnet.microsoft.com/apps/xamarin"
      AbsoluteLayout.LayoutBounds="0,150,500,500" />
</AbsoluteLayout>

WidthRequest と HeightRequest を "使用しない" Grid。 Grid は、要求された高さと幅を指定する必要のない数少ないレイアウトの 1 つです。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Label Text="test" Grid.Row="0" />
    <WebView Source="https://dotnet.microsoft.com/apps/xamarin" Grid.Row="1" />
</Grid>

JavaScript の呼び出し

WebView には、C# から JavaScript 関数を呼び出し、呼び出し元の C# コードに結果を返す機能が含まれています。 これは、WebView サンプルの次の例に示されている WebView.EvaluateJavaScriptAsync メソッドを使用して行われます。

var numberEntry = new Entry { Text = "5" };
var resultLabel = new Label();
var webView = new WebView();
...

int number = int.Parse(numberEntry.Text);
string result = await webView.EvaluateJavaScriptAsync($"factorial({number})");
resultLabel.Text = $"Factorial of {number} is {result}.";

WebView.EvaluateJavaScriptAsync メソッドは、引数として指定された JavaScript を評価し、結果を string として返します。 この例では、factorial JavaScript 関数が呼び出され、結果として number の階乗が返されます。 この JavaScript 関数は、WebView が読み込むローカル HTML ファイルで定義されており、次の例に示されています。

<html>
<body>
<script type="text/javascript">
function factorial(num) {
        if (num === 0 || num === 1)
            return 1;
        for (var i = num - 1; i >= 1; i--) {
            num *= i;
        }
        return num;
}
</script>
</body>
</html>

Cookie

Cookie は WebView で設定でき、Web 要求と共に指定された URL に送信されます。 これを行うには、Cookie オブジェクトを CookieContainer に追加し、WebView.Cookies バインド可能なプロパティの値として設定します。 この例を次のコードに示します。

using System.Net;
using Xamarin.Forms;
// ...

CookieContainer cookieContainer = new CookieContainer();
Uri uri = new Uri("https://dotnet.microsoft.com/apps/xamarin", UriKind.RelativeOrAbsolute);

Cookie cookie = new Cookie
{
    Name = "XamarinCookie",
    Expires = DateTime.Now.AddDays(1),
    Value = "My cookie",
    Domain = uri.Host,
    Path = "/"
};
cookieContainer.Add(uri, cookie);
webView.Cookies = cookieContainer;
webView.Source = new UrlWebViewSource { Url = uri.ToString() };

この例では、1 つの CookieCookieContainer オブジェクトに追加し、WebView.Cookies プロパティの値として設定します。 WebView が指定したURL に Web 要求を送信すると、要求と共に Cookie が送信されます。

UIWebView の非推奨と App Store の拒否 (ITMS-90809)

2020 年 4 月以降、非推奨の UIWebView API を引き続き使用するアプリは Apple によって拒否されます。 Xamarin.Forms が既定として WKWebView に切り替わりましたが、Xamarin.Forms バイナリには古い SDK への参照がまだあります。 現在の iOS リンカーの動作ではこれは削除されないため、App Store に送信するときに非推奨の UIWebView API は引き続きアプリから参照されているように見えます。

重要

Xamarin.Forms 5.0 では、WebViewRenderer クラスは削除されました。 したがって、Xamarin.Forms 5.0 には、UIWebView コントロールへの参照は含まれません。

この問題を解決するためにリンカーのプレビュー バージョンを使用できます。 プレビューを有効にするには、リンカーに追加の引数 --optimize=experimental-xforms-product-type を指定する必要があります。

これを機能させるための前提条件は次のとおりです。

  • Xamarin.Forms 4.5 以上。 アプリで素材のビジュアルを使用する場合は、Xamarin.Forms 4.6 以降が必要です。
  • Xamarin.iOS 13.10.0.17 以降Visual Studio で Xamarin.iOS のバージョンを確認します。 このバージョンの Xamarin.iOS は、Visual Studio for Mac 8.4.1 および Visual Studio 16.4.3 に含まれています。
  • UIWebView への参照を削除する。 コードには、UIWebView への参照や、UIWebView を利用するクラスを含めないようにする必要があります。

UIWebView 参照の検出と削除の詳細については、「UIWebView の非推奨」を参照してください。

リンカーを構成する

リンカーで UIWebView 参照を削除するには、次の手順に従います。

  1. iOS プロジェクトのプロパティを開く – iOS プロジェクトを右クリックし、[プロパティ] を選択します。
  2. [iOS ビルド] セクションに移動する[iOS ビルド] セクションを選択します。
  3. [追加の mtouch 引数] を更新する[追加の mtouch 引数] では、このフラグ --optimize=experimental-xforms-product-type を追加します (既にある可能性がある値に加えて)。 注: このフラグは、[SDK のみ] または [すべてリンク] に設定されている [リンカーの動作] と連携します。 何らかの理由で、[リンカーの動作] を [すべて] に設定するときにエラーが表示される場合、これは、ほとんどの場合、アプリ コード、またはリンカー セーフではないサード パーティ製ライブラリ内の問題です。 リンカーの詳細については、「Xamarin.iOS アプリをリンクする」を参照してください。
  4. すべてのビルド構成を更新する – ウィンドウの上部にある [構成] および [プラットフォーム] リストを使用して、すべてのビルド構成を更新します。 更新する最も重要な構成は [リリース/iPhone] 構成です。これは通常、App Store 送信用のビルドを作成するために使用されるためです。

このスクリーンショットでは、新しいフラグが設定されたウィンドウを確認できます。

Setting the flag in the iOS Build section

これで、新しい (リリース) ビルドを作成して App Store に送信するときに、非推奨の API に関する警告は表示されないはずです。