react-native-webview-invoke
react-native-webview-invoke copied to clipboard
hooks 组件件 push一个新的webview返回旧的webview,旧webview invoke定义的原生方法丢失
import { StackHeaderOptions } from '@react-navigation/stack/lib/typescript/src/types'; import React, { useCallback, useContext, useEffect, useRef } from 'react'; import { View, Platform, StatusBar, Keyboard, BackHandler, KeyboardEvent, NativeModules, StatusBarStyle, AppState, AppStateStatus } from 'react-native'; import { _openCamera, _openPicker } from '../../moudles/tokenPhoto'; import WebView from 'react-native-webview'; import createInvoke, { IMessager } from 'react-native-webview-invoke/native'; import { _testwebviewUrl } from '../../config/url'; import askPermission from '../../moudles/AskPermission'; import { getLocation } from '../../moudles/Location'; import JPush from 'jpush-react-native'; import styles from './indexstyle'; import { StoreContext } from '../../store'; import LoadError from '../../components/LoadErr'; import { useFocusEffect, useIsFocused } from '@react-navigation/native';
let statusBarHeight: number | undefined = 20;
const _PLATFROM = Platform.OS;
if (_PLATFROM === 'ios') { NativeModules.StatusBarManager.getHeight((s:any) => { statusBarHeight = s.height; }); } else statusBarHeight = StatusBar.currentHeight;
function Home(props:any) {
const webviewRef = useRef<WebView<{}>>(null);
const Invoke: IMessager = createInvoke(()=>webviewRef.current); // 创建注入原生方法的实列
const { state } = useContext(StoreContext);
const isFocused = useIsFocused();
const _keyboardDidShow:(e:KeyboardEvent)=>void = (e) => { // 键盘弹起
const js = ` window.keyboardDidShow && window.keyboardDidShow(${ e.endCoordinates.height })`;
webviewRef.current && webviewRef.current.injectJavaScript(js);
};
const _keyboardDidHide:()=>void = () => { // 键盘收起
const js = 'window.keyboardDidHide && window.keyboardDidHide()';
webviewRef.current && webviewRef.current.injectJavaScript(js);
};
const _onBackHander:()=>boolean = ()=>{ // 物理返回键
const js = 'window.onBackHander && window.onBackHander()';
webviewRef.current && webviewRef.current.injectJavaScript(js);
return true;
}
const _onAppState:(nextAppState:AppStateStatus)=>void = (nextAppState)=>{ //App前后台切换状态
const currAppState = AppState.currentState;
const js = `window.onAppState && window.onAppState(${currAppState},${nextAppState})`;
webviewRef.current && webviewRef.current.injectJavaScript(js);
}
const _push = (url:string, data?:{[key:string]:any},headerOptions?:StackHeaderOptions):void=>{ // 打开一个新的webview
console.log(99999)
props.navigation.push('Home',{
url,
...data,
headerOptions
})
};
const _pop = ()=>{ // 返回上一个路由栈
props.navigation.goBack();
}
const _setBarStyle = (color:StatusBarStyle)=>{ // 设置状态栏字体颜色
if(_PLATFROM == 'ios') NativeModules.Tools.setBarStyle(color);
else StatusBar.setBarStyle(color);
}
const _getStatusBarHeight:()=>number | undefined = ()=>{ // 获取状态栏高度
return statusBarHeight
};
const _exitApp:()=>void = ()=>{ // 退出app
if(_PLATFROM == 'android') BackHandler.exitApp();
}
const _reload:()=>void = ()=>{ // 重新加载
webviewRef.current?.reload();
}
useEffect(()=>{ // 定义注入webview的原生方法
// 打开一个新的webview
Invoke.define('push',_push);
// 回退路由栈
Invoke.define('pop',_pop)
// 设置状态栏样式'default' | 'light-content' | 'dark-content';
Invoke.define('setBarStyle', _setBarStyle);
// 获取状态栏高度
Invoke.define('getStatusBarHeight', _getStatusBarHeight);
// android 请求权限询问
Invoke.define('askPermission', askPermission);
// 选择相册
Invoke.define('openPicker', _openPicker);
// 拍照
Invoke.define('openCamera', _openCamera);
// 退出App
Invoke.define('exitApp', _exitApp);
// 重载
Invoke.define('reload', _reload);
// 定位
Invoke.define('getLocation', getLocation);
},[]);
useEffect(()=>{ // 监听 (键盘 | 物理返回 | AppState | 推送监听)
const keyboardDidShow = Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
const keyboardDidHide = Keyboard.addListener("keyboardDidHide", _keyboardDidHide);
const backHander = BackHandler.addEventListener('hardwareBackPress', _onBackHander);
AppState.addEventListener('change', _onAppState);
JPush.addNotificationListener(res => {
let {url} = res.extras || {url: null},
type = res.notificationEventType;
if (type == 'notificationOpened' && url) {
let json = JSON.stringify({url: url});
const js = ` window.recievedPushMessage && window.recievedPushMessage(${json})`;
webviewRef.current?.injectJavaScript(js);
}
});
return () => {
keyboardDidShow.remove();
keyboardDidHide.remove();
backHander.remove();
AppState.removeEventListener('change', _onAppState);
JPush.removeListener(()=>{});
};
},[]);
useFocusEffect(useCallback(()=>{
if(!isFocused){
const js = ` window.screenIsFocused && window.screenIsFocused()`;
webviewRef.current?.injectJavaScript(js);
}
},[isFocused]))
let _webviewUrl: string = state?.webviewUrl || ''
_webviewUrl = _testwebviewUrl;
return(
<View
style={ styles.container }
>
{ _PLATFROM == 'android' ? <StatusBar translucent={true} backgroundColor={'rgba(255,255,255,0)'} /> : null }
<WebView
ref={ webviewRef }
style={{flex: 1}}
sharedCookiesEnabled={true}
useSharedProcessPool={true}
source={{uri: props.route.params?.url || _webviewUrl }}
onLoadEnd={() => {}}
mixedContentMode={'always'} // compatibility
startInLoadingState={true}
textZoom={100}
allowsInlineMediaPlayback={true}
scrollEnabled={ props.route.params?.scrollEnabled || false }
onMessage={ Invoke.listener }
renderError={()=>(
<LoadError setBarStyle={ _setBarStyle } reload={ _reload }/>
)}
/>
</View>
)
}
export default Home;