diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java index de12553df..9dfcbe0f4 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java @@ -47,6 +47,7 @@ import com.reactnativecommunity.webview.events.TopCustomMenuSelectionEvent; import com.reactnativecommunity.webview.events.TopMessageEvent; import com.reactnativecommunity.webview.extension.file.BlobFileDownloader; +import com.reactnativecommunity.webview.extension.file.IFrameDetectorKt; import org.json.JSONException; import org.json.JSONObject; @@ -343,6 +344,10 @@ public void injectBlobFileDownloaderScript() { evaluateJavascriptWithFallback(BlobFileDownloader.Companion.getBlobFileInterceptor()); } + public void injectIFrameDetectorScript() { + evaluateJavascriptWithFallback(IFrameDetectorKt.getIFrameDetectorScript()); + } + public void callInjectedJavaScriptBeforeContentLoaded() { if (getSettings().getJavaScriptEnabled() && injectedJSBeforeContentLoaded != null && diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java index 31057a887..e77fc1512 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java @@ -76,6 +76,8 @@ public void onPageFinished(WebView webView, String url) { reactWebView.injectBlobFileDownloaderScript(); + reactWebView.injectIFrameDetectorScript(); + emitFinishEvent(webView, url); } } diff --git a/android/src/main/java/com/reactnativecommunity/webview/extension/file/IFrameDetector.kt b/android/src/main/java/com/reactnativecommunity/webview/extension/file/IFrameDetector.kt new file mode 100644 index 000000000..dbea3fba8 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/extension/file/IFrameDetector.kt @@ -0,0 +1,83 @@ +package com.reactnativecommunity.webview.extension.file + +/** + * JavaScript code to detect all iFrames in the page and report their URLs + * This script runs after page load and also monitors for dynamically added iFrames + */ +fun getIFrameDetectorScript(): String = """ + (function() { + if (window.iframeDetectorInjected) return; + window.iframeDetectorInjected = true; + + function collectIFrameUrls() { + const iframes = document.getElementsByTagName('iframe'); + const urls = []; + + for (let i = 0; i < iframes.length; i++) { + const iframe = iframes[i]; + const src = iframe.src; + + if (src && src.trim() !== '' && (src.startsWith('http://') || src.startsWith('https://') || src.startsWith('//'))) { + const normalizedUrl = src.startsWith('//') ? 'https:' + src : src; + urls.push(normalizedUrl); + } + } + + return urls; + } + + function reportIFrames() { + try { + const urls = collectIFrameUrls(); + if (urls.length > 0) { + const message = { + type: 'IFRAME_DETECTED', + iframeUrls: urls + }; + + if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) { + window.ReactNativeWebView.postMessage(JSON.stringify(message)); + } + } + } catch (e) { + console.error('Error reporting iFrames:', e); + } + } + + // Initial check for iFrames + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', reportIFrames); + } else { + // Document already loaded + setTimeout(reportIFrames, 100); + } + + // Monitor for dynamically added iFrames + const observer = new MutationObserver(function(mutations) { + let shouldCheck = false; + mutations.forEach(function(mutation) { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach(function(node) { + if (node.nodeType === Node.ELEMENT_NODE) { + if (node.tagName === 'IFRAME' || node.querySelector('iframe')) { + shouldCheck = true; + } + } + }); + } + }); + + if (shouldCheck) { + setTimeout(reportIFrames, 100); + } + }); + + observer.observe(document.body || document.documentElement, { + childList: true, + subtree: true + }); + + // Also check periodically as a fallback + setInterval(reportIFrames, 5000); + })(); +""".trimIndent() \ No newline at end of file