WebView의 Android 호출 JavaScript 함수


249

내부에서 실행 javascript되는 html페이지에 앉아있는 일부 함수 를 호출하려고 합니다 android webview. 코드가 아래에서 수행하려는 작업은 매우 간단합니다 .Android 앱에서 javascript테스트 메시지가 있는 함수를 호출합니다. 테스트 메시지는 토스트를 통해 테스트 메시지를 표시하는 Android 앱에서 다시 Java 함수를 호출합니다.

javascript기능 외모가 좋아 :

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

WebView에서 javascript운없이 다음과 같은 방법으로 전화를 시도했습니다 .

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

나는 활성화 javascript했다WebView

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

그리고 여기에 Java클래스

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();
    }
}

나는 내가 뭘 잘못하고 있는지 알기 위해 인터넷 검색에 많은 시간을 보냈다. 내가 찾은 모든 예제는이 접근법을 사용합니다. 여기에 잘못된 것이 있습니까?

편집 :javascript 에서 참조되고 사용되는 다른 외부 파일 이 몇 가지 있는데 html문제가 될 수 있습니까?


13
사용하려는 코드는 자바 스크립트 측에서 따옴표를 누락합니다.
Paul de Vrieze

2
Android 4.2부터는 @JavascriptInterfaceJavaScript 인터페이스를 통해 WebView에 제공하려는 Java 메소드 에서 데코레이터 를 사용해야합니다 .
Fred

1
코드 myWebView.loadUrl("javascript:testEcho('Hello World!')");에서 html 파일을 이미 해당 웹보기에 첨부했음을 이해합니다. 어떻게했는지 말해 주실 수 있습니까?
Tony_craft

답변:


195

문제가 무엇인지 알아 냈습니다 : testEcho () 매개 변수에 따옴표가 없습니다. 이것이 내가 전화하라는 방법입니다.

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


멋지지만 Java 객체를 인수로 JavaScript 함수에 어떻게 전달합니까?
Kovács Imre

1
@ KovácsImre String.Format ( "javascript : testEcho ( '% d', '% d', '% d')", 1, 2, 3); 생각합니다
user457015

고마워, 나는 또한 그 동안 발견했다.
Kovács Imre

1
KitKat으로 시작하면 validateJavascript 메소드가 있습니다. stackoverflow.com/a/32163655/3063226
Heitor

117

kitkat부터는 다음과 같이 javascript 함수를 호출하기 위해 대신 loadUrl을 사용하십시오.

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

2
loadUrl () 대신 평가 자바 스크립트 ()를 사용해야하는 이유는 무엇입니까?
Kamran Bigdely

2
@kami loadUrl ()은 페이지를 다시로드하고 onPageFinished ()를 다시 호출합니다
Zach

1
@Zach 그것은 여전히 ​​KitKat 이전의 문제입니다.
Vsevolod Ganin

2
@kami Zach 답변에 추가하면 평가 자바 스크립트 ()는 자바 스크립트를 비동기 적으로 실행합니다. 따라서 validateJavascript ()를 사용하여 UI 스레드를 차단하지 않아도됩니다.
Prasad

loadUrl또한 입력 필드에 값을 입력하려고 할 때 소프트웨어 키보드가 표시됩니다.
Joshua

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

이것이 작동하지 않으면, 새로운 Thread (new Runnaable () {.. <like above> ...}). start ()
Radu Simionescu

26

JavaScript 메소드를 호출하기위한 멋진 래퍼를 만들었습니다. 또한 로그에 JavaScript 오류가 표시됩니다.

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());
}

이것도 추가해야합니다 :

private class WebViewInterface{

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

그리고이 인터페이스를 webview에 추가하십시오.

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

이 기능은 아이디어로는 좋지만 구현이 잘못되었습니다. 이 호출 : final Object a = new Object(); callJavaScript(mBrowser, "alert", 1, true, "abc", a);에 얻을 것 SyntaxError와 함께 Unexpected token하는 당신이 생성 된 JS 볼 때 놀라운 일이 아니다 호출 :javascript:try{alert(,,'abc',,)}catch(error){console.error(error.message);}
루카스 'Severiaan'Grela

callJavaScript(mBrowser, "alert", "abc", "def");끝에 항상 불량 쉼표가 있으므로 간단한 호출조차도 오류를 생성합니다. 나에게서 -1.
Lukasz 'Severiaan'Grela

1
@ Lukasz'Severiaan'Grela tnx, 나는 그것을 고쳤다. 추신 다음에 게으르지 마라. 스스로 고칠 수 ... ...)
Ilya Gazman

16
나중에 참조 할 것 : 긍정적 인 태도를 유지합시다. 코드에서 오류를 지적하는 것은 게으르지 않습니다. 여전히 유용한 의견입니다.
DW

매개 변수 중 하나에 '문자가있는 경우이 기능이 작동하지 않는 것 같습니다. 예 :callJavascript(mBrowser, "can't do it");
Kostanos

18

예, 구문 오류가 있습니다. logcat에서 Javascript 오류 및 인쇄 명령문을 얻으 onConsoleMessage(ConsoleMessage cm)려면 WebChromeClient 에서 메소드를 구현해야합니다 . 웹 콘솔 (검사 요소)과 같은 완전한 스택 추적을 제공합니다. 방법은 다음과 같습니다.

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

구현 후에는 console.loglogcat에 Javascript 오류 및 인쇄 문 ( )이 표시됩니다.


2
나는 WebViewClient가 아니라 WebChromeClient에 있다고 생각합니다.
Michael Levy

네, @MichaelLevy가 맞습니다. 그 실수를 지적 해 주셔서 감사합니다. 이제 답변을 편집했습니다.
Dinesh

1
고마워요, 당신의 대답은 내가 필요한 것입니다. 또한 사람들이 WebChromeClient에서 onJsAlert ()를 재정의하는 것이 좋습니다. 웹뷰에서 호스팅되는 자바 스크립트를 디버깅 할 때 자바 스크립트 로깅 및 알림 조합이 실제로 도움이 될 수 있습니다.
Michael Levy

13

@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);
    }

JS 호출을 올바르게 생성합니다.

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);}

객체는 올바르게 전달되지 않지만 인수로 전달하기 전에 직렬화 할 수 있습니다.

또한 오류가 발생하는 위치를 변경했으며 오류를 콘솔 로그로 전환하여 다음과 같이들을 수 있습니다.

    webView.setWebChromeClient(new CustomWebChromeClient());

그리고 클라이언트

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;
    }
}

감사. 이 메소드는 변수 내에서 '문자를 이스케이프합니까? 즉, 다음과 함께 작동 callJavascript(mBrowser, "can't do it");합니까?
Kostanos

1
방금 답변을 편집하고 'character
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')");
            }
        });
    }
}

자산 파일

<!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>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.