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

inFablic

Fablic開発者ブログ

Drekkarを使ってAndroid WebViewのJavascriptブリッジ処理をEvent Bus風に書く

Android

こんにちはFablic エンジニアの@cutmailです。

この記事は、Fablic Advent Calendar 2016 1日目のエントリーです。

2016年もあと1か月で終わってしまいますが、いかがお過ごしでしょうか。

アプリ開発をする際に、一般的にUIを全てネイティブコードで作ることはユーザー体験的には良くなりそうですが、 どうしても一部をWebViewにしなければならないなどのケースってありますよね。

WebViewからHTMLやURLを指定して、そのHTML内で処理が完結すれば良いのですが、 Android JavaとHTML内のJavascriptで相互に呼び出しを行いたいみたいなケースもあると思います。

弊社のアプリフリルでも一部の画面をWebViewを使って作っていたりします。

AndroidのWebViewクラスではaddJavascriptInterfaceメソッドを使うことで、任意のJavascriptのインターフェースを定義できます。

そして実際に、JavaからJavascriptのメソッドを呼ぶ、JavascriptからJavaのメソッドを呼ぶ処理はこういう感じで書くことができます。

JavaからJavascriptのメソッドを呼ぶ

Java

webView.loadUrl("javascript:showMessage('call From Java');");

Javascript

function showMessage() {
    $('body').append('<p>Received From Java</p>');
}

JavascriptからJavaのメソッドを呼ぶ

Java

public class JavascriptInterfaceActivity extends AppCompatActivity {

    private WebView webView;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_javascript_interface);

        webView = (WebView) findViewById(R.id.webview);
        webView.loadUrl("file:///android_res/raw/javascript_interface.html");
        webView.getSettings().setJavaScriptEnabled(true);
        webView.addJavascriptInterface(new JSInterface(this), "droid");
    }

    final class JSInterface {
        private final Context context;

        JSInterface(Context context) {
            this.context = context;
        }

        @JavascriptInterface
        public void showToast(final String message) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
}

Javascript

droid.showToast('call from Javascript');

これでJavaとJavascriptで相互にメソッド呼び出しをすることができますが、 ぱっと見た感じわかりやすいとは言い難い部分がありそうです。

そこでDrekkarというライブラリをご紹介します。

Drekkar

https://github.com/coshx/drekkar

DrekkarはJavaとJavascriptの間でEvent Bus形式で相互に呼び出しをすることができるライブラリです。

実際にJavascriptInterfaceを使っていた部分をDrekkarを使って書き換えてみます。

JavaからJavascriptのメソッドを呼ぶ

Java

webView = (WebView) findViewById(R.id.webview);
webView.loadUrl("file:///android_res/raw/drekkar.html");
webView.getSettings().setJavaScriptEnabled(true);

Drekkar.getDefault(this, webView, new WhenReady() {
  @Override
  public void run(EventBus eventBus) {
    eventBus.post("showMessage");
  }
});

Javascript

Drekkar.getDefault().register("showMessage", function(name) {
    $('body').append('<p>Received From Java</p>');
});

JavascriptからJavaのメソッドを呼ぶ

Java

webView = (WebView) findViewById(R.id.webview);
webView.loadUrl("file:///android_res/raw/drekkar.html");
webView.getSettings().setJavaScriptEnabled(true);

Drekkar.getDefault(this, webView, new WhenReady() {
  @Override
  public void run(EventBus eventBus) {
    eventBus.register("showToast", new Callback() {
      @Override
      public void run(String name, final Object data) {
        runOnUiThread(new Runnable() {
          @Override
          public void run() {
            Toast.makeText(getApplicationContext(), data.toString(), Toast.LENGTH_SHORT).show();
          }
        });
      }
    });
  }
});

Javascript

Drekkar.getDefault().post('showToast', 'Call From Javascript');

ほかにもDrekkarではListの値をそのまま渡すこともできたりします。

Drekkar.getDefault(this, webView, new WhenReady() {
  @Override
  public void run(EventBus bus) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);

    bus.post("List", list);
  }
});

JavascriptでListを受け取る例

Drekkar.getDefault().register("List", function(name, data) {
    if (JSON.stringify(data) == JSON.stringify([1, 2, 3])) {
        alert("ok");
    }
});

その他にもBool, Int, Float, Double, String, Arrayなどの型もサポートしているようです。 気になる方はサンプルコードが公開されているのでこちらをご覧ください。 https://github.com/coshx/drekkar/blob/master/app/src/main/java/com/coshx/drekkartest/EventDataActivity.java

まとめ

  • Drekkarを使うとJavaとJavascriptのブリッジ処理をEvent Busっぽく書けてJavascript Interfaceをうまく隠蔽できる
  • Javascript Interfaceと違い様々な型の値を受け渡しすることができる
  • Javascript Intefaceの冗長なコードを書く必要がなくなる

今回使ったサンプルコード

https://github.com/cutmail/DrekkarExample