1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Android] Javascript Interface

Last updated at Posted at 2024-09-21

Javascript Interfaceとは?

スマホアプリ内にウェブページを埋め込むwebViewを使う際、
フロントエンドのコードがスマホアプリのネイティブコードを叩く手段が提供されている。

それがJavascriptInterface

使い方導入

kotlin実装

class MyJavascriptInterfaces {
    @JavascriptInterface
    fun hello(){
        Log.i("webViewApp", "Hello, World")
    }
}

というJavascript Interfaceを搭載したクラスを作り

binding.webView.apply {
    settings.javaScriptEnabled = true
    addJavascriptInterface(MyJavascriptInterfaces(), "MyJavascriptInterface")
    loadUrl("https://www.google.co.jp/")
}

webViewのaddJavascriptInterface関数を使用して登録するだけ。簡単。

フロントエンドから叩く方法

MyJavascriptInterface.hello()

で叩ける。

もしもリリース済みのアプリで

  1. JavascriptInterfaceを導入しようとしている場合
  2. JavascriptInterfaceの関数を追加しようとしている場合

は、過去のアプリ上でエラーが発生しないよう

MyJavascriptInterface?.hello?.()

とすると安全である。

実際に動かしてみる

webViewアプリを起動して
Chrome上で chrome://inspect/#devices を開いてください

image.png

このように現在起動しているwebView画面の一覧が出て来ます。
スマホでGoogle Chrome等のブラウザを開いているとそれも一覧に出て来ます。

inspectを押すと見慣れた物が出て来ます。
先ほどのJavascriptInterface呼び出し関数をconsole上で実行すると

image.png
エラーが発生せず
LogCatを確認すると Hello, World が正常に出力されています。

取り扱える値

誰かドキュメント探して教えてください(土下座)!!!探しても見つからなかったので実際に動かして試しました。

結論から言うと、引数と戻り値ともに

  • Boolean
  • Int
  • Double
  • String
  • String?
    が取り扱える。

引数限定として

  • StringArray
    も渡せる。
@JavascriptInterface
fun getInt(v: Int): Int {
    return v+2
}

@JavascriptInterface
fun getBoolean(v: Boolean): Boolean {
    return !v
}

@JavascriptInterface
fun getDouble(v: Double): Double {
    return v+1
}

@JavascriptInterface
fun getString(v: String): String {
    return "hello~ $v"
}

@JavascriptInterface
fun getOptionalString(v: String?): String? {
    return v?.let{"hello~ $it"}
}

@JavascriptInterface
fun getStringArray(v: Array<String>) {
    v.forEach {
        element -> Log.i("WebViewApp", element)
    }
}

応用例

Stringが扱えるので、jsonを一回stringに変換すれば相互にjsonの受け渡しが可能です。

@JavascriptInterface
fun getJsonString(v: String): String {
    val json: JSONObject = JSONObject(v)
    val name: String = json.get("name") as String
    val age: Int = json.get("age") as Int
    json.put("status", "alive")
    return json.toString()
}
let character = {"name": "taro", "age":25}
// jsonをstringに変換すると共にJavascriptInterfaceで値の受け渡し
let returnString = MyJavascriptInterface.getJsonString(JSON.stringify(character))
// stringをjsonに変換
let json = JSON.parse(returnString)

注意点

このJavascriptInterfaceは UIスレッド上 で実行されます。その為できるだけ重たい処理をさせる事は避けた方が無難です。

もしも重たい処理をしたい場合は明確に別スレッドやコルーチンを使用して非同期で処理をするのがオススメです。

@JavascriptInterface
fun heavyTask1(): String {
    Thread.sleep(10000)
    return "DONE!"
}

@JavascriptInterface
fun heavyTask2(callback: String) {
    CoroutineScope(Dispatchers.IO).launch {
        Thread.sleep(10000)
        val returnValue = "DONE!"
        withContext(Dispatchers.Main){
            binding.webView.evaluateJavascript("javascript:$callback('$returnValue')", null)
        }
    }
}
function handleResult(result) {
    console.log(result);
}

HeavyJavascriptInterfaces.heavyTask2("handleResult")

heavyTask1では10秒の間、UI処理が中断されてしまいユーザー体験が悪くなります。
一方でheavyTask2では処理自体は別スレッドで実行し、evaluateJavascriptでcallBack関数を呼んでいます。

サンプルレポジトリ

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?