JUnitについての書籍が遂に発売します!
Java開発時のユニットテストを加速する「JUnit速効レシピ」
Java開発時のユニットテストを加速する「JUnit速効レシピ」
今回は、WebView内に書かれたJavaScriptをアプリ側から起動したり、
HTML内のリンクタップをアプリ側で検知したり、
アプリ側からJavaScriptを介す事によって値をWebView内へ渡したり、
逆にWebView内の値をアプリへ渡す様な相互連携を行う方法について
サンプルコード付きで解説します。
まずは、アプリを外部のインターネットへ接続出来る様に権限を指定する必要がありますので、
権限の付加方法から解説しましょう。
- マニュフェストの設定でインターネット通信を許可しよう
- アプリ内のブラウザ。webViewを設置しよう
- WebViewに対してJavaScriptを実行しよう
- リンクタップ等、ロケーションの変更を検知する
マニュフェストの設定でインターネット通信を許可しよう
デフォルトでは、アプリから外部のインターネットへ接続する事は出来ません。
そこで、アプリ毎にインターネットへ接続する事を許可する設定が必要です。
設定は、インターネットへの接続権限を追加するだけですので
AndroidManifest.xmlに下記を追記しましょう。
この一行を追加するだけで、インターネットへの接続を許可する事が出来ます。
簡単ですね。
アプリ内のブラウザ。webViewを設置しよう
早速WebViewを画面に設置してみましょう。
下記のサンプルでは、WebViewに表示するサイトのURLも同時に設定しています。
後は、他のViewの設置方法と変わらないので、とてもシンプルにWebViewを配置する事が出来ます。
// ウェブビューを作成 WebView webView = new WebView(this); // URLを指定する webView.loadUrl("http://www.android.com/"); // 画面に追加する setContentView( webView, new LayoutParams(MP, MP) );
基本的に、WebViewのインスタンスを作成して、
表示するサイトのURLを『loadUrl()』にて指定します。
そうすると、配置したWebViewに『loadUrl()』にて指定したアドレスのサイトが表示されます。
表示位置の指定は、WebViewもViewなので、レイアウトを指定して『setContentView()』や『addView()』にて
画面へ追加します。
また、インターネット上のサイトを表示するのではなく、
ローカルにあるHTMLファイルを参照する場合は、下記の様に指定します。
// ローカルファイルを参照する webView.loadUrl("file:///android_asset/hoge.html");
ポイントは、『file:///』から始まる事。
スラッシュが三つある事に気を付けて、目的のローカルファイルまでのパスを記述して下さい。
そして、WebViewの背景はCSSでいくら設定しても、通常では透明にはならず、WebViewの後ろにある背景を見せる事は出来ませんが、
下記の設定を行う事によって、WebView自体を透過させる事が出来ます。
// 背景色を透過させる webView.setBackgroundColor(0); webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
これで簡単なブラウザが出来あがりました。
後はJavaScriptとの連携が出来れば、かならりアプリと関連付けが出来、
WebViewの機能をフル活用出来るかと思います。
HTMLの表示を操作するJavaScriptと、Android端末本体に関する処理を行うJavaで連携を取れれば、
特異な機能を分業で構築する事が出来ますので、
実装方法の選択肢として身に付けられれば、かなりの『強み』になりますね。
次章では、そんなJavaScriptとの連携について解説します。
WebViewに対してJavaScriptを実行しよう
いよいよ、設置したWebView内のJavaScriptとアプリを連携させてみましょう。
前提条件として、まずはWebViewにJavaScriptの実行を有効にする様に設定する必要があります。
WebViewには専用の設定情報がありますので、『getSettings()』で取得した設定情報へ『setJavaScriptEnabled()』にて『true』をセットします。
これで該当するWebViewにたいしてJavaScriptを実行出来る様になります。
実際の実装方法は下記を参考にして下さい。
// webViewの設定でjavascriptを有効にする webView.getSettings().setJavaScriptEnabled(true);
これでWebViewに対してJavaScriptを実行する前準備が整いました。
いよいよJavaScriptを実行してみましょう。
使用するメソッドは、ページの読み込みと同じく『loadUrl()』にて行います。
渡す文字列の先頭に『javascript:』を記述する事によって、ソレがJavaScriptである事を宣言出来、
WebView内で渡された文字列をJavaScriptとして実行されます。
// JavaScriptを実行して文字列を書き出す webView.loadUrl("javascript:document.write('JavaScriptが実行されました!');");
もちろん、あらかじめHTMLに書かれたJavaScriptを起動する様に、
メソッドコールも可能です。
例えば、上記の様なHTMLがあったとすると、
下記の様に引数付でメソッドコールする事が出来ます。
// JavaScriptを実行して文字列を書き出す webView.loadUrl("javascript:addMessage('表示されます');");
予め決まった処理をHTML内にJavaScriptで記述して
使用するタイミングでアプリから『loadUrl()』で必要な処理を呼び出すといった使い方が
可能です。
これでアプリからHTMLを操作する事も可能になりました。
しかし、このままですとアプリからHTMLへの一方通行です。
もちろん、表示した際のコールバックを受けたい事もあるかと思います。
例えば、アニメーションの終了をアプリに通知したい。
HTML内で選択された情報をアプリに通知したい。
といった事が出来れば、相互に情報がやり取り出来て便利ですね。
次章では、HTML側のアクションをアプリ側で取得する方法を解説します。
リンクタップ等、ロケーションの変更を検知する
HTMLからアプリへ何かを通知するには、ロケーションの変更イベントを送信し、
アプリ側ではロケーション変更イベントから、どのロケーションへ変化するのかを判断して、
目的の処理へと誘導します。
ロケーションの変更イベントの発生契機といえば、一般的にはリンクがタップされた時でしょう。
リンクがタップされた事を検知するには、webViewに対して『setWebViewClient()』で
目的のメソッドを実装した『WebViewClient』クラスを登録します。
『WebViewClient』クラスでは、リンクをタップされた時に呼ばれるメソッドが用意されており、
『public boolean shouldOverrideUrlLoading( WebView view_, String url_ )』と定義できます。
実際の実装例は下記の通りです。
// ロケーション変更イベントを拾う webView.setWebViewClient( new WebViewClient(){ public boolean shouldOverrideUrlLoading( WebView view_, String url_ ){ // タップされたリンクのURL(変更先ロケーション) Log.v( "url", url_ ); // trueを返却 return( true ); } });
厳密にいうと、リンクをタップされた事を検知するのではなく、
WebViewのlocationに変更がある時に呼ばれます。
ですので、JavaScriptにて
document.location = "app://action_finish";
の様に実行しても、同じく『shouldOverrideUrlLoading』が起動され
引数のURLには『app://action_finish』という文字列が渡されてきます。
後は、渡されてきたURLを見て処理を切り替える事が出来ますので、
『loadUrl』でJavaScriptを起動して、完了通知を『shouldOverrideUrlLoading』で受けるといった
相互連携も可能にします。
また、URLは文字列できますので『mailto』を判定して、独自にメーラーを起動させるといった
使い方もできます。
URLの判定は、例えば下記の様に行えるでしょう。
// リンクがクリックされたイベントを拾う webView.setWebViewClient( new WebViewClient(){ public boolean shouldOverrideUrlLoading( WebView view_, String url_ ){ String request_string = url_; if( ! request_string.startsWith( "app://" ) ){ return( true ); } if( request_string.equals( "app://selected_1" ) ){ // ボタン1が押された時の処理 } if( request_string.equals( "app://selected_2" ) ){ // ボタン2が押された時の処理 } if( request_string.equals( "app://action_finish" ) ){ // JavaScriptで実行したアクションの終了後の処理 } // trueを返却 return( true ); } }
JavaScriptからのの終了検知にも使用できますし、ボタンリンクを設置しておけば、
押されたボタンもURLを判定するだけで取得出来てしまいます。
上記の例と遂になるHTMLは下記の通りです。
ボタン1ボタン2
『loadUrl()』でHTMLに記述された『addMessage()』を呼ぶと、
メッセージが表示された後にロケーションの変更を行いますので、
アプリに変更イベントが飛んでいき、変更先URLを『app://action_finish』と判定して
処理を行う事が出来ます。
『<a href>』のイベントも取得できますので、
どのボタンが押されたのかも簡単に判定出来てしまいます。
もちろん、ボタンタップをJavaScriptで検知して、何かの処理を行った後に『document.location = "app://selected_1";』
としても問題ありません。
ですので、何かの処理結果の値をアプリに渡したい時は、ロケーションにパラメータを付け加える事で
アプリ側で取得出来る様になります。
例えば、『app://action_finish?hamada』というパラメータ付の文字列をJavaScriptで作成し、
ロケーションに指定します。
var name = "hanada"; var location_string = "app://action_finish?"+name; document.location = location_string;
そうすると、『shouldOverrideUrlLoading()』へ渡されて来るURLは
『app://action_finish?hamada』となりますので、
後は下記の様に解析してパラメータの値を取り出します。
// リンクがクリックされたイベントを拾う webView.setWebViewClient( new WebViewClient(){ public boolean shouldOverrideUrlLoading( WebView view_, String url_ ){ String request_string = url_; if( ! request_string.startsWith( "app://action_finish?" ) ){ // パラメータ開始位置を取得 int start_point = request_string.indexOf( '?' ); // パラメータ部分を取得 String param = request_string.substring( start_point ); // paramにはhamadaというパラメータが取得出来ました。 Log.v( "param", param ); } // trueを返却 return( true ); } }
結局の所、パラメータの取得は渡されてきたURLの文字列解析になりますので、
特定のルールを持たせれば、複数のパラメータをキーとバリューの関係で渡す事も可能です。
かなり柔軟に扱えますので、みなさん独自のアプリにあったやり方で実装して下さいね。
これで、HTML側とアプリ側で相互に連携が取れるようになりました。
間にJavaScriptを介す事によって、出来る事の幅が一段と広がりますね。
以上を持ちまして、WebView内のHTMLやJavaScriptとネイティブアプリのJavaとの連携方法の解説を
終わりにします。
ありがとうございました。
JUnitについての書籍が遂に発売します!
Java開発時のユニットテストを加速する「JUnit速効レシピ」
Java開発時のユニットテストを加速する「JUnit速効レシピ」