Определите, является ли WebView невидимым, используя только JS

У меня есть тестовое приложение для Android с веб-интерфейсом:

<WebView
        android:alpha="0"
        android:id="@+id/myWebView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

Моя основная активность загружает страницу, на которой работает JS-контент. JS разрешен с использованием:

webSettings.setJavaScriptEnabled(true);

В моем приложении есть кнопка, которая переключает значение альфа от 0 до 1 (show/hide webView).

Есть ли "творческий" способ обнаружения изменений на стороне JS?

Вещи, которые я пробовал:

Обновить:

Уточнение, я ищу решение JS Only, фактический JS-код - это SDK, используемый внутри среды WebView.

Я не контролирую приложение Android, полный контроль над содержимым WebView.

Ответы

Ответ 1

Вы можете подклассифицировать android WebView, переопределить его метод setAlpha и добавить некоторую логику, чтобы веб-страница знала текущее значение альфа.

Вот упрощенный пример:

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.webkit.WebView;

public class MyWebView extends WebView {

    public MyWebView(Context context) {
        super(context);
        init();
    }

    public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public MyWebView(Context context,
                     AttributeSet attrs,
                     int defStyleAttr,
                     int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    @SuppressLint("SetJavaScriptEnabled")
    private void init() {
        getSettings().setJavaScriptEnabled(true);
    }

    @Override
    public void setAlpha(float alpha) {
        super.setAlpha(alpha);
        propagateAlphaToWebPage(alpha);
    }

    private void propagateAlphaToWebPage(float alpha) {
        // setWebViewAlpha is a JS function that should be defined in your html js 
    String jssnippet = "setWebViewAlpha("+alpha+");";
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        evaluateJavascript(jssnippet, null);
    } else {
        loadUrl("javascript:"+jssnippet);
    }
}
}

Другие связанные вопросы, которые могут оказаться полезными:

Ответ 2

Ниже приведен полный код, который будет WebView в JavaScript если WebView будет виден или нет.

Шаги:

  1. Создайте макет, содержащий ToggleButton и WebView.
  2. Загрузите html с помощью htmlWebView.loadUrl("file:///android_asset/index.html"); и связанный код
  3. Создайте функцию onToggleButtonPressed() которая будет вызываться onClick toggle button
  4. В onToggleButtonPressed() отображает/скрывает WebView и в то же время передает статус JavaScript с помощью htmlWebView.evaluateJavascript(). Pass visibilityStatusFromAndroid() для JavaScript
  5. Получить статус в JavaScript из функции visibilityStatusFromAndroid()

Android-макет XML-кода:

<ToggleButton
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:background="@color/red"
    android:onClick="onToggleButtonPressed"
    android:text="Button1"
    android:textOn="Show"
    android:textOff="Hide"
    tools:ignore="MissingConstraints"
    tools:layout_editor_absoluteX="148dp"
    tools:layout_editor_absoluteY="0dp" />

<WebView
    android:id="@+id/webView"
    android:layout_width="368dp"
    android:layout_height="447dp"
    android:layout_alignParentStart="true"
    android:layout_below="@+id/button"
    tools:ignore="MissingConstraints"
    tools:layout_editor_absoluteX="8dp"
    tools:layout_editor_absoluteY="56dp"
    android:layout_alignParentLeft="true" />

Код Java:

    WebView htmlWebView; // put it outside onCreate() to make it accessible in onToggleButtonPressed() 

    htmlWebView = (WebView)findViewById(R.id.webView);
    htmlWebView.setWebViewClient(new WebViewClient());
    htmlWebView.loadUrl("file:///android_asset/index.html");
    WebSettings webSetting = htmlWebView.getSettings();
    webSetting.setJavaScriptEnabled(true);

public void onToggleButtonPressed(View view) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

        boolean on = ((ToggleButton) view).isChecked();
        String visibility;
        if (on) {
            htmlWebView.setVisibility(View.GONE);
            visibility = "NOT VISIBLE";
                htmlWebView.evaluateJavascript("javascript: " +
                        "visibilityStatusFromAndroid(\"" + visibility + "\")", null);
        } else {
            htmlWebView.setVisibility(View.VISIBLE);
            visibility = "VISIBLE NOW";
            htmlWebView.evaluateJavascript("javascript: " +
                    "visibilityStatusFromAndroid(\"" + visibility + "\")", null);

        }
    }
}

Файл JavaScript:

function visibilityStatusFromAndroid(message) {
  if (message === "NOT VISIBLE") {
    console.log("webview is not visible");
    // do your stuff here

  } else if (message === "VISIBLE NOW") {
    console.log("webview is visible now");
    // do your stuff here

  }
}

Это. Вы сделали!

Вот видео рабочего кода.

Обновить:

Существует один вариант, который можно использовать для обнаружения видимости только с использованием JavaScript - document.hasFocus(), но это не будет работать, если на экране есть какой-либо EditText, и пользователь сосредоточит этот EditText.

На всякий случай ниже приведен код, который вы можете использовать для document.hasFocus():

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>TEST</title>
<style>
#message { font-weight: bold; }
</style>
<script>
setInterval( checkPageFocus, 200 ); // you can change interval time to check more frequently

function checkPageFocus() {
  var info = document.getElementById("message");

  if ( document.hasFocus() ) {
    info.innerHTML = "The document is VISIBLE.";
  } else {
    info.innerHTML = "The document is INVISIBLE.";
  }
}

</script>
</head>
<body>
  <h1>JavaScript hasFocus example</h1>
  <div id="message">Waiting for user action</div>
</body>
</html>

Ответ 3

В настоящее время нет JS-единственного решения.

Содержимое WebView не должно получать информацию об окружающей среде.
Единственным исключением является информация, которая была вызвана самой средой.

Это будет противоречить базовой песочнице и может привести к проблемам безопасности.

Поскольку нет стандартного API, который предоставит вам необходимую информацию, вам придется самостоятельно изменить среду, чтобы открыть ее в WebView.

Если вы не можете изменить среду, то, что вы запрашиваете, (теоретически) невозможно с текущими браузерами /Android.


@Hack Чтобы найти реальную лазейку, которую мы можем использовать для получения альфа-значения, нам понадобится более подробная информация о JS SDK, об окружающей среде и о том, какое влияние на сторону Android и веб-просмотра приложения у вас есть.
И даже тогда, потратив много усилий, результат, скорее всего, будет таким же.