WebView中检测视频播放状态的最优方案探讨(无需JavaScriptInterface)
Great question—tracking video state via onProcessChanged with flags is definitely a clunky approach, and there are far more reliable, efficient ways to do this without relying on JavaScriptInterface. Let’s break down the best options based on your use case:
1. Fullscreen Video Detection (Native, No JS Required)
If you only care about videos that enter fullscreen mode (the most common scenario for mobile), Android’s WebChromeClient gives you built-in callbacks that are perfectly suited for this. These callbacks fire directly when the WebView switches to/from a fullscreen video container, no JS interaction needed.
Here’s how to implement it:
webView.setWebChromeClient(new WebChromeClient() { private boolean isFullscreenVideoPlaying = false; @Override public void onShowCustomView(View view, CustomViewCallback callback) { super.onShowCustomView(view, callback); // Triggered when video enters fullscreen isFullscreenVideoPlaying = true; // Optional: Hide your WebView and display the fullscreen video view here } @Override public void onHideCustomView() { super.onHideCustomView(); // Triggered when video exits fullscreen isFullscreenVideoPlaying = false; // Optional: Restore your WebView's visibility } });
This method is super reliable because it’s tied directly to the system’s video rendering logic. The only catch: it won’t detect videos playing inline (in the page’s normal layout, not fullscreen).
2. Inline Video State Detection (No JavaScriptInterface)
For inline HTML5 videos, you can use WebView.evaluateJavascript() to query or listen for playback state changes without registering a JavaScriptInterface. This is a safe, lightweight way to interact with the page’s DOM without opening up a bridge for the page to call native code.
Option A: One-Time State Query
If you just need to check the video’s state at specific moments (e.g., after the page loads, when the user taps a button), run this JS snippet:
webView.evaluateJavascript( // Check if any video exists and if it's paused "document.querySelector('video') ? !document.querySelector('video').paused : false;", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { // Parse the result (returns "true" or "false" as a string) boolean isVideoPlaying = Boolean.parseBoolean(value); // Update your app's state based on this value } } );
Option B: Real-Time State Updates
If you need to track changes as they happen, inject a simple JS event listener into the page (still no JavaScriptInterface needed). The listener will update a global variable, which your native code can periodically query:
// Inject the event listener once after the page loads webView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); webView.evaluateJavascript( "const video = document.querySelector('video'); " + "if (video) { " + " window.videoPlaybackState = video.paused ? 'paused' : 'playing'; " + " video.addEventListener('play', () => window.videoPlaybackState = 'playing'); " + " video.addEventListener('pause', () => window.videoPlaybackState = 'paused'); " + "}", null ); } }); // Periodically query the state (e.g., using a Handler) new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { @Override public void run() { webView.evaluateJavascript( "window.videoPlaybackState || 'no_video'", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { String state = value.replace("\"", ""); // Clean up the string result switch(state) { case "playing": // Handle playing state break; case "paused": // Handle paused state break; case "no_video": // No video found on the page break; } } } ); // Repeat the query every 500ms (adjust interval as needed) new Handler(Looper.getMainLooper()).postDelayed(this, 500); } }, 500);
This approach gives you near-real-time updates without exposing your app to the security risks of JavaScriptInterface.
Final Recommendation
- Use the
WebChromeClientfullscreen callbacks if you only need to track fullscreen videos (this is the most efficient, native solution). - Use the
evaluateJavascriptapproach if you need to monitor inline videos. It’s flexible and avoids the overhead/security concerns ofJavaScriptInterface.
内容的提问来源于stack exchange,提问作者mel

