読者です 読者をやめる 読者になる 読者になる

WPFでCefSharp(Chromiumの.NET向け実装)を使う - 2

経緯

前回の続きです。

今回は具体的なWebBrowserとの比較として、以下の機能の実装方法について検証します。

  • UserAgentの設定
  • ページ遷移のハンドリング
  • Cookieの操作

UserAgentの設定

WebBrowserの場合

urlmon.dllUrlMkSetSessionOptionを利用すると実現できます→参考

難しいことはないんですがアンマネージドなコードを触るのがちょっともやっとします。

Cefの場合

CefSharp.Wpf.ChromiumWebBrowserインスタンスを生成する前に、Cef.Initialize(cefSettings)を呼び出すことでUserAgent等の設定を行うことができます。

この関数の引数であるCefSettingsは他にもいろいろ設定できる項目があるので後々検証します。

今回はUserAgentを設定したいだけなので、UIスレッドでUserAgentを指定したCefSettingsを使ってCefをInitializeするだけです。

public static void Init()
{
    var cefSettings = new CefSettings
    {
        UserAgent = "CefSample",
    };
    Cef.Initialize(cefSettings);
}

f:id:ghken:20170426233050p:plain

ちゃんとUserAgentがCefSampleになってます。

ページ遷移のハンドリング

WebBrowserの場合

WebBrowser.Navigating, WebBrowser.Navigatedイベントがあるので、それぞれ遷移前、遷移後の処理をハンドリングすることができます。

また、Navigatingのイベントハンドラに第二引数として渡されるNavigatingCancelEventArgsのCancelプロパティをtrueにしておくことで、遷移をキャンセルさせることができます。

Cefの場合

ChromiumWebBrowser.FrameLoadStart, ChromiumWebBrowser.FrameLoadEndイベントがあるので、それぞれ遷移開始、遷移後の処理をハンドリングすることができます。

ただ、このFrameLoadStartイベントでは遷移をキャンセルすることができず、リクエストの書き換えや遷移のキャンセルを制御するにはChromiumWebBrowser.RequestHandlerプロパティを実装する必要があります。

RequestHandlerは多機能なので別途検証を行います(今回は行いません)。

Browser = new ChromiumWebBrowser();
Browser.FrameLoadStart += (sender, e) =>
{
    var uri = new Uri(e.Url);
    if (uri.Host == "www.google.co.jp")
    {
        MessageBox.Show("www.google.co.jpのページに遷移します");
    }
};

みたいなことができます。

Cookieの操作

実際にやりたかったのは"クッキーを削除する"ボタンの実装なので、それをどうやって実現できそうかを見ていきます。

WebBrowserの場合

Cookieをまとめて削除するような機能はなさそうです(あったら教えてください)。

一応アンマネージドなコードを触ってInternetSetOptionでいろいろやれば既存のCookieを無視したブラウザを立ち上げることは可能なのですが、

直接消すわけではないので"クッキーを削除する"とは違う挙動になってしまいます。(オプションを無効化して再起動すると前のCookieが残ってる)

WebBrowserにはDocumentプロパティが存在して、HTMLにjsを挿入することができるので、そのjsでそのドメインCookieのExpireをいじることは可能なのですが、

すべてのページのCookieを削除することは難しそうです。

Cefの場合

Cookieを操作するためのCookieManagerクラスが用意されていて、Cef.GetGlobalCookieManager()でCookieManagerを取得することができます。

CookieManagerには特定のUrlのCookieを消すためのDeleteCookiesが実装されているので、一つだけ消す場合であればそれを呼べばOKです。

複数のドメインCookieを処理するためにはアプローチを少し変える必要があって、ICookieVisitorを実装したクラスを用意して、そのインスタンスをCookieManagerのVisitAllCookiesに渡す必要があります(VisitUrlCookiesってのもあったのでドメインごとに消すとかも簡単にできそう)。

またasyncに処理してくれるVisitAllCookiesAsyncというものもあって、こちらは返り値でCookieのListを返してくれるのですが、返ってきたところでどうやって消せばいいのかはよくわかりませんでした。

void ClearAllCookies()
{
    var cookieManager = Cef.GetGlobalCookieManager();

    cookieManager.VisitAllCookies(new CookieEater());
}

class CookieEater : ICookieVisitor
{
    public void Dispose()
    {
    }

    public bool Visit(Cookie cookie, int count, int total, ref bool deleteCookie)
    {
        deleteCookie = true;
        return true;
    }
}

まとめ

  • CefのInitializeにCefSettingsを渡すといろいろできる(UserAgentとかCacheのパスとか)
  • FrameLoadStartとFrameLoadEndでページのロード開始とページのロード完了のイベントが取れる
    • リクエスト自体をいじりたいとかならRequestHandlerを実装する必要がある(また今度検証)
  • CookieManagerとCookieVisitorを使ってCookieを簡単に操作できる

今回はここまでです。

次回はRequestHandlerあたりについて書こうと思います。