【Android】WebView内のJavaScriptやHTMLと相互連携する方法

JUnitについての書籍が遂に発売します!
Java開発時のユニットテストを加速する「JUnit速効レシピ」



今回は、WebView内に書かれたJavaScriptをアプリ側から起動したり、
HTML内のリンクタップをアプリ側で検知したり、
アプリ側からJavaScriptを介す事によって値をWebView内へ渡したり、
逆にWebView内の値をアプリへ渡す様な相互連携を行う方法について
サンプルコード付きで解説します。


まずは、アプリを外部のインターネットへ接続出来る様に権限を指定する必要がありますので、
権限の付加方法から解説しましょう。



  1. マニュフェストの設定でインターネット通信を許可しよう
  2. アプリ内のブラウザ。webViewを設置しよう
  3. WebViewに対してJavaScriptを実行しよう
  4. リンクタップ等、ロケーションの変更を検知する


マニュフェストの設定でインターネット通信を許可しよう



デフォルトでは、アプリから外部のインターネットへ接続する事は出来ません。
そこで、アプリ毎にインターネットへ接続する事を許可する設定が必要です。

設定は、インターネットへの接続権限を追加するだけですので
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内のHTMLJavaScriptとネイティブアプリのJavaとの連携方法の解説を
終わりにします。

ありがとうございました。


JUnitについての書籍が遂に発売します!
Java開発時のユニットテストを加速する「JUnit速効レシピ」

コメントをお待ちしています

人気の投稿

Category

Algorithm (2) Android (8) ASP/aspx (1) Blogger (2) C/C++ (1) Chrome (5) CSS (9) Firefox (4) Fortran (1) Google (9) GoogleMap (2) HTML (12) IE (3) Information (4) iOS (2) iPhone/iPad/iPod (2) Java (6) JavaScript (16) jQuery (9) JSP (1) LifeRecipe (5) Linux (2) Macintosh (2) MapKit (4) Marketing (7) MySQL (3) NAMAZU (2) Objective-C (7) Other (7) Perl (1) PHP (9) Python (1) RSS/Atom (2) Ruby (1) Safari (2) SEO (11) Smarty (2) SQL (2) Tex (1) Three.js (1) Twitter (1) TwitterLog (313) UIKit (5) Unix (1) VBA/VBS (1) Windows (5) WordPress (3) Writing (5) XAMPP (1) XML (1) Yahoo (2) ZendFramework2 (14)

Archives