web-dev-qa-db-ja.com

Javascriptコールバック関数のパスAndroid

Javaで実装されたjavascriptインターフェイスがあります。これは、webviewにロードされたjavascriptコードによって呼び出されます。

JS Inside WebView:

Android.myFunction(function(data){
    console.log(data);
});

Java:

public class JavaScriptInterface {

    Context context;
    WebView webView;

    JavaScriptInterface(Context c, WebView w) {
        context = c;
        webView = w;
    }

    public void myFunction(String callback) {
        //when I log callback, it is "undefined"
         String someData = "Yay for data";
         String js =
             "javascript:(function() { "
                 + "var callback = " + callback + ";"
                 + "callback('" + someData + "');"
             + "})()";
        webView.loadUrl(js);
    }
}

Webviewによってロードされる文字列は、最終的に次のようになります。

javascript:(function() {var callback = undefined; undefined();})()

私にはいくつかのアイデアがあります:

a。 JSで文字列としてコールバックを作成します。

b。 Android.myFunction()に渡す前に、コールバックのtoString()を呼び出します。

私の質問は、これを行う最善の方法は何ですか?オブジェクトをAndroidに渡すだけで、魔法のように動作します。明らかにそうではありません。;)次の最善の方法は何ですか?

29
Jonathan

指定した方法で関数を渡すことはできません。関数をAndroid.myDataに渡しますが、Android.myDataは文字列を受け取ります。代わりに、おそらく

var myCallback = console.log;
Android.myFunction("myCallback");

まだコールバックにデータを渡していないという問題があります。それはあなたの質問に直接関連していませんが、同じキャスト/文字列の問題があるため問題になります(JSON経由で解決可能ですが、Androidその部分を処理しました)。

最後に、おそらくjavascript:文字列を

String js = "javascript:" + callback + "();";

しかし、もちろん、最初にテストしてください;)

12
David Souther

同様の問題がありました:Webアプリ内から、ネイティブAndroid確認ダイアログを使用したいと思います。これは、確認ダイアログの結果とともにAndroidからJavascript部分にコールバックする必要があることを意味します。

私はこれを次のように解決しました:

_function foo() {
    // user confirmation needed
    var dataString = <encode data into string>;
    MyClient.showConfirmationDialog('myCallBackFunction', dataString, 'A title', 'A message');
}
_

上記のコードは、Android javascriptインターフェイスを呼び出します(以下を参照)。 javascriptはコールバックメソッドmyCallbackFunction()を提供し、その名前はパラメーターとしてAndroidに渡されます(データ文字列、タイトル、メッセージとともに)。コールバック関数は次のようになります。

_function myCallbackFunction(dataString, result) {
    var data = <decode data from dataString>;
    if (result) {
        // user has confirmed
    } else {
        // user has denied
    }
}
_

Android側では、最初にアクティビティのonCreate()メソッドでJavascriptインターフェイスをアクティブにします。

_public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    WebView webView = new WebView(this);
    setContentView(webView);
    WebSettings settings = webView.getSettings();
    settings.setJavaScriptEnabled(true);
    webView.addJavascriptInterface(new MyJavascriptInterface(webView), "MyClient");
}
_

MyJavascriptInterfaceの実装は、対応するAndroidダイアログを作成し、結果をjavascriptに返します。

_    WebView webView;

    public MyJavascriptInterface(WebView w) {
         this.webView = w;
    }

    @JavascriptInterface
    public void showConfirmationDialog(final String callbackFunction, final String data, String title,
            String message) {

        Dialog.OnClickListener positiveListener = new Dialog.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', true)");
            }
        };
        Dialog.OnClickListener negativeListener = new Dialog.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', false)");
            }
        };

        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle(title).setMessage(message).setPositiveButton("Ok", positiveListener)
                .setNegativeButton("Cancel", negativeListener).setCancelable(false);
        builder.create().show();
    }
_

コールバック関数の名前をAndroidに渡すと、確認ダイアログへの複数の呼び出しを使用できます。各呼び出しには、実際のアクションを実行する独自の関数が装備されています。データ文字列には、アクションの実行に必要なすべてのデータが含まれます(Jsonエンコードされたオブジェクトを含めることもできます)。

38
csoltenborn

WebViewでは、ウィンドウコンテキストでJavaScriptを直接実行できます。したがって、リソースURLを介してJavaScriptを渡す必要はありません。

これは、データをhtmlページに戻す承認済みの方法です

/**
 * This is an approved way to pass data back to the html page
 */
 webView.evaluateJavascript("alert('pass here some ...')", new ValueCallback<String>() {
       @Override
       public void onReceiveValue(String s) {

        }
    });

公式文書の詳細

現在表示されているページのコンテキストでJavaScriptを非同期に評価します。 null以外の場合、| resultCallback |その実行から返された結果で呼び出されます。このメソッドはUIスレッドで呼び出す必要があり、コールバックはUIスレッドで行われます。

互換性に関する注意。 N以降を対象とするアプリケーションでは、空のWebViewからのJavaScript状態は、loadUrl(String)などのナビゲーション間で保持されなくなりました。たとえば、loadUrl(String)を呼び出す前に定義されたグローバル変数と関数は、読み込まれたページに存在しません。アプリケーションは、代わりにaddJavascriptInterface(Object、String)を使用して、ナビゲーション間でJavaScriptオブジェクトを永続化する必要があります。

公式のWebViewドキュメントへのリンク

5
Yoraco Gonzales