From 4b920aa8b4cf7c4dac601b06f0d7866700925287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Mart=C3=ADnez?= Date: Fri, 13 Feb 2026 09:10:10 +0100 Subject: [PATCH 1/2] chore: polyfill web share API on Android WebView --- plugin/src/wayfinding/components/MapView.tsx | 83 ++++++++++++++++++-- 1 file changed, 78 insertions(+), 5 deletions(-) diff --git a/plugin/src/wayfinding/components/MapView.tsx b/plugin/src/wayfinding/components/MapView.tsx index ce8c907..e88db47 100644 --- a/plugin/src/wayfinding/components/MapView.tsx +++ b/plugin/src/wayfinding/components/MapView.tsx @@ -11,6 +11,7 @@ import React, { import { Linking, Platform, + Share, type StyleProp, StyleSheet, type ViewStyle, @@ -31,23 +32,23 @@ import { } from "../store"; import { useSelector } from "../store/utils"; import { - type OnInternalMapViewMessageCallback, type CartographySelectionOptions, + type InternalMapViewRef, type MapViewDirectionsOptions, type MapViewError, type MapViewRef, type NavigateToCarPayload, type NavigateToPointPayload, type NavigateToPoiPayload, - type ShareLiveLocationSessionPayload, type OnDirectionsRequestInterceptor, type OnExternalLinkClickedResult, type OnFavoritePoisUpdatedResult, type OnFloorChangedResult, + type OnInternalMapViewMessageCallback, type OnPoiDeselectedResult, type OnPoiSelectedResult, type SearchFilter, - type InternalMapViewRef, + type ShareLiveLocationSessionPayload, } from "../types"; import { ErrorName } from "../types/constants"; import { sendMessageToViewer } from "../utils"; @@ -107,6 +108,13 @@ export type MapViewConfiguration = { language?: string; }; +// ref https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share +interface WebShareAPIParam { + url?: string; + text?: string; + title?: string; +} + const viewerStyles = StyleSheet.create({ webview: { minHeight: "100%", @@ -616,6 +624,10 @@ const MapView = React.forwardRef( case "ui.speak_aloud_text": SitumPlugin.speakAloudText(payload); break; + case "native.share": + if (Platform.OS !== "android") return; + _onWebShareMessage(payload); + break; default: break; } @@ -625,11 +637,32 @@ const MapView = React.forwardRef( // intermediation of this plugin. try { internalMessageCallbackRef.current?.(type, payload); - } catch (error) { - console.error("Error delegating:", type, error); + } catch (e) { + console.error("Error delegating:", type, e); } }; + const _onWebShareMessage = useCallback(async (param: WebShareAPIParam) => { + try { + if (param.url == null && param.text == null) { + return; + } + await Share.share( + { + title: param.title, + message: [param.text, param.url].filter(Boolean).join(" "), + url: param.url, + }, + { + dialogTitle: param.title, + subject: param.title, + }, + ); + } catch (e) { + console.error(e); + } + }, []); + const _onShouldStartLoadWithRequest = (request: any) => { if ( request && @@ -724,6 +757,45 @@ const MapView = React.forwardRef( ); }; + // As the share API is not available in the webview, we need to override it to use the native share API. + // See https://github.com/react-native-webview/react-native-webview/issues/1262#issuecomment-933315821 + const _androidShareInjection = useMemo(() => { + // Path share behavior only on Android + if (Platform.OS !== "android") return undefined; + + return ` + if (navigator.canShare == null) { + navigator.canShare = (param) => { + if (param == null || typeof param !== "object") { + return false; + } + if (Array.isArray(param.files) && param.files.length > 0) { + return false; + } + return param.url != null || param.text != null || param.title != null; + }; + } + if (navigator.share == null) { + navigator.share = (param) => { + return new Promise((resolve, reject) => { + try { + window.ReactNativeWebView.postMessage( + JSON.stringify({ + type: "native.share", + payload: param, + }) + ); + resolve(); + } catch (error) { + reject(error); + } + }); + }; + } + true; + `; + }, []); + return ( ( limitsNavigationsToAppBoundDomains={true} javaScriptEnabled={true} domStorageEnabled={true} + injectedJavaScriptBeforeContentLoaded={_androidShareInjection} startInLoadingState={true} cacheEnabled onMessage={handleRequestFromViewer} From b62bd28f6ef900cfa87ab47c81704139a66a53ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alba=20Mart=C3=ADnez?= Date: Fri, 13 Feb 2026 17:41:29 +0100 Subject: [PATCH 2/2] chore: simplify share options --- plugin/src/wayfinding/components/MapView.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugin/src/wayfinding/components/MapView.tsx b/plugin/src/wayfinding/components/MapView.tsx index e88db47..d5885a1 100644 --- a/plugin/src/wayfinding/components/MapView.tsx +++ b/plugin/src/wayfinding/components/MapView.tsx @@ -110,9 +110,8 @@ export type MapViewConfiguration = { // ref https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share interface WebShareAPIParam { - url?: string; - text?: string; title?: string; + url?: string; } const viewerStyles = StyleSheet.create({ @@ -644,18 +643,16 @@ const MapView = React.forwardRef( const _onWebShareMessage = useCallback(async (param: WebShareAPIParam) => { try { - if (param.url == null && param.text == null) { + if (param.url == null) { return; } await Share.share( { title: param.title, - message: [param.text, param.url].filter(Boolean).join(" "), - url: param.url, + message: param.url, }, { dialogTitle: param.title, - subject: param.title, }, ); } catch (e) { @@ -757,13 +754,14 @@ const MapView = React.forwardRef( ); }; - // As the share API is not available in the webview, we need to override it to use the native share API. + // Override the Web Share API as it is not supported on Android WebView // See https://github.com/react-native-webview/react-native-webview/issues/1262#issuecomment-933315821 const _androidShareInjection = useMemo(() => { // Path share behavior only on Android if (Platform.OS !== "android") return undefined; return ` + // Polyfill the check of being able to share for the webview if (navigator.canShare == null) { navigator.canShare = (param) => { if (param == null || typeof param !== "object") { @@ -772,11 +770,13 @@ const MapView = React.forwardRef( if (Array.isArray(param.files) && param.files.length > 0) { return false; } - return param.url != null || param.text != null || param.title != null; + return param.url != null || param.title != null; }; } + // Polyfill the share API for the webview if (navigator.share == null) { navigator.share = (param) => { + // Return a promise same as the native share API return new Promise((resolve, reject) => { try { window.ReactNativeWebView.postMessage(