Các chức năng gọi điện của Android trong WebView


249

Tôi đang cố gắng gọi một số javascriptchức năng ngồi trong một htmltrang chạy bên trong một android webview. Khá đơn giản những gì mã cố gắng thực hiện bên dưới - từ ứng dụng Android, gọi một javascripthàm với thông báo kiểm tra, trong đó inturn gọi hàm java trở lại trong ứng dụng android hiển thị thông báo kiểm tra qua bánh mì nướng.

Các javascripthình chức năng thích:

function testEcho(message){
     window.JSInterface.doEchoTest(message);
}

Từ WebView, tôi đã thử gọi các javascriptcách sau mà không gặp may:

myWebView.loadUrl("javascript:testEcho(Hello World!)");
mWebView.loadUrl("javascript:(function () { " + "testEcho(Hello World!);" + "})()");

Tôi đã kích hoạt javascripttrênWebView

myWebView.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
myWebView.addJavascriptInterface(myJSInterface, "JSInterface"); 

Và đây là Javalớp học

public class JSInterface{

private WebView mAppView;
public JSInterface  (WebView appView) {
        this.mAppView = appView;
    }

    public void doEchoTest(String echo){
        Toast toast = Toast.makeText(mAppView.getContext(), echo, Toast.LENGTH_SHORT);
        toast.show();
    }
}

Tôi đã dành rất nhiều thời gian để đi vòng quanh để xem những gì tôi có thể làm sai. Tất cả các ví dụ tôi đã tìm thấy sử dụng phương pháp này. Có ai thấy điều gì sai ở đây không?

Chỉnh sửa: Có một số javascripttệp bên ngoài khác đang được tham chiếu & sử dụng trong html, chúng có thể là vấn đề không?


13
Mã bạn cố gắng sử dụng bỏ lỡ dấu ngoặc kép ở phía javascript.
Paul de Vrieze

2
Xin lưu ý rằng vì Android 4.2 bạn bắt buộc phải sử dụng trình @JavascriptInterfacetrang trí trên các phương thức Java mà bạn muốn cung cấp cho WebView thông qua Giao diện JavaScript.
Fred

1
Từ mã myWebView.loadUrl("javascript:testEcho('Hello World!')");tôi hiểu rằng bạn đã đính kèm tệp html vào webview đó. Bạn có thể cho tôi biết làm thế nào bạn làm điều đó?
Tony_craft

Câu trả lời:


195

Tôi đã tìm ra vấn đề là gì: thiếu dấu ngoặc kép trong tham số testEcho (). Đây là cách tôi nhận được cuộc gọi để làm việc:

myWebView.loadUrl("javascript:testEcho('Hello World!')");

vui lòng xem trong các liên kết stackoverflow.com/questions/9079374/ từ
kamal_tech_view

Thật tuyệt, nhưng làm thế nào để bạn chuyển một đối tượng Java sang một hàm JavaScript làm đối số?
Kovács Imre

1
@ KovácsImre String.Format ("javascript: testEcho ('% d', '% d', '% d')", 1, 2, 3); Tôi đoán
user456015 27/12/13

Cảm ơn, tôi cũng đã tìm ra trong thời gian đó.
Kovács Imre

1
Bắt đầu với KitKat, có phương thức AssessmentJavascript, kiểm tra stackoverflow.com/a/32163655/3063226
Heitor

117

Từ kitkat trở đi, hãy sử dụng phương thức AssessmentJavascript thay vì loadUrl để gọi các hàm javascript như bên dưới

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        webView.evaluateJavascript("enable();", null);
    } else {
        webView.loadUrl("javascript:enable();");
    }

2
Tại sao nên sử dụng AssessmentJavascript () thay vì loadUrl ()?
Kamran Bigdely

2
@kami loadUrl () sẽ tải lại trang và gọi lại onPageFinished ()
Zach

1
@Zach Vẫn là một vấn đề trên pre-KitKat, phải không?
Vsevolod Ganin

2
@kami Thêm vào câu trả lời của Zach, AssessmentJavascript (), sẽ chạy JavaScript không đồng bộ. Vì vậy, chúng ta có thể tránh chặn luồng UI bằng cách sử dụng AssessmentJavascript ().
Prasad

loadUrlcũng khiến bàn phím phần mềm hiển thị khi tôi cố gắng điền giá trị vào trường nhập.
Joshua

34
public void run(final String scriptSrc) { 
        webView.post(new Runnable() {
            @Override
            public void run() { 
                webView.loadUrl("javascript:" + scriptSrc); 
            }
        }); 
    }

và nếu điều này không hoạt động, hãy thực hiện Chủ đề mới (Runnaable () {.. <như trên> ..}). start ()
Radu Simionescu

26

Tôi đã tạo một trình bao bọc đẹp để gọi các phương thức JavaScript; nó cũng hiển thị lỗi JavaScript trong nhật ký:

private void callJavaScript(String methodName, Object...params){
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("javascript:try{");
    stringBuilder.append(methodName);
    stringBuilder.append("(");
    for (int i = 0; i < params.length; i++) {
        Object param = params[i];
        if(param instanceof String){
            stringBuilder.append("'");
            stringBuilder.append(param.toString().replace("'", "\\'"));
            stringBuilder.append("'");
        }
        if(i < params.length - 1){
            stringBuilder.append(",");
        }
    }
    stringBuilder.append(")}catch(error){Android.onError(error.message);}");
    webView.loadUrl(stringBuilder.toString());
}

Bạn cũng cần thêm điều này:

private class WebViewInterface{

    @JavascriptInterface
    public void onError(String error){
        throw new Error(error);
    }
}

Và thêm giao diện này vào webview của bạn:

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");

Chức năng này, tuy nhiên tốt như một ý tưởng, đã thực hiện sai. Cuộc gọi này: final Object a = new Object(); callJavaScript(mBrowser, "alert", 1, true, "abc", a);sẽ mang đến SyntaxErrorvới Unexpected tokenmà không có gì ngạc nhiên khi bạn sẽ xem xét các js tạo ra gọi:javascript:try{alert(,,'abc',,)}catch(error){console.error(error.message);}
Lukasz 'Severiaan' Grela

Ngay cả cuộc gọi đơn giản cũng callJavaScript(mBrowser, "alert", "abc", "def");tạo ra lỗi vì luôn có dấu phẩy giả mạo ở cuối. -1 từ tôi.
Lukasz 'Severiaan' Grela

1
@ Lukasz'Severiaan'Grela tnx, tôi đã sửa nó. PS Lần sau đừng lười biếng, bạn có thể tự sửa nó ...;)
Ilya Gazman

16
Để tham khảo trong tương lai: Hãy sống tích cực. Chỉ ra một lỗi trong mã không phải là lười biếng. Nó vẫn là phản hồi hữu ích.
DW

Tôi đoán điều này sẽ không hoạt động nếu bất kỳ tham số nào có 'ký tự trong đó? Ví dụ:callJavascript(mBrowser, "can't do it");
Kostanos

18

Có bạn có lỗi cú pháp. Nếu bạn muốn nhận lỗi Javascript và in các câu lệnh trong logcat của mình, bạn phải triển khai onConsoleMessage(ConsoleMessage cm)phương thức trong WebChromClient của mình. Nó cung cấp các dấu vết ngăn xếp hoàn chỉnh như bảng điều khiển Web (Kiểm tra phần tử). Đây là phương pháp.

public boolean onConsoleMessage(ConsoleMessage cm) 
    {
        Log.d("Message", cm.message() + " -- From line "
                             + cm.lineNumber() + " of "
                             + cm.sourceId() );
        return true;
    }

Sau khi thực hiện, bạn sẽ nhận được các lỗi Javascript và in các câu lệnh ( console.log) trên logcat của mình.


2
Tôi tin rằng nó có trên WebChromClient chứ không phải WebViewClient.
Michael Levy

Vâng, bạn đúng @MichaelLevy. Cảm ơn đã chỉ cho tôi cho sai lầm đó. Bây giờ tôi đã chỉnh sửa câu trả lời của tôi.
Dinesh

1
Cảm ơn, câu trả lời của bạn là một thứ tôi cần. Tôi cũng đề nghị mọi người ghi đè onJsAlert () trong WebChromClient. Sự kết hợp giữa ghi nhật ký và cảnh báo javascript có thể thực sự hữu ích khi gỡ lỗi Javascript được lưu trữ trong chế độ xem web.
Michael Levy

13

Sửa đổi câu trả lời @Ilya_Gazman

    private void callJavaScript(WebView view, String methodName, Object...params){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("javascript:try{");
        stringBuilder.append(methodName);
        stringBuilder.append("(");
        String separator = "";
        for (Object param : params) {               
            stringBuilder.append(separator);
            separator = ",";
            if(param instanceof String){
                stringBuilder.append("'");
            }
                stringBuilder.append(param.toString().replace("'", "\\'"));
            if(param instanceof String){
                stringBuilder.append("'");
            }

        }
        stringBuilder.append(")}catch(error){console.error(error.message);}");
        final String call = stringBuilder.toString();
        Log.i(TAG, "callJavaScript: call="+call);


        view.loadUrl(call);
    }

sẽ tạo chính xác các cuộc gọi JS, vd

callJavaScript(mBrowser, "alert", "abc", "def");
//javascript:try{alert('abc','def')}catch(error){console.error(error.message);}
callJavaScript(mBrowser, "alert", 1, true, "abc");
//javascript:try{alert(1,true,'abc')}catch(error){console.error(error.message);}

Lưu ý rằng các đối tượng sẽ không được truyền chính xác - nhưng bạn có thể tuần tự hóa chúng trước khi truyền dưới dạng đối số.

Ngoài ra, tôi đã thay đổi lỗi xảy ra, tôi đã chuyển nó sang nhật ký giao diện điều khiển có thể được nghe bởi:

    webView.setWebChromeClient(new CustomWebChromeClient());

và khách hàng

class CustomWebChromeClient extends WebChromeClient {
    private static final String TAG = "CustomWebChromeClient";

    @Override
    public boolean onConsoleMessage(ConsoleMessage cm) {
        Log.d(TAG, String.format("%s @ %d: %s", cm.message(),
                cm.lineNumber(), cm.sourceId()));
        return true;
    }
}

Cảm ơn. Phương thức này sẽ thoát khỏi ký tự bên trong của bất kỳ biến nào? Nói cách khác, nó sẽ làm việc với : callJavascript(mBrowser, "can't do it");?
Kostanos

1
Chỉ cần chỉnh sửa câu trả lời và thêm lối thoát cho 'nhân vật
Kostanos

2

Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

MainActivity.java


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.bluapp.androidview.R;

public class WebViewActivity3 extends AppCompatActivity {
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view3);
        webView = (WebView) findViewById(R.id.webView);
        webView.setWebViewClient(new WebViewClient());
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl("file:///android_asset/webview1.html");


        webView.setWebViewClient(new WebViewClient(){
            public void onPageFinished(WebView view, String weburl){
                webView.loadUrl("javascript:testEcho('Javascript function in webview')");
            }
        });
    }
}

tài sản tập tin

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>WebView1</title>
<meta forua="true" http-equiv="Cache-Control" content="max-age=0"/>
</head>

<body style="background-color:#212121">
<script type="text/javascript">
function testEcho(p1){
document.write(p1);
}
</script>
</body>

</html>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.