From 11b9abc84911921e89c23e2cddabb182fc68ab19 Mon Sep 17 00:00:00 2001 From: Ilya Pishchulin <45998835+ilyapishchulin@users.noreply.github.com> Date: Wed, 4 May 2022 13:12:26 +0300 Subject: [PATCH] Supported communication with ReactNative webview (#284) * Supported postMessage event from ReactNative webview * Update version to 2.5.2 --- package.json | 2 +- src/bridge.ts | 69 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index fd98062..f47a73c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vkontakte/vk-bridge", - "version": "2.5.5", + "version": "2.6.0", "description": "Connects a Mini App with VK client", "license": "MIT", "main": "dist/index.js", diff --git a/src/bridge.ts b/src/bridge.ts index 273d3f2..32c8942 100644 --- a/src/bridge.ts +++ b/src/bridge.ts @@ -15,6 +15,11 @@ export const IS_IOS_WEBVIEW = Boolean( (window as any).webkit.messageHandlers.VKWebAppClose ); +export const IS_REACT_NATIVE_WEBVIEW = Boolean( + (window as any).ReactNativeWebView && + typeof (window as any).ReactNativeWebView.postMessage === 'function' +); + /** Is the runtime environment a browser */ export const IS_WEB = IS_CLIENT_SIDE && !IS_ANDROID_WEBVIEW && !IS_IOS_WEBVIEW; @@ -132,6 +137,14 @@ export function createVKBridge(version: string): VKBridge { iosBridge[method].postMessage!(props); } + // Sending data through React Native bridge + else if (IS_REACT_NATIVE_WEBVIEW) { + (window as any).ReactNativeWebView.postMessage(JSON.stringify({ + handler: method, + params: props, + })); + } + // Sending data through web bridge else if (webBridge && typeof webBridge.postMessage === 'function') { webBridge.postMessage( @@ -231,25 +244,47 @@ export function createVKBridge(version: string): VKBridge { return !isEmbedded(); } + function handleEvent(event: any) { + if (IS_IOS_WEBVIEW || IS_ANDROID_WEBVIEW) { + // If it's webview + return [...subscribers].map((fn) => fn.call(null, event)); + } + + let bridgeEventData = event?.data; + if (!IS_WEB || !bridgeEventData) { + return; + } + + if (IS_REACT_NATIVE_WEBVIEW && typeof bridgeEventData === 'string') { + try { + bridgeEventData = JSON.parse(bridgeEventData); + } catch {} + } + + const { type, data, frameId } = bridgeEventData; + if (!type) { + return; + } + + if (type === 'SetSupportedHandlers') { + webSdkHandlers = data.supportedHandlers; + return; + } + + if (type === 'VKWebAppSettings') { + webFrameId = frameId; + return; + } + + [...subscribers].map((fn) => fn({ detail: { type, data } })); + } + // Subscribes to listening messages from a runtime for calling each // subscribed event listener. - if (typeof window !== 'undefined' && 'addEventListener' in window) { - window.addEventListener(EVENT_TYPE, (event: any) => { - if (IS_IOS_WEBVIEW || IS_ANDROID_WEBVIEW) { - // If it's webview - return [...subscribers].map((fn) => fn.call(null, event)); - } else if (IS_WEB && event && event.data) { - // If it's web - const { type, data, frameId } = event.data; - if (type && type === 'SetSupportedHandlers') { - webSdkHandlers = data.supportedHandlers; - } else if (type && type === 'VKWebAppSettings') { - webFrameId = frameId; - } else { - [...subscribers].map((fn) => fn({ detail: { type, data } })); - } - } - }); + if (IS_REACT_NATIVE_WEBVIEW && /(android)/i.test(navigator.userAgent)) { + document.addEventListener(EVENT_TYPE, handleEvent); + } else if (typeof window !== 'undefined' && 'addEventListener' in window) { + window.addEventListener(EVENT_TYPE, handleEvent); } /**