diff --git a/examples/mpx-webview/H5/webviewbridge.min.js b/examples/mpx-webview/H5/webviewbridge.min.js index b94c23c965..7ac85a8e78 100644 --- a/examples/mpx-webview/H5/webviewbridge.min.js +++ b/examples/mpx-webview/H5/webviewbridge.min.js @@ -1,6 +1,6 @@ /** - * mpxjs webview bridge v2.9.53 + * mpxjs webview bridge v2.9.58 * (c) 2024 @mpxjs team * @license Apache */ -var e,t;e=this,t=function(){"use strict";function e(e,t,o){return(t=function(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var o=e[Symbol.toPrimitive];if(void 0!==o){var n=o.call(e,t||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}(t))in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function t(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}var o,n,a,r,i=function(o){for(var n=1;n-1&&g.indexOf("MiniProgram")>-1?c="my":g.toLowerCase().indexOf("miniprogram")>-1?c=g.indexOf("QQ")>-1?"qq":"wx":g.indexOf("swan/")>-1?c="swan":g.indexOf("toutiao")>-1?c="tt":(c="web",window.addEventListener("message",(function(e){var t=e.data,o=t;try{"string"==typeof t&&(o=JSON.parse(t))}catch(e){}var n=o,a=n.callbackId,r=n.error,i=n.result;void 0!==a&&d[a]&&(r?d[a](r):d[a](null,i),delete d[a])}),!1));var u=!1;function w(e){u?e():o.then((function(){u=!0,e()}))}var l={config:function(e){"wx"===c?w((function(){window.wx&&window.wx.config(e)})):console.warn("\u975e\u5fae\u4fe1\u73af\u5883\u4e0d\u9700\u8981\u914d\u7f6econfig")}};function f(e){if("[object Object]"!==Object.prototype.toString.call(e))return e;var t={};for(var o in e)"function"!=typeof e[o]&&(t[o]=e[o]);return t}function m(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("getEnv"!==e){var o=++s;d[o]=function(e,n){e?(t.fail&&t.fail(e),t.complete&&t.complete(e)):(t.success&&t.success(n),t.complete&&t.complete(n)),delete d[o]};var n={type:e,callbackId:s,payload:f(t)};void 0!==p&&(n.clientUid=p),window.ReactNativeWebView?window.ReactNativeWebView.postMessage&&window.ReactNativeWebView.postMessage(JSON.stringify(n)):window.parent.postMessage&&window.parent.postMessage(n,"*")}else t({webapp:!0})}var v=function(){var e={wx:{keyName:"miniProgram",api:["navigateTo","navigateBack","switchTab","reLaunch","redirectTo","postMessage","getEnv"]},tt:{keyName:"miniProgram",api:["redirectTo","navigateTo","switchTab","reLaunch","navigateBack","setSwipeBackModeSync","postMessage","getEnv","checkJsApi","chooseImage","compressImage","previewImage","uploadFile","getNetworkType","openLocation","getLocation"]},swan:{keyName:"webView",api:["navigateTo","navigateBack","switchTab","reLaunch","redirectTo","getEnv","postMessage"]},qq:{keyName:"miniProgram",api:["navigateTo","navigateBack","switchTab","reLaunch","redirectTo","getEnv","postMessage"]}}[c]||{},t={wx:["checkJSApi","chooseImage","previewImage","uploadImage","downloadImage","getLocalImgData","startRecord","stopRecord","onVoiceRecordEnd","playVoice","pauseVoice","stopVoice","onVoicePlayEnd","uploadVoice","downloadVoice","translateVoice","getNetworkType","openLocation","getLocation","startSearchBeacons","stopSearchBeacons","onSearchBeacons","scanQRCode","chooseCard","addCard","openCard"],my:["navigateTo","navigateBack","switchTab","reLaunch","redirectTo","chooseImage","previewImage","getLocation","openLocation","alert","showLoading","hideLoading","getNetworkType","startShare","tradePay","postMessage","onMessage","getEnv"],swan:["makePhoneCall","setClipboardData","getNetworkType","openLocation","getLocation","chooseLocation","chooseImage","previewImage","openShare","navigateToSmartProgram"],web:["navigateTo","navigateBack","switchTab","reLaunch","redirectTo","getEnv","postMessage","getLoadError","getLocation"],tt:[]}[c]||[];(e.api||[]).forEach((function(t){l[t]=function(){for(var o=arguments.length,n=new Array(o),a=0;a1&&void 0!==arguments[1]?arguments[1]:{},o=t.time,n=void 0===o?5e3:o,a=t.crossOrigin,r=void 0!==a&&a;function i(){return new Promise((function(t,o){var n=document.createElement("script");n.type="text/javascript",n.async="async",r&&(n.crossOrigin="anonymous"),n.onload=n.onreadystatechange=function(){this.readyState&&!/^(loaded|complete)$/.test(this.readyState)||(t(),n.onload=n.onreadystatechange=null)},n.onerror=function(){o(new Error("load ".concat(e," error"))),n.onerror=null},n.src=e,document.getElementsByTagName("head")[0].appendChild(n)}))}function c(){return new Promise((function(t,o){setTimeout((function(){o(new Error("load ".concat(e," timeout")))}),n)}))}return Promise.race([i(),c()])}(i[c].url):Promise.reject(new Error("\u672a\u627e\u5230\u5bf9\u5e94\u7684sdk")):Promise.resolve(),v(),l},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).mpx=t(); \ No newline at end of file +var e,o;e=this,o=function(){"use strict";var e,o,a,t,n=Object.assign({wx:{url:"https://res.wx.qq.com/open/js/jweixin-1.3.2.js"},qq:{url:"https://qqq.gtimg.cn/miniprogram/webview_jssdk/qqjssdk-1.0.0.js"},my:{url:"https://appx/web-view.min.js"},swan:{url:"https://b.bdstatic.com/searchbox/icms/searchbox/js/swan-2.0.4.js"},tt:{url:"https://lf3-cdn-tos.bytegoofy.com/obj/goofy/developer/jssdk/jssdk-1.2.1.js"}},window.sdkUrlMap),i=null,r=0,c=(a=location.href,(t=/mpx_webview_id=(\d+)/g.exec(a))&&t[1]&&(o=+t[1]),o),s={},d=navigator.userAgent;d.indexOf("AlipayClient")>-1&&d.indexOf("MiniProgram")>-1?i="my":d.toLowerCase().indexOf("miniprogram")>-1?i=d.indexOf("QQ")>-1?"qq":"wx":d.indexOf("swan/")>-1?i="swan":d.indexOf("toutiao")>-1?i="tt":(i="web",window.addEventListener("message",(function(e){var o=e.data,a=o;try{"string"==typeof o&&(a=JSON.parse(o))}catch(e){}var t=a,n=t.callbackId,i=t.error,r=t.result;void 0!==n&&s[n]&&(i?s[n](i):s[n](null,r),delete s[n])}),!1));var g=!1;function w(o){g?o():e.then((function(){g=!0,o()}))}var p={config:function(e){"wx"===i?w((function(){window.wx&&window.wx.config(e)})):console.warn("\u975e\u5fae\u4fe1\u73af\u5883\u4e0d\u9700\u8981\u914d\u7f6econfig")}};function l(e){for(var o=arguments.length,a=new Array(o>1?o-1:0),t=1;t1&&void 0!==arguments[1]?arguments[1]:{},a=o.time,t=void 0===a?5e3:a,n=o.crossOrigin,i=void 0!==n&&n;function r(){return new Promise((function(o,a){var t=document.createElement("script");t.type="text/javascript",t.async="async",i&&(t.crossOrigin="anonymous"),t.onload=t.onreadystatechange=function(){this.readyState&&!/^(loaded|complete)$/.test(this.readyState)||(o(),t.onload=t.onreadystatechange=null)},t.onerror=function(){a(new Error("load ".concat(e," error"))),t.onerror=null},t.src=e,document.getElementsByTagName("head")[0].appendChild(t)}))}function c(){return new Promise((function(o,a){setTimeout((function(){a(new Error("load ".concat(e," timeout")))}),t)}))}return Promise.race([r(),c()])}(n[i].url):Promise.reject(new Error("\u672a\u627e\u5230\u5bf9\u5e94\u7684sdk")):Promise.resolve(),m(),p},"object"==typeof exports&&"undefined"!=typeof module?module.exports=o():"function"==typeof define&&define.amd?define(o):(e=e||self).mpx=o(); \ No newline at end of file diff --git a/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts b/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts index d63cbcffb9..4a8b5c0677 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/getInnerListeners.ts @@ -81,7 +81,7 @@ export const getCustomEvent = ( { detail = {}, layoutRef - }: { detail?: Record; layoutRef: LayoutRef }, + }: { detail?: Record; layoutRef?: LayoutRef }, props: Props = {} ) => { const targetInfo = extendObject({}, oe.target, { diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx index d205fdc4e3..b645d05094 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx @@ -1,6 +1,5 @@ -import { forwardRef, JSX, useEffect, useRef, useContext, useMemo, createElement } from 'react' -import { noop, warn } from '@mpxjs/utils' -import { View } from 'react-native' +import { forwardRef, JSX, useRef, useContext, useMemo, createElement } from 'react' +import { warn, getFocusedNavigation, isFunction } from '@mpxjs/utils' import { Portal } from '@ant-design/react-native' import { getCustomEvent } from './getInnerListeners' import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy' @@ -31,26 +30,25 @@ interface WebViewProps { } interface PayloadData { - data?: Record + [x: string]: any } type MessageData = { payload?: PayloadData, + args?: Array, type?: string, callbackId?: number } -const _WebView = forwardRef, WebViewProps>((props, ref): JSX.Element => { - const { src, bindmessage = noop, bindload = noop, binderror = noop } = props - if (!src) { - return () - } +const _WebView = forwardRef, WebViewProps>((props, ref): JSX.Element | null => { + const { src, bindmessage, bindload, binderror } = props + const mpx = global.__mpx if (props.style) { warn('The web-view component does not support the style prop.') } const pageId = useContext(RouteContext) const currentPage = useMemo(() => getCurrentPage(pageId), [pageId]) - + const webViewRef = useRef(null) const defaultWebViewStyle = { position: 'absolute' as 'absolute' | 'relative' | 'static', left: 0 as number, @@ -59,34 +57,14 @@ const _WebView = forwardRef, WebViewProps>((pr bottom: 0 as number } - const webViewRef = useRef(null) useNodesRef(props, ref, webViewRef, { style: defaultWebViewStyle }) - const _messageList = useRef([]) - const handleUnload = () => { - // 这里是 WebView 销毁前执行的逻辑 - bindmessage(getCustomEvent('messsage', {}, { - detail: { - data: _messageList.current - }, - layoutRef: webViewRef - })) + if (!src) { + return null } - useEffect(() => { - if (currentPage) { - currentPage.__webViewUrl = src - } - }, [src, currentPage]) - - useEffect(() => { - // 组件卸载时执行 - return () => { - handleUnload() - } - }, []) const _load = function (res: WebViewNavigationEvent) { const result = { type: 'load', @@ -107,8 +85,33 @@ const _WebView = forwardRef, WebViewProps>((pr } binderror(result) } + const injectedJavaScript = ` + if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) { + var _documentTitle = document.title; + window.ReactNativeWebView.postMessage(JSON.stringify({ + type: 'setTitle', + payload: { + _documentTitle: _documentTitle + } + })) + Object.defineProperty(document, 'title', { + set (val) { + _documentTitle = val + window.ReactNativeWebView.postMessage(JSON.stringify({ + type: 'setTitle', + payload: { + _documentTitle: _documentTitle + } + })) + }, + get () { + return _documentTitle + } + }); + } + ` const _changeUrl = function (navState: WebViewNavigation) { - if (currentPage) { + if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑 currentPage.__webViewUrl = navState.url } } @@ -121,43 +124,79 @@ const _WebView = forwardRef, WebViewProps>((pr if (typeof nativeEventData === 'string') { data = JSON.parse(nativeEventData) } - } catch (e) { - data = {} - } + } catch (e) {} + const args = data.args const postData: PayloadData = data.payload || {} - switch (data.type) { + const params = Array.isArray(args) ? args : [postData] + const type = data.type + switch (type) { + case 'setTitle': + { // case下不允许直接声明,包个块解决该问题 + const title = postData._documentTitle + if (title) { + const navigation = getFocusedNavigation() + navigation && navigation.setOptions({ title }) + } + } + break case 'postMessage': - _messageList.current.push(postData.data) + bindmessage && bindmessage(getCustomEvent('messsage', {}, { // RN组件销毁顺序与小程序不一致,所以改成和支付宝消息一致 + detail: { + data: params[0]?.data + } + })) asyncCallback = Promise.resolve({ errMsg: 'invokeWebappApi:ok' }) break case 'navigateTo': - asyncCallback = navObj.navigateTo(postData) + asyncCallback = navObj.navigateTo(...params) break case 'navigateBack': - asyncCallback = navObj.navigateBack(postData) + asyncCallback = navObj.navigateBack(...params) break case 'redirectTo': - asyncCallback = navObj.redirectTo(postData) + asyncCallback = navObj.redirectTo(...params) break case 'switchTab': - asyncCallback = navObj.switchTab(postData) + asyncCallback = navObj.switchTab(...params) break case 'reLaunch': - asyncCallback = navObj.reLaunch(postData) + asyncCallback = navObj.reLaunch(...params) + break + default: + if (type) { + const implement = mpx.config.webviewConfig.apiImplementations && mpx.config.webviewConfig.apiImplementations[type] + if (isFunction(implement)) { + asyncCallback = Promise.resolve(implement(...params)) + } else { + /* eslint-disable prefer-promise-reject-errors */ + asyncCallback = Promise.reject({ + errMsg: `未在apiImplementations中配置${type}方法` + }) + } + } break } asyncCallback && asyncCallback.then((res: any) => { if (webViewRef.current?.postMessage) { const test = JSON.stringify({ - type: data.type, + type, callbackId: data.callbackId, result: res }) webViewRef.current.postMessage(test) } + }).catch((error: any) => { + if (webViewRef.current?.postMessage) { + const test = JSON.stringify({ + type, + callbackId: data.callbackId, + error + }) + webViewRef.current.postMessage(test) + } }) } const events = {} @@ -172,11 +211,9 @@ const _WebView = forwardRef, WebViewProps>((pr onError: _error }) } - if (bindmessage) { - extendObject(events, { - onMessage: _message - }) - } + extendObject(events, { + onMessage: _message + }) return createElement(Portal, null, createElement(WebView, extendObject({ style: defaultWebViewStyle, diff --git a/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts b/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts index ed58b3fb4c..052fc1ac56 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts @@ -19,7 +19,8 @@ declare module '@mpxjs/utils' { bottom: number left: number right: number - } + }, + setOptions: (params: Record) => void } | undefined } diff --git a/packages/webpack-plugin/lib/runtime/components/web/mpx-web-view.vue b/packages/webpack-plugin/lib/runtime/components/web/mpx-web-view.vue index b3fecfa9b6..0e1ff52a63 100644 --- a/packages/webpack-plugin/lib/runtime/components/web/mpx-web-view.vue +++ b/packages/webpack-plugin/lib/runtime/components/web/mpx-web-view.vue @@ -5,7 +5,8 @@