From 171b0976ec72867f028d99cb0571c6448fdfe80d Mon Sep 17 00:00:00 2001 From: Mathieu Date: Sun, 17 May 2026 12:38:35 +0200 Subject: [PATCH] fix: WebView iOS gestion deep links et interception URL schemes externes --- app/ios/Movix/Info.plist | 4 ++++ app/src/components/WebViewBrowser.tsx | 31 ++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/app/ios/Movix/Info.plist b/app/ios/Movix/Info.plist index f89cacc..b808500 100644 --- a/app/ios/Movix/Info.plist +++ b/app/ios/Movix/Info.plist @@ -57,5 +57,9 @@ audio + LSApplicationQueriesSchemes + + tg + diff --git a/app/src/components/WebViewBrowser.tsx b/app/src/components/WebViewBrowser.tsx index 7ac4d44..2355641 100644 --- a/app/src/components/WebViewBrowser.tsx +++ b/app/src/components/WebViewBrowser.tsx @@ -4,11 +4,12 @@ import React, { useImperativeHandle, useRef, } from 'react'; -import { Platform } from 'react-native'; +import { Linking, Platform } from 'react-native'; import { WebView, type WebViewNavigation } from 'react-native-webview'; import type { WebViewErrorEvent, WebViewMessageEvent, + ShouldStartLoadRequest, } from 'react-native-webview/lib/WebViewTypes'; import { handleBridgeMessage } from '../services/bridge'; import { buildInjectedJavaScript } from '../injection/inject'; @@ -26,12 +27,13 @@ interface WebViewBrowserProps { url: string; onNavigationStateChange?: (state: WebViewNavigation) => void; onError?: (error: string) => void; + onLoadEnd?: () => void; } const injectedJS = buildInjectedJavaScript(); const WebViewBrowser = forwardRef( - ({ url, onNavigationStateChange, onError }, ref) => { + ({ url, onNavigationStateChange, onError, onLoadEnd }, ref) => { const webViewRef = useRef(null); useImperativeHandle(ref, () => ({ @@ -61,6 +63,27 @@ const WebViewBrowser = forwardRef( [onError], ); + const onShouldStartLoadWithRequest = useCallback( + (request: ShouldStartLoadRequest) => { + const { url, navigationType } = request; + if ( + url.startsWith('https://') || + url.startsWith('http://') || + url.startsWith('about:') || + url.startsWith('blob:') + ) { + return true; + } + // Ouvre uniquement les deep links déclenchés par un vrai clic utilisateur. + // Les redirections automatiques (pubs, iframes) sont silencieusement bloquées. + if (navigationType === 'click') { + Linking.openURL(url).catch(() => {}); + } + return false; + }, + [], + ); + const onWebViewError = useCallback( (event: WebViewErrorEvent) => { onError?.(event.nativeEvent.description); @@ -83,10 +106,12 @@ const WebViewBrowser = forwardRef( // Bridge messages onMessage={onMessage} // Navigation + onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} onNavigationStateChange={onNavigationStateChange} // Errors onError={onWebViewError} onHttpError={onHttpError} + onLoadEnd={onLoadEnd} // Config userAgent={userAgent} javaScriptEnabled={true} @@ -96,7 +121,7 @@ const WebViewBrowser = forwardRef( allowsFullscreenVideo={true} allowsBackForwardNavigationGestures={true} // Sécurité - originWhitelist={['https://*', 'http://*']} + originWhitelist={['https://*', 'http://*', 'about:*', 'blob:*']} mixedContentMode="compatibility" // Cache cacheEnabled={true}