Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webview settitle #1733

Merged
merged 16 commits into from
Dec 19, 2024
4 changes: 2 additions & 2 deletions examples/mpx-webview/H5/webviewbridge.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const getCustomEvent = (
{
detail = {},
layoutRef
}: { detail?: Record<string, unknown>; layoutRef: LayoutRef },
}: { detail?: Record<string, unknown>; layoutRef?: LayoutRef },
props: Props = {}
) => {
const targetInfo = extendObject({}, oe.target, {
Expand Down
135 changes: 86 additions & 49 deletions packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -31,26 +30,25 @@ interface WebViewProps {
}

interface PayloadData {
data?: Record<string, any>
[x: string]: any
}

type MessageData = {
payload?: PayloadData,
args?: Array<any>,
type?: string,
callbackId?: number
}

const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element => {
const { src, bindmessage = noop, bindload = noop, binderror = noop } = props
if (!src) {
return (<View></View>)
}
const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, 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<WebView>(null)
const defaultWebViewStyle = {
position: 'absolute' as 'absolute' | 'relative' | 'static',
left: 0 as number,
Expand All @@ -59,34 +57,14 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
bottom: 0 as number
}

const webViewRef = useRef<WebView>(null)
useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
style: defaultWebViewStyle
})

const _messageList = useRef<any[]>([])
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',
Expand All @@ -107,8 +85,33 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, 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
}
}
Expand All @@ -121,43 +124,79 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, 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 = {}
Expand All @@ -172,11 +211,9 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
onError: _error
})
}
if (bindmessage) {
extendObject(events, {
onMessage: _message
})
}
extendObject(events, {
onMessage: _message
})

return createElement(Portal, null, createElement(WebView, extendObject({
style: defaultWebViewStyle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ declare module '@mpxjs/utils' {
bottom: number
left: number
right: number
}
},
setOptions: (params: Record<string, any>) => void
} | undefined
}

Expand Down
Loading
Loading