次の方法で共有


WebView について知っておくべき 10 項目

こんにちは。先日に引き続き、米国のサポートチームで公開している Blog の翻訳を紹介させてください。
ご存じの通り Windows 8 から Windows ストア アプリケーションが利用できるようになり、私たちのチームでお問い合わせを担当しています。米国のサポートチームでは、Windows ストア アプリケーション専門のサポート チームがあり、こちらのチームでも Blog を運営していますが、その中でもページビューが多いいくつかの記事を日本語に翻訳してみたいと思います。

 

Ten Things You Need to Know About WebView

こんにちは - 私はマイクロソフト Windows ストア開発者ソリューション チームのシニア エスカレーション エンジニアのマット・スモールです。 私は Release Preview の以前より Windows 8 に携わっており、ストアのフォーラムでは、C# のフォーラムに主に参加してきました。C# forum には WebView コントロールについての投稿が実に多かったので WebView について私が集積した知識をここでまとめておくとよいと思いました。この記事はかなり長くなりますので 10 項目にわけて説明します。

  1. WebView は一般用途のブラウザではありません
  2. WebView は常に XAML の上にレンダリングされます
  3. WebView は Flash、Silverlight、PDF、およびその他の ActiveX コントロールやプラグインをサポートしません
  4. Webview で表示されたページで Javascript を起動する方法
  5. WebView からデータを受け取る方法
  6. WebView のページに Javascript を動的に埋め込む方法
  7. WebView のキャッシュをクリアする方法
  8. WebView で使うフォントをアプリに埋め込む方法
  9. WebView 内のリンクから他のアプリを起動する方法
  10. デバッグ中に目障りな JavaScript の例外画面を表示させない方法 

 

  1. WebView は一般用途のブラウザではありません

    WebView コントロールはストアアプリの開発者がウェブの一部をアプリに埋め込むためのもので、インターネット上の任意のサイトを閲覧する目的で付け加えないようにしてください。- 自分で開発するストアアプリに自分で提供するウェブサイトのページを表示するためのリンクとして使用してください。

    例: 頻繁に変更が発生するウェブコンテンツの場合、WebView コントロールにデータを表示させる方が、ストアを通じてアプリを毎回アップデートするよりもはるかに簡単です。

    これに対し、ストアアプリから Web アプリへのポータルとして使うことは意図されていません。事実、この目的で WebView コントロールを使用するとストアへの登録が却下されます。

    これとは別に、いくつかの機能は完全な Internet Explorer ブラウザのようには動作しません。これは別にそれを意図しているわけではなく、コードベースが (似てはいるものの) 単純に異なっている、IE とは別物ということです。実際、ドキュメントにはこのことが WebView の制限事項として明確にうたわれています。

    WebView はドキュメントモードでは常に Internet Explorer 10 を使用します。さらに、WebView は現在 HTML5、AppCache、IndexedDB、クリップボードへのプログラム アクセス、および地理的情報をサポートせず、Javascript を使用した Windows ストア アプリでサポートする Document Object Model (DOM) のプロパティのみサポートします。

    WebView コントロール内で表示されるコンテンツはアプリの構成部品として、WebView の制限事項に従う必要があります。

  2. WebView は常に XAML の上にレンダリングされます

    これもドキュメントに明確に謳われていますが、WebView のこの側面に引っかかったことのある人は (私自身もふくめ) 多いため繰り返します。本来 WebView が占めているスペースに覆いかぶさって、WebView の全体または一部を隠すはずの要素を作成した場合、WebView は常に XAML の上に描画されるという事象があり、Airspace 問題と呼ばれています。これは WebView は Control オブジェクトのサブクラスではなく、残りの XAML スペースとは別に描画されるためです。たとえば次のコードの場合、もし WebView が普通のコントロールであったと仮定すると、TextBox の後ろに隠れるはずです。

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
     <StackPanel>
     <Grid>
     <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html"/>
     <TextBox Width="800" Height="30" Text="This control would be in front of the WebView if WebView were a normal control."/>
     </Grid>
     <Button x:Name="MyButton" Margin="10" Content="Invoke the WebViewBrush control" Click="MyButton_Click_1" HorizontalAlignment="Center"/>
     </StackPanel>
     </Grid>

    実際はこの図にあるような問題が起こります。

    回避方法は WebViewBrush コントロールを使用することです。簡単にいうと、WebViewBrush は既存の WebView の内容をコピーし Rectangle オブジェクト内に表示します。これにより、他の XAML コンテンツが上にかぶさってレンダリングされます。WebView の内容を TextBox の上にかぶせるには以下のようにします。

    XAML に Rectangle オブジェクトを追加:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
     <StackPanel>
     <Grid>
     <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html"/>
     <Rectangle x:Name="MyRectangle"/>
     <TextBox Width="800" Height="30" Text="This control would be in front of the WebView if WebView were a normal control."/>
     </Grid>
     <Button x:Name="MyButton" Margin="10" Content="Invoke the WebViewBrush control" Click="MyButton_Click_1" HorizontalAlignment="Center"/>
     </StackPanel>
     </Grid>

    ボタンの Click イベントハンドラはこちら :

    private void MyButton_Click_1(object sender, RoutedEventArgs e)
     {
     WebViewBrush MyWebViewBrush = new WebViewBrush();
     MyWebViewBrush.SourceName = "MyWebview";
     MyWebViewBrush.Redraw();
     MyRectangle.Fill = MyWebViewBrush;
     MyWebview.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
     }

    ここでボタンをクリックすると、TextBox は WebView の手前にあるオブジェクトのさらに手前に表示されます。ただ一つ気を付けなければならないのは WebView そのものは畳み込んでおいて WebViewBrush を含む Rectangle はそのまま表示させている点です。

  3. WebView は Flash、Silverlight、PDF、およびその他の ActiveX コントロールやプラグインをサポートしません

    ActiveX コントロールは Internet Explorer を実に優れたアプリ配布手段に発展させた反面、マルウェア開発者の絶好の攻撃手段ともなってきました。WinRT API の開発過程で決定されたことは、WebView コントロールは、セキュリティおよびパフォーマンスの観点から ActiveX コントロールを一切ホストしない - 過去の IE が Flash や Silverlight をホストしていた時と異なり、WebView が隠し IE として悪用されるのを防ぐ - ということです。加えて、IE10 の RTM 版が Flash を内蔵しているにもかかわらず、WebView にはこの機能は含めてありません。

  4. Webview で表示されたページで Javascript を起動する方法

    WebView がアプリの操作性の一要素であることはお分かりいただけたと思いますので、HTML を使ってアプリ全体の価値を高める方法を考えたいと思います。以下のコードを試してみましょう。

    まずは Javascript の関数を 1 つ含む HTML ページを作ります。

    <!DOCTYPE html>
    <html lang="en" xmlns=https://www.w3.org/1999/xhtml>
    <head>
     <meta charset="utf-8" />
     <title>Matt's Webview Content Page</title>
     <script lang="en-us" type="text/javascript">
     function TimeUpdate() {
     var TimeTextbox = document.getElementById("TheTime");
     TimeTextbox.value = new Date().toTimeString();
     }

     </script>
    </head>
    <body>
     <h2>Matt's Webview Content Page</h2>
     <h5>The current time is: <input type="text" Id="TheTime" /> </h5>
     <button onclick="TimeUpdate()">Update the time!</button>
    </body>
    </html>

    次にこのページを読み込む WebView を含む XAML を作ります。

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
    <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html"/>
    <Button x:Name="MyButton" Margin="10" Content="Invoke the TimeUpdate Javascript function from C# using this button" Click="MyButton_Click_1" HorizontalAlignment="Center"/>
    </StackPanel>
    </Grid>
     
    WebView の Source には "ms-appx-web:///" のプロトコルが使われることに注意してください。これには、*3 つの* スラッシュがあります。
    最後に、C# のページからこの Javascript を呼ぶためのコードを作成します。

    private void MyButton_Click_1(object sender, RoutedEventArgs e)
     {
     MyWebview.InvokeScript("TimeUpdate", null);
     }
     
    XAML のページのボタンは Click イベントハンドラを起動し WebView の InvokeScript メソッドを呼びます。InvokeScript メソッドには 2 つの引数があり、Javascript の関数名と、その関数に渡す引数の文字列配列を指定します。

    このコードを実行すると以下のようになります。

  5. WebView からデータを受け取る方法

    Web ページ中の操作を呼び出すのと同様に重要なのが、C# コードで使用できるデータを Web ページから取得する技術です。これは次のように行います。

    初めに Web ページからストアアプリで必要とするデータを取得する方法が必要です。 これには window.external.notify(string) 関数を使います。 前述の TimeUpdate 関数をつぎのように修正してみます。
     
     function TimeUpdate() {
     var TimeTextbox = document.getElementById("TheTime");
     TimeTextbox.value = new Date().toTimeString();
     window.external.notify(TimeTextbox.value);
     }
     
    次に、XAML にイベント定義を記述し、C# に渡されたデータを見るための TextBox を追加します。

    <WebView x:Name="MyWebview" Width="500" Height="500" Source="ms-appx-web:///HTMLPage1.html" ScriptNotify="MyWebview_ScriptNotify_1"/>
     …
     <TextBox x:Name="MyTextBox" Width="200"/>
     
    最後に ScriptNotify イベントハンドラメソッドを追加します。

    private void MyWebview_ScriptNotify_1(object sender, NotifyEventArgs e)
     {
     MyTextBox.Text = e.Value;
     }

    コードを実行し "Update the Time!" HTML ボタンを押すと、コードがあたかも Web ページの一部として実行されたかのようにデータが返ってきます。

  6. WebView のページに Javascript を埋め込む方法

    WebView でホストされた Web ページとデータを授受する方法はこれでわかりましたが、場合によっては、自分でコンテンツを管理していない Web ページからデータを受け取るような状況もあることを考慮する必要があります。このような場合、そのページに我々が使用するためのコードを注入する必要があります。

    まず、コンテンツを注入するにあたって、WebView の Source をそのページに変えればよい、という簡単な話ではありません - そのページの HTML ソースコードを変更することができないからです。そのページを読み込んで文字列にする必要があります。 話を簡単にするため、前述のコードを少し変えて使い続けます。以下がコードの概要です。

     a. HTML ページのソースをダウンロードし文字列に格納
     b. ページ内でスクリプトを注入する場所を特定
     c. ページにスクリプトを注入
     d. NavigateToString メソッドで WebView の Source を上記の文字列に設定以下が実装です。

    XAML ページで、WebView オブジェクトから Source 属性を除去。以下のようになります。

    <WebView x:Name="MyWebview" Width="500" Height="500" ScriptNotify="MyWebview_ScriptNotify_1"/>

    ここで Web ページの文字列を取得し変更する魔術をほどこします。

    async protected override void OnNavigatedTo(NavigationEventArgs e)
     {
     Windows.Storage.StorageFile MyWebPageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///HTMLPage1.html"));
     string MyWebPageString = await FileIO.ReadTextAsync(MyWebPageFile);
     string ScriptTagString = "<script lang=\"en-us\" type=\"text/javascript\">";
     int IndexOfScriptTag = MyWebPageString.IndexOf(ScriptTagString);
     int LengthOfScriptTag = ScriptTagString.Length;
     string InsertionScriptString = "function SayHelloWorld() { window.external.notify(\"Hello World!\");} ";
     MyWebPageString = MyWebPageString.Insert(IndexOfScriptTag + LengthOfScriptTag + 1, InsertionScriptString);
     MyWebview.NavigateToString(MyWebPageString);
     }

    最後に InvokeScript メソッドを上述の新しい Javascript 関数を呼ぶように変更します。

    private void MyButton_Click_1(object sender, RoutedEventArgs e)
     {
     MyWebview.InvokeScript("SayHelloWorld", null);
     }

    このコードを実行すると次の 2 つの関数が現れます。

     a. 最初の HTML "Update the time!" ボタン。これは Web ページの textbox と XAML の TextBox の両方の時刻を更新します。
     b. XAML の "Invoke the TimeUpdate Javascript function..." ボタン。これは "HelloWorld" を呼び XAML の TextBox のみ更新します。

       

    この 3 つのプロジェクトはこの blog の一番下にある WebviewJavascript.zip に含まれてるのでダウンロードすることができます。

  7. WebView のキャッシュをクリアする方法

    残念ながら WebView のキャッシュはストアアプリからプログラム的にも、また UI 的にも (つまりボタンなどで) クリアする方法はありません。ただし、これはコマンド プロンプトから次の方法で実現できます。
     
    C:\Users\<username>\AppData\Local\Packages\<PackageName>\

    ここで以下のコマンドを実行します

    Attrib -H -S /S /D

    これにより、この場所のファイルとフォルダの隠し属性とシステム属性が解除されます。うまくいくと、次の図のようなフォルダ構成が表示されます。

    これでアプリに埋め込まれた WebView のキャッシュ、クッキー、および履歴を削除できます。

  8. WebView で使うフォントをアプリに埋め込む方法

    ttf フォントでは以下のようになります。CSS ファイルまたは <style> タグで使用します。

    @import url(ms-appx:///<fontname>.ttf)

    (10/24/12) すいません。間違っていますね。 どうやらこれではうまくいかないようなので、WebView にフォントを埋め込む方法を説明した別の記事を用意しました。今度はうまくいくことを願っています。

  9. WebView 内のリンクから他のアプリを起動する方法

    どんなストア アプリでもそうですが、直接他のアプリを起動する方法はありません。ただし、Webview でもデフォルトのプロトコル ハンドラおよびデフォルトの拡張子ハンドラの考えは当てはまります。アプリ内のリンクはデフォルトのプロトコル ハンドラおよび拡張子ハンドラで開かれます。たとえば .PDF のリンクなら組み込みのドキュメント ビューアで開かれます。

  10. デバッグ中に目障りな JavaScript の例外画面を表示させない方法

    WebView 搭載アプリのデバッグ中に、WebView 内のページの JavaScript が例外を起こすと、以下の図のようなデバッガー ダイアログが表示されます。

    これは C#/XAML アプリにおいてはあまり意味のあるダイアログではありません。これを表示させないようにするには Visual Studio のスクリプト デバッギングをオフにします。

    デバッグ > オプションと設定 > デバッグ > Just-In-Time > "スクリプト" を無効化

    これでもう煩わされることはありません。

 

皆様が Windows ストアの XAML/C# アプリを開発するにあたり、以上の情報が役に立つことを期待しております。コメントを歓迎しますので、是非 @WinDevMatt へ呟いてください。このブログのハッシュタグは #WSDevSol です。

WebviewJavascript.zip