Android के WebView में जावास्क्रिप्ट से रिटर्न वैल्यू कैसे प्राप्त करें?


83

मैं एंड्रॉइड में जावास्क्रिप्ट से रिटर्न वैल्यू प्राप्त करना चाहता हूं। मैं इसे iPhone के साथ कर सकता हूं, लेकिन मैं Android के साथ नहीं कर सकता। मैंने लोड-यूआरएल का उपयोग किया, लेकिन यह एक वस्तु के बजाय शून्य वापस आ गया। कोई भी मेरी मदद कर सकता हैं?

जवाबों:


79

उतना ही Keithलेकिन छोटा जवाब

webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");

और फ़ंक्शन को लागू करें

@JavascriptInterface
public void onData(String value) {
   //.. do something with the data
}

सूची onDataसे हटाने के लिए मत भूलना proguard(यदि आपने समर्थ को सक्षम किया है)


1
क्या आप विस्तार से बता सकते हैं proguard?
— यूजीन

@ यूजीन अगर आपको नहीं पता कि यह क्या है तो आप शायद इसका इस्तेमाल न करें। वैसे भी इसके कुछ सक्षम करने के लिए जो रिवर्स इंजीनियरिंग को आपके ऐप को कठिन बनाता है
— किरिल कुलकोव

1
धन्यवाद। मुझे पता है कि मेरे पास प्रोजेक्ट रूट में proguard-project.txt है लेकिन इससे अधिक नहीं है। मैं पूछ रहा हूं क्योंकि आपका समाधान काम करता है लेकिन मुझे SIGSEGV मिलता है। मैं document.getElementById("my-div").scrollTopस्क्रॉल स्थिति प्राप्त करने के लिए मूल्यांकन कर रहा हूं SwipeRefreshLayout::canChildScrollUp()। मुझे लगता है कि यह छोटी अवधि में कई बार कॉल के कारण हो सकता है। या proguardजिस पर मुझे संदेह है क्योंकि मुझे नहीं पता कि यह क्या है ..
— यूगीन

यहाँ सभी टिप्पणियों के बजाय स्वीकृत जवाब होना चाहिए
— रोमित कुमार

64

यहां बताया गया है कि आप इसे कैसे पूरा कर सकते हैं:

इस ग्राहक को अपने WebView में जोड़ें:

final class MyWebChromeClient extends WebChromeClient {
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            Log.d("LogTag", message);
            result.confirm();
            return true;
        }
    }

अब आपकी जावास्क्रिप्ट कॉल में करें:

webView.loadUrl("javascript:alert(functionThatReturnsSomething)");

अब onJsAlert कॉल में "मैसेज" में लौटाया गया मान होगा।


17
यह एक अत्यंत मूल्यवान हैक है; विशेष रूप से तब जब आप एक ऐप बना रहे हों जहाँ आपके पास जावास्क्रिप्ट पर नियंत्रण नहीं है और मौजूदा कार्यों के साथ करना है। ध्यान दें कि आप का उपयोग कर जे एस अलर्ट में अवरोध डालने के बिना एक ही परिणाम प्राप्त कर सकते हैं public boolean onConsoleMessage(ConsoleMessage consoleMessage)के बजाय onJsAlertऔर फिर javascript कॉल आप कर में webView.loadUrl("javascript:console.log(functionThatReturnsSomething)");- इस तरह से तुम अकेले जे एस अलर्ट छोड़ दें।
— मिक बायरन

के साथ समाधान WebChromeClient.onConsoleMessageक्लीनर लग रहा है, लेकिन ध्यान रखें कि यह एचटीसी के कुछ उपकरणों के साथ काम नहीं करता है। अधिक जानकारी के लिए यह प्रश्न देखें ।
— पियोट्र

3
AddJavascriptInterface का उपयोग करने का कोई कारण बेहतर नहीं होगा?
— कीथ

@ कीथ: आपको एक ऑब्जेक्ट की आवश्यकता होगी जिसमें जावास्क्रिप्ट इसे लिखते हैं, लेकिन जैसा कि आप इस प्रश्न में मौजूदा जावास्क्रिप्ट को नहीं छू सकते हैं और मौजूदा जेएस ऐसे ऑब्जेक्ट में नहीं लिखते हैं, जेएस इंटरफ़ेस विधि यहां मदद नहीं करती है ( मैं इसे कैसे समझ पाया)।
— रे

1
@RayKoopa जरूरी नहीं कि सच हो। यद्यपि आप मौजूदा जावास्क्रिप्ट को लक्ष्य वेबपेज के भीतर संपादित करने में सक्षम नहीं हो सकते हैं, फिर भी आप mWebView.addJavascriptInterface(YourObject mYourObject,String yourNameForObject);फ़ंक्शन को कॉल करके पास की गई वस्तु पर विधियों को लागू कर सकते हैंmWebView.loadUrl("javascript:yourNameForObject.yourSetterMethod(valueToSet)")
— क्रिस - जूनियर

21

addJavascriptInterface()जावास्क्रिप्ट वातावरण में जावा ऑब्जेक्ट जोड़ने के लिए उपयोग करें । अपने जावास्क्रिप्ट को उस जावा ऑब्जेक्ट पर एक विधि कहें, जो उसके "रिटर्न वैल्यू" की आपूर्ति करे।


मैं कैसे की तरह कर सकते हैं स्थिति में है कि stackoverflow.com/questions/5521191/...
— vnshetty

यह मदद नहीं करता है यदि आपका js इस ऑब्जेक्ट में नहीं लिखता है और आप js को नहीं छू सकते हैं।
— रे

7
@PMMani: उपयोग करें loadUrl("javascript:...")evaluateJavascript() वर्तमान में लोड किए गए वेब पेज के संदर्भ में अपने स्वयं के जावास्क्रिप्ट का मूल्यांकन करने के लिए (एपीआई स्तर 1-18) या (एपीआई स्तर 19+) का उपयोग करें।
— कॉमन्सवेयर

@CommonsWare: धन्यवाद, मुझे वह मिल गया;) हालांकि, प्रबंधक ने फैसला किया कि js को "अपमानजनक जावास्क्रिप्ट अलर्ट" (आईरोल) पर संशोधित किया जा सकता है, इसलिए मैंने इसे इंटरफ़ेस विधि के साथ जाना।
— रे

12

यहाँ मैं आज के साथ आया हूँ। यह थ्रेड-सुरक्षित, यथोचित रूप से कुशल है, और एंड्रॉइड वेब व्यू के लिए जावा से सिंक्रोनस जावास्क्रिप्ट निष्पादन के लिए अनुमति देता है ।

Android 2.2 और बाद में काम करता है। (कॉमन्स-लैंग की आवश्यकता होती है क्योंकि मुझे अपने कोड स्निपेट को ईवैलस करने के लिए पास करना पड़ता है) () एक जावास्क्रिप्ट स्ट्रिंग के रूप में। आप इस निर्भरता को कोड के उद्धरण चिह्नों में नहीं बल्कि लपेटकर निकाल सकते हैं।function(){} )

सबसे पहले, इसे अपनी जावास्क्रिप्ट फ़ाइल में जोड़ें:

function evalJsForAndroid(evalJs_index, jsString) {
    var evalJs_result = "";
    try {
        evalJs_result = ""+eval(jsString);
    } catch (e) {
        console.log(e);
    }
    androidInterface.processReturnValue(evalJs_index, evalJs_result);
}

फिर, इसे अपनी Android गतिविधि में जोड़ें:

private Handler handler = new Handler();
private final AtomicInteger evalJsIndex = new AtomicInteger(0);
private final Map<Integer, String> jsReturnValues = new HashMap<Integer, String>();
private final Object jsReturnValueLock = new Object();
private WebView webView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    webView = (WebView) findViewById(R.id.webView);
    webView.addJavascriptInterface(new MyJavascriptInterface(this), "androidInterface");
}

public String evalJs(final String js) {
    final int index = evalJsIndex.incrementAndGet();
    handler.post(new Runnable() {
        public void run() {
            webView.loadUrl("javascript:evalJsForAndroid(" + index + ", " +
                                    "\"" + StringEscapeUtils.escapeEcmaScript(js) + "\")");
        }
    });
    return waitForJsReturnValue(index, 10000);
}

private String waitForJsReturnValue(int index, int waitMs) {
    long start = System.currentTimeMillis();

    while (true) {
        long elapsed = System.currentTimeMillis() - start;
        if (elapsed > waitMs)
            break;
        synchronized (jsReturnValueLock) {
            String value = jsReturnValues.remove(index);
            if (value != null)
                return value;

            long toWait = waitMs - (System.currentTimeMillis() - start);
            if (toWait > 0)
                try {
                    jsReturnValueLock.wait(toWait);
                } catch (InterruptedException e) {
                    break;
                }
            else
                break;
        }
    }
    Log.e("MyActivity", "Giving up; waited " + (waitMs/1000) + "sec for return value " + index);
    return "";
}

private void processJsReturnValue(int index, String value) {
    synchronized (jsReturnValueLock) {
        jsReturnValues.put(index, value);
        jsReturnValueLock.notifyAll();
    }
}

private static class MyJavascriptInterface {
    private MyActivity activity;

    public MyJavascriptInterface(MyActivity activity) {
        this.activity = activity;
    }

    // this annotation is required in Jelly Bean and later:
    @JavascriptInterface
    public void processReturnValue(int index, String value) {
        activity.processJsReturnValue(index, value);
    }
}

2
उपरोक्त कोड के लिए धन्यवाद - मैंने इसे अपने एंड्रॉइड प्रोजेक्ट में अपनाया। हालांकि, इसमें एक जाल है, जिसके परिणामस्वरूप जावा एपीआई डिजाइन खराब है। पंक्ति: jsReturnValueLock.wait (WaitMs - (System.currentTimeMillis () - start)); प्रतीक्षा का मान () फ़ंक्शन तर्क कभी-कभी मूल्यांकन करने के लिए हो सकता है 0. और इसका अर्थ है "असीम रूप से प्रतीक्षा करें" - मुझे एक सामयिक "कोई प्रतिक्रिया नहीं" त्रुटियां मिल रही थीं। मैंने इसके लिए परीक्षण करके इसे हल किया: यदि (बीता हुआ = = प्रतीक्षा) विराम; और नीचे फिर से System.currentTimeMillis () कॉल नहीं कर रहा है, लेकिन बीत चुके मूल्य का उपयोग कर रहा है। उपरोक्त कोड को संपादित करना और उसे ठीक करना सबसे अच्छा होगा।
— ग्रैग्को

वाह बहुत बहुत धन्यवाद! मैं उस लटक को भी देख रहा था और यह कभी पता नहीं लगा पाया कि यह कहां से आ रही है।
— कीथ

1
लेकिन अगर मैं evalJS को button.click श्रोता, आदि में चलाता हूं। WaitForJsReturnValue के कारण evalJs () लटक सकते हैं। इसलिए handView.post () के अंदर webView.loadUrl () बटन को निष्पादित करने का मौका नहीं हो सकता है क्योंकि बटन क्लिक करें।
— विजोरोवो

लेकिन उद्धरण चिह्नों में नहीं बल्कि कोड को कैसे लपेटें function(){}? JsString को कैसे रखें {}?
— विजोरोवो

7

API 19+ पर, ऐसा करने का सबसे अच्छा तरीका है मूल्यांकन को अपने WebView पर जावास्क्रिप्ट कहें :

webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
    @Override public void onReceiveValue(String value) {
        // value is the result returned by the Javascript as JSON
    }
});

अधिक विस्तार के साथ संबंधित जवाब: https://stackoverflow.com/a/20377857


5

@Felix Khazin ने जो समाधान सुझाया वह काम करता है, लेकिन एक प्रमुख बिंदु गायब है।

जावास्क्रिप्ट WebViewलोड वेब पेज लोड होने के बाद किया जाना चाहिए । के साथ, यह WebViewClientकरने के लिए जोड़ेंWebViewWebChromeClient ।

पूर्ण उदाहरण:

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    WebView webView = (WebView) findViewById(R.id.web_view);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.setWebViewClient(new MyWebViewClient());
    webView.setWebChromeClient(new MyWebChromeClient());
    webView.loadUrl("http://example.com");
}

private class MyWebViewClient extends WebViewClient {
    @Override
    public void onPageFinished (WebView view, String url){
        view.loadUrl("javascript:alert(functionThatReturnsSomething())");
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }
}

private class MyWebChromeClient extends WebChromeClient {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    Log.d("LogTag", message);
        result.confirm();
        return true;
    }
}

1

एक वैकल्पिक संस्करण के रूप में जो एक कस्टम योजना का उपयोग करता है:

मुख्य गतिविधि

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            WebView.setWebContentsDebuggingEnabled(true);
        }

        final WebView webview = new CustomWebView(this);

        setContentView(webview);

        webview.loadUrl("file:///android_asset/customPage.html");

        webview.postDelayed(new Runnable() {
            @Override
            public void run() {

                //Android -> JS
                webview.loadUrl("javascript:showToast()");
            }
        }, 1000);
    }
}

CustomWebView

public class CustomWebView extends WebView {
    public CustomWebView(Context context) {
        super(context);

        setup();
    }

    @SuppressLint("SetJavaScriptEnabled")
    private void setup() {
        setWebViewClient(new AdWebViewClient());

        getSettings().setJavaScriptEnabled(true);

    }

    private class AdWebViewClient extends WebViewClient {

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {

            if (url.startsWith("customschema://")) {
                //parse uri
                Toast.makeText(CustomWebView.this.getContext(), "event was received", Toast.LENGTH_SHORT).show();

                return true;
            }


            return false;
        }

    }
}

customPage.html (संपत्ति में स्थित तह)

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript View</title>

    <script type="text/javascript">

        <!--JS -> Android-->
        function showToast() {
            window.location = "customschema://goto/";
        }

    </script>
</head>

<body>

</body>
</html>

0

आप इसे इस तरह से कर सकते हैं:

[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
    public WebView web_view;
    public static TextView textView;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        Xamarin.Essentials.Platform.Init(this, savedInstanceState);

        Window.AddFlags(WindowManagerFlags.Fullscreen);
        Window.ClearFlags(WindowManagerFlags.ForceNotFullscreen);

        // Set our view from the "main" layout resource
        SetContentView (Resource.Layout.main);

        web_view = FindViewById<WebView>(Resource.Id.webView);
        textView = FindViewById<TextView>(Resource.Id.textView);

        web_view.Settings.JavaScriptEnabled = true;
        web_view.SetWebViewClient(new SMOSWebViewClient());
        web_view.LoadUrl("https://stns.egyptair.com");
    }

    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
    {
        Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

        base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

public class SMOSWebViewClient : WebViewClient
{
    public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
    {
        view.LoadUrl(request.Url.ToString());
        return false;
    }

    public override void OnPageFinished(WebView view, string url)
    {
        view.EvaluateJavascript("document.getElementsByClassName('notf')[0].innerHTML;", new JavascriptResult());
    }
}

public class JavascriptResult : Java.Lang.Object, IValueCallback
{
    public string Result;

    public void OnReceiveValue(Java.Lang.Object result)
    {
        string json = ((Java.Lang.String)result).ToString();
        Result = json;
        MainActivity.textView.Text = Result.Replace("\"", string.Empty);
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.