0

I am attempting to pass a URL as input to a JavaScript script from an Android application and expect to receive a true or false value as a string in return from the script. The JavaScript code works fine when run independently, but when integrated with the Android app, I'm not receiving any data from the script. It's uncertain whether the JavaScript code is even executing properly within the Android environment.

public void linkValidation(String url) {
        textStatus.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.white));
        textStatus.setText(getString(R.string.validating_link));
//        Toast.makeText(MainActivity.this, url, Toast.LENGTH_SHORT).show();
        // Regex pattern for profile link
        Pattern profileLinkPattern = Pattern.compile("^https://www.threads.net/@[^/]+$");
        // Regex pattern for post link
//                Pattern postWithNoHttps = Pattern.compile("^(?!https:\\/\\/)(.*(?:www\\.)?threads\\.net).*");
//                Matcher postWithNoHTTPS_Matcher = postWithNoHttps.matcher(url);
        Matcher profileMatcher = profileLinkPattern.matcher(url);
        if (url.startsWith("https://www.threads.net") || url.startsWith("https://threads.net")) {
//            Toast.makeText(MainActivity.this, "Checked", Toast.LENGTH_SHORT).show();
            if (profileMatcher.matches()) {
                textStatus.setText(null);
                textStatus.setText(getString(R.string.profile_link));
            } else if (url.contains("/post/") || url.contains("threads.net/t/")) {
                textStatus.setText(null);

                // Call the method to run JavaScript in the WebView with the URL
                runJavaScriptInWebView(url, result -> {
                    // Here, 'result' will contain the value of 'foundNot' from JavaScript
                    textStatus.setText(result);

                    // Show the result as a Toast message
                    Toast.makeText(MainActivity.this, "Result: " + result, Toast.LENGTH_LONG).show();
                });
            } else {
                textStatus.setText(null);
                textStatus.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.orange));
                textStatus.setText(getString(R.string.threadlink_invaliddataurl));
            }
        } else if (((!url.startsWith("https://")) && (url.contains("www.threads.net"))) || ((!url.startsWith("https://") && (url.contains("https://threads.net"))))) {
            textStatus.setText(null);
            textStatus.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.orange));
            textStatus.setText(getString(R.string.threadLink_NoHttps));

        } else {
            Toast.makeText(MainActivity.this, "Invailed Url", Toast.LENGTH_SHORT).show();
            textStatus.setText(null);
            textStatus.setTextColor(ContextCompat.getColor(MainActivity.this, R.color.orange));
            textStatus.setText(getString(R.string.threadLink_False));
        }

    }
    private void runJavaScriptInWebView(String url, final JavaScriptCallback callback) {
        WebView webView = new WebView(getApplicationContext());
        webView.getSettings().setJavaScriptEnabled(true);

        // WebView JavaScript interface to receive the result
        class JavaScriptInterface {
            @JavascriptInterface
            public void processResult(String result) {
                // Call the callback with the result
                callback.onResult(result);
            }
        }

        // Set the JavaScript interface
        webView.addJavascriptInterface(new JavaScriptInterface(), "androidJSInterface");

        // Set a custom WebChromeClient to capture console logs
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
                // Log the console message to Logcat
                Log.d("JavaScriptConsole", consoleMessage.message());
                return true;
            }
        });

        // Load the HTML content with JavaScript code in the WebView
        String jsCode = "function evaluatePage(url) {" +
                "    let foundNot = null;" +
                "    try {" +
                "        const svgElements = document.querySelector('[aria-hidden=\"true\"][fill=\"none\"]');" +
                "        if (svgElements) {" +
                "            foundNot = 'true';" +
                "            console.log(foundNot);" +
                "        } else {" +
                "            foundNot = 'false';" +
                "            console.log(foundNot);" +
                "        }" +
                "        window.androidJSInterface.processResult(foundNot);" + // Pass the result to the JavaScript interface
                "    } catch (error) {" +
                "        console.error('Error:', error);" +
                "    }" +
                "}" +
                "evaluatePage('" + url + "');"; // Call the function immediately when the page loads

        String htmlContent = "<html><head><script>" + jsCode + "</script></head><body></body></html>";

        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                // The page is loaded, and evaluatePage() has been called
                // At this point, JavaScript execution is already done, and the result is available in foundNot
                // You can handle the result here or in the JavaScriptInterface's processResult method
            }
        });

        // Load the HTML content (start JavaScript execution)
        webView.loadData(htmlContent, "text/html", "UTF-8");
    }


    private interface JavaScriptCallback {
        void onResult(String result);
    }
Vasant Raval
  • 257
  • 1
  • 12
  • 31

2 Answers2

1

Looking at the purpose why you want to evaluate JavaScript code, I suggest to trying out the Javascript Engine androidx package.

Here is the documentation that shows you some examples how to use it: https://developer.android.com/develop/ui/views/layout/webapps/jsengine

It's not just a solution and simplification for your problem, but it is also better for performance since it won't create an entire WebView.

Jetpack library JavaScriptEngine provides a way for an application to evaluate JavaScript code without creating a WebView instance.

For applications requiring non-interactive JavaScript evaluation, using the JavaScript engine library has the following advantages:

  • Lower resource consumption, since there is no need to allocate a WebView instance.

  • Can be done in a Service (WorkManager task).

  • Multiple isolated environments with low overhead, enabling the application to run several JavaScript snippets simultaneously.

  • Ability to pass large amounts of data by using an API call.

0

The issue is probably caused by missing Android Permissions. Does your Android application have the necessary permissions to access the internet?

In your AndroidManifest.xml file, try including the following permission:

<uses-permission android:name="android.permission.INTERNET"/>

haris.doku
  • 36
  • 4