[Xamarin.Forms] プログラムからJavaScriptを使用してgoogle検索を自動化する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 プログラムからJavaScriptを操作する

ブラウザは、アプリの中で動作している場合に限り、コードからJavaScriptを実行したり、逆にJavaScriptからコードにアクセスすることが可能です。 今回は、Xamarin.FormsのWebViewでJavaScriptを実行することで、プログラムからGoogle検索をしてみました。

2 固有ブラウザ

Xamarin.Formsで使用するWebViewは、各プラットフォームごと動作しているブラウザが違うため、JavaScriptを実行する方法も異なります。 そこで、共通的に利用できるようにWebViewを拡張して、メソッドを1つ追加しました。 実際の実装は、レンダラーで行う事になります。

App.cs

    public class ExWebView : WebView {
        public delegate void CallJsHandler(string js);
        public CallJsHandler CallJs;//JavaScriptの実行
    }

3 レンダラー

続いて、各プラットフォームのレンダラーを実装します。

(1) iOS

iOSで動作しているUIKit.UIWebViewは、EvaluateJavascriptメソッドでJavaScript の実行が可能です。

ExWebViewRenderer.cs

using CallingJavascriptSample;
using CallingJavascriptSample.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms.CallingJavascriptSample;

[assembly: ExportRenderer(typeof(ExWebView), typeof(ExWebViewRenderer))]
namespace CallingJavascriptSample.iOS
{
    public class ExWebViewRenderer : WebViewRenderer
    {
        protected override void OnElementChanged(VisualElementChangedEventArgs e) {
            base.OnElementChanged(e);

            var exWebView = e.NewElement as ExWebView;
            if (exWebView!=null) {
                exWebView.CallJs = CallJs;
            }
        }

        public void CallJs(string js) {
            //this = UIKit.UIWebView
            //this.EvaluateJavascript(js);
            EvaluateJavascript(js);
        }

    }
}

(2) Android

Androidで動作しているAndroid.Webkit.WebViewは、LoadUrl("javascript:" + js)でJavaScript の実行が可能です。

ExWebViewRenderer.cs

using Android.Webkit;
using Xamarin.Forms.CallingJavascriptSample;
using Xamarin.Forms.CallingJavascriptSample.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using WebView = Xamarin.Forms.WebView;

[assembly: ExportRenderer(typeof(ExWebView), typeof(ExWebViewRenderer))]
namespace Xamarin.Forms.CallingJavascriptSample.Droid
{
    class ExWebViewRenderer:WebViewRenderer{


        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e){
            base.OnElementChanged(e);

            var exWebView = e.NewElement as ExWebView;
            if (exWebView != null) {
                exWebView.CallJs = CallJs;
            }
            Control.SetWebChromeClient(new WebChromeClient());
        }
        public void CallJs(string js){
            //Android.Webkit.WebView
            Control.LoadUrl("javascript:" + js);
        }

    }
}

4 JavaScriptの実行

それでは、この拡張ブラウザを使用して、JavaScriptを実行する画面を作成してみます。 Entryに入力された文字列をJavaScriptのコードとしてブラウザに送って実行するものです。

App.cs

namespace Xamarin.Forms.CallingJavascriptSample
{
    public class App : Application
    {
        public App ()
        {
            MainPage = new MyPage();
        }
    }

    class MyPage : ContentPage {
        public MyPage() {
            var webView = new ExWebView() {
                Source = "http://www.google.com",
                VerticalOptions = LayoutOptions.FillAndExpand,
            };

            var entry = new Entry() {
                HorizontalOptions = LayoutOptions.FillAndExpand
            };

            var button = new Button {
                WidthRequest = 60,
                Text = "OK"
            };
            button.Clicked += async (s, a) => {
                if (!string.IsNullOrEmpty(entry.Text)) {
                    webView.CallJs(entry.Text);
                }
            };

            Content = new StackLayout {
                Padding = new Thickness(0,Device.OnPlatform(20,0,0),0,0),
                Children = {
                    new StackLayout {
                        BackgroundColor = Color.Navy,
                        Padding = 5,
                        Orientation = StackOrientation.Horizontal,
                        Children = { entry,button}
                    },webView
                }
            };
        }
    }

}

実行画面は、次の通りです。alert()が実行されていることを確認できます。

001 002

5 IDの取得と動作確認

JavaScriptの実行が確認できたので、続いて、目的のgoogle検索に移ります。

まずは、Chromeの「要素の検証」を使用して、検索文字の入力位置、及び検索開始ボタンのid(name)を確認します。

↓idは「lst-ib」であることが分かる 005

↓nameは「btnG」であることが分かる 006

続いて、ChromeのデベロッパーツールのConsoleを使用して、JavaScriptの動作を確認しています。

//検索文字列に「123」をセットする document.getElementById('lst-ib').value='123'; //「検索」ボタンをクリックする document.getElementsByName('btnG')[0].click();

↓スクリプトが実行されて、意図する動作をしていることが確認できる。 007

6 アプリからの操作(Google検索)

目的の動作をするJavaScriptができたので、検索文字列をEntryから取得して、OKボタンでブラウザに送り込むようにしてみます。 修正したのはボタンのイベントハンドラだけです。

App.cs

button.Clicked += async (s, a) => {
    var js = string.Format("document.getElementById('lst-ib').value='{0}';",entry.Text);
    webView.CallJs(js);
    await Task.Delay(2000);//少しタイミングを計らないと、文字入力完了前にボタンを押してしまうためDelayを入れた
    js = "document.ElementsByName('btnG')[0].click();";
    webView.CallJs(js);

    entry.Unfocus();//キーボード非表示
};

次の画面が動作している様子です。 ブラウザには触れずに検索を実行しています。

003 004

7 最後に

タイトルに自動化と書いてしまいましたが、今回のようにプログラムから制御できるとなれば、自動化も簡単でしょう。

最近は、各種のAPI等が公開されており、それらを駆使することで色々な機能を作り込むことが可能です。しかし、サービスによっては、どうしてもブラウザから実行するしかない作業も存在します。 そのような時、ブラウザを非表示にしてしまって、今回の手法でプログラムすれば、その制約をクリアできるかも知れません。

↓サンプルコードです。

githubhttps://github.com/furuya02/Xamarin.Forms.CallingJavascriptSample

8 参考資料


Xamarin記事一覧(SAPPOROWORKSの覚書)
[Developers.IO] Xamarinシリーズ