marunomaruno-memo

marunomaruno-memo

[Android] JavaScript との連携 - WebView

2012年02月12日 | Android
[Android] JavaScript との連携 - WebView
================================================================================

WebView を使うことで、レイアウトの中で、HTML を表示することができる。
自分のアプリケーションから独立しているブラウザーでは、アプリケーションから HTML 
を制御することはできないが、アプリケーション内の WebView を使えば、アプリケーシ
ョンから HTML の制御は可能になる。たとえば、JavaScript と Java のプログラムとを
連携させることができる。

JavaScript との連携方法としては次の 2 つがある。
(1) JavaScript から Java のメソッド呼び出し
(2) Java から JavaScript の関数呼び出し


どちらも、以下の処理を行う必要がある。
・WebView オブジェクトを取得し、HTML の中で JavaScript を使えるようにする

上記を行ったのちの、それぞれの概要は以下のとおり。

(1) JavaScript から Java のメソッド呼び出し

・JavaScript から使える Java のメソッドのオブジェクトを登録
    WebView.addJavascriptInterface(オブジェクト, インターフェース名);


(2) Java から JavaScript の関数呼び出し

・つぎのメソッドを使う
    WebView.loadUrl("javascript:関数名(引数リスト)");


JavaScript を扱う上での注意点として、以下をあげる。

・alert や prompt を使うときには設定が必要
    WebView.setWebChromeClient(WebChromeClient オブジェクト);

・JavaScript インターフェースのメソッドで、アクティビティのビューを操作する場合
はハンドラー Handler オブジェクトが必要
    Handler.post(new Runnable() {
        public void run() {
            // ビューの操作
        }
    });

WebView を使う上での注意点

・マニフェストに次の権限を設定する
    <uses-permission android:name="android.permission.INTERNET"/>


▲ アクティビティ

上記の概要に基づいたクラス。

□ WebViewJavaScript01Activity.java
---
package jp.marunomaruno.android.webviewjavascript;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class WebViewJavaScript01Activity extends Activity {
    private WebView webView1; // (1)

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Handler handler = new Handler(); // (2)

        webView1 = (WebView) findViewById(R.id.webView1);
        webView1.loadUrl("file:///android_asset/index.html");    // (3)

        WebSettings settings = webView1.getSettings();    // (4)
        settings.setJavaScriptEnabled(true);    // (5)

        webView1.addJavascriptInterface(new JavaScriptInterfaceFunctions(this,
                handler), "AndroidFunctions");    // (6)
        
        webView1.setWebChromeClient(new WebChromeClient());    // (7)
    }

    public void onClickHandler(View view) {
        webView1.loadUrl("javascript:showText()");    // (8)
    }
}
---

(1) WebView オブジェクト

    private WebView webView1; // (1)


△ WebView クラス

HTML をアプリケーション内から表示するためのクラス。

java.lang.Object
   +  android.view.View
        +  android.view.ViewGroup
             +  android.widget.AbsoluteLayout
                  +  android.webkit.WebView

・主なメソッド
---
void     addJavascriptInterface(Object obj, String interfaceName)
WebSettings   getSettings()
void     loadData(String data, String mimeType, String encoding)
void     loadDataWithBaseURL(String baseUrl, String data, String mimeType, 
                                String encoding, String historyUrl)
void     loadUrl(String url)
void     loadUrl(String url, Map<String, String> extraHeaders)
void     setDownloadListener(DownloadListener listener)
void     setWebChromeClient(WebChromeClient client)
void     setWebViewClient(WebViewClient client)
void     stopLoading()
---

・履歴関係のメソッド
---
boolean  canGoBack()
boolean  canGoBackOrForward(int steps)
boolean  canGoForward()
void     goBack()
void     goBackOrForward(int steps)
void     goForward()
---

・画面のズーム関係のメソッド
---
boolean  canZoomIn()
boolean  canZoomOut()
boolean  zoomIn()
boolean  zoomOut()
---


(2) ハンドラー・オブジェクトの生成

JavaScript から呼ばれたメソッドで、アクティビティのビューを操作できるようにする
ために、Handler クラスのオブジェクトを生成しておく。

    Handler handler = new Handler(); // (2)


△ Handler クラス

Handler クラスは、マルチスレッドで、スレッド間でメッセージをやり取りするのを実現
するためのクラス。

java.lang.Object
   + android.os.Handler


詳細は、以下のURLを参照のこと。
Android の Handler とは何か?
http://www.adamrocker.com/blog/261/what-is-the-handler-in-android.html
---
・AndroidのUI操作はシングル・スレッド モデル
・ユーザビリティ向上の為にはマルチスレッドが必要
・Handlerで実現
・Handlerを使わない場合に起きる例外は実行スレッドのチェックで発生
・Handlerを使うと、UI Threadの持つキューにジョブを登録できる
・キューはUI Threadにより実行される
・別スレッドからUI Threadに処理を登録するのでスレッドチェックで例外が発生しない
---

・メッセージを送るメソッド
---
final boolean  post(Runnable r)
final boolean  postAtFrontOfQueue(Runnable r)
final boolean  postAtTime(Runnable r, Object token, long uptimeMillis)
final boolean  postAtTime(Runnable r, long uptimeMillis)
final boolean  postDelayed(Runnable r, long delayMillis)

final boolean  sendEmptyMessage(int what)
final boolean  sendEmptyMessageAtTime(int what, long uptimeMillis)
final boolean  sendEmptyMessageDelayed(int what, long delayMillis)

final boolean  sendMessage(Message msg)
final boolean  sendMessageAtFrontOfQueue(Message msg)
boolean        sendMessageAtTime(Message msg, long uptimeMillis)
final boolean  sendMessageDelayed(Message msg, long delayMillis)
---

・メッセージを受け取るメソッド
---
void  handleMessage(Message msg)
---


(3) HTML を読み込む

    webView1.loadUrl("file:///android_asset/index.html");    // (3)

プロジェクトの assets フォルダは、「/android_asset」でアプリケーション内から参照
できる。


(5) HTML で JavaScript が使えるようにする

    WebSettings settings = webView1.getSettings();    // (4)
    settings.setJavaScriptEnabled(true);    // (5)


△ WebSettings クラス

WebView オブジェクトに関する設定関係のオブジェクト。

java.lang.Object
   +    android.webkit.WebSettings


・主なメソッド
---
synchronized void setJavaScriptEnabled(boolean flag)  JavaScript 有効無効の設定
void     setSaveFormData(boolean save)       フォームデータ保存の有効無効の設定
void     setSavePassword(boolean save)       パスワード保存の有効無効の設定
void     setSupportZoom(boolean support)     ズームの有効無効の設定
---


(6) JavaScript から Java のメソッドを使えるようにする

    webView1.addJavascriptInterface(new JavaScriptInterfaceFunctions(this,
            handler), "AndroidFunctions");    // (6)

形式
---
void  addJavascriptInterface(Object JavaScriptインターフェース・オブジェクト, 
                                            String インターフェース名)
---

JavaScript 側からは、インターフェース名.メソッド名() で呼び出せる。


(7) JavaScript で、alert や prompt が使えるようにする

    webView1.setWebChromeClient(new WebChromeClient());    // (7)


△ WebChromeClient クラス

JavaScript で使う prompt や alert は、Android のダイアログになる。これらをサポー
トするクラス。デフォルトで用意されているが、必要に応じて、このクラスのメソッドを
オーバーライドしてカスタマイズする。

java.lang.Object
   +    android.webkit.WebChromeClient

・JavaScript 関係の主なメソッド
---
boolean  onJsAlert(WebView view, String url, String message, JsResult result)
boolean  onJsConfirm(WebView view, String url, String message, JsResult result)
boolean  onJsPrompt(WebView view, String url, String message, 
                                    String defaultValue, JsPromptResult result)
boolean  onJsTimeout()
---


(8) JavaScript の関数を呼び出す

    webView1.loadUrl("javascript:showText()");    // (8)

・形式
---
webView1.loadUrl("javascript:関数名(引数リスト)");
---


▲ JavaScript から使う関数を定義したクラス

単なる Java のクラスとして作ればよい。
ただし、アクティビティのビューを操作するときは、ハンドラー・オブジェクトが必要。

□ JavaScriptInterfaceFunctions.java
---
package jp.marunomaruno.android.webviewjavascript;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.widget.TextView;
import android.widget.Toast;

public class JavaScriptInterfaceFunctions {

    private Context context;
    private Handler handler;    // (1)

    public JavaScriptInterfaceFunctions(Context context, Handler handler) {
        this.context = context;
        this.handler = handler;
    }

    public void showToast(String message) {
        Toast.makeText(context, getMessage(message), Toast.LENGTH_LONG).show();
    }

    public void setTextView(final String message) {
            handler.post(new Runnable() {    // (2)
                public void run() {    // (3)
                    TextView textView1 = (TextView) ((Activity) context)
                    .findViewById(R.id.textView1);
                    textView1.setText(getMessage(message));
                }
            });
    }

    public String getMessage(String message) {
        return String.format("<span class='html'>☆%s☆</span> %s", message, 
                                                            getMessage());
    }

    public String getMessage() {
        return String.format("<span class='java'>★%s★</span>", 
                                                        "これはJavaの文字列");
    }
}
---

(1) JavaScript から呼ばれたメソッドで、アクティビティのビューを操作できるように
する

コンストラクターの引数をそのまま設定する。

    private Handler handler;    // (1)


(2)(3) テキスト・ビューに値を設定する

ハンドラーの post() メソッドを使って実行する。

    handler.post(new Runnable() {    // (2)
        public void run() {    // (3)
            TextView textView1 = (TextView) ((Activity) context)
                .findViewById(R.id.textView1);
            textView1.setText(getMessage(message));
        }
    });


▲ HTML ファイル

通常の HTML ファイル。
JavaScript から、Android の Java メソッドを呼ぶには、インターフェース名が必要。
    インターフェース名.メソッド名(引数リスト)

□ assets/index.html
---
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
                                "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style TYPE="text/css">
#area { background-color: lightgreen; }
.html { color: red; }
.java { color: green; }
</style>
<script type="text/javascript">
// Android のトースト表示
function showToast(message){
    AndroidFunctions.showToast(message);    // (1)
}

// Android のテキストビューに設定
function setTextView(message){
    AndroidFunctions.setTextView(message);
}

// メッセージを組み立て
function makeMessage(message){
    var message = AndroidFunctions.getMessage(message);    // (2)
    document.getElementById("area").innerHTML = message; 
}

// メッセージ取得
function getMessage(){
    var message = AndroidFunctions.getMessage();    // (3)
    document.getElementById("area").innerHTML = message; 
}

// メッセージをプロンプトから取得する
function messageFromPrompt(){
    var message = prompt("文字列を入力してください。", "");    // (4)
    alert(message);     // (5)
}

// Android から呼ばれる
function showText(){
    document.getElementById("area").innerHTML = "Javaから呼ばれたJavaScriptの関
数"; 
}
   
</script>
<title>Insert title here</title>
</head>
<body>
<p>
<input type="button" value="Androidのトーストを表示"
    onclick="showToast('HTMLの文字列')"/>
</p>

<p>
<input type="button" value="Androidのテキストビューに表示"
    onclick="setTextView('HTMLの文字列')"/>
</p>

<p>
<input type="button" value="Androidからメッセージを組み合わせる"
    onclick="makeMessage('HTMLの文字列')"/>
</p>

<p>
<input type="button" value="プロンプトから文字列を読んでアラート表示"
    onclick="messageFromPrompt()"/>
</p>

<p>
<input type="button" value="Androidからメッセージを得る"
    onclick="getMessage()"/>
</p>

<p>
<div id="area">ここに文字列が入る</div>
</p>

</body>

</html>
---

(1) Java 側のメソッドの呼び出し

    AndroidFunctions.showToast(message);    // (1)

Java 側では以下のような設定をしている。
    webView1.addJavascriptInterface(new JavaScriptInterfaceFunctions(this,
            handler), "AndroidFunctions");


(2)(3) Java 側のメソッドはオーバーロード可能

    var message = AndroidFunctions.getMessage(message);    // (2)
    var message = AndroidFunctions.getMessage();    // (3)


(4)(5) prompt や alert を使う

    var message = prompt("文字列を入力してください。", "");    // (4)
    alert(message);     // (5)

Java 側では以下のような設定をしている。
    webView1.setWebChromeClient(new WebChromeClient());


▲レイアウト

□ res/layout/main.xml
---
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <WebView
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="400dp" />    <!-- (1) -->

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClickHandler"
        android:text="JavaScriptの呼び出し" />

</LinearLayout>
---

(1) WebView

    <WebView
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="400dp" />    <!-- (1) -->


▲ マニフェスト

---
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.marunomaruno.android.webviewjavascript"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />
    <uses-permission android:name="android.permission.INTERNET"/>  <!-- (1) -->

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".WebViewJavaScript01Activity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
---

(1) WebView を使うときは以下の設定が必要

    <uses-permission android:name="android.permission.INTERNET"/>  <!-- (1) -->

                                                                        以上



最新の画像もっと見る

コメントを投稿