pinqy520 / react-native-webview-invoke Goto Github PK
View Code? Open in Web Editor NEWInvoke functions between React Native and WebView
License: MIT License
Invoke functions between React Native and WebView
License: MIT License
请问这个对系统最低的版本要求是什么?ios和安卓,我用安卓4.3不可以
你好,请问RN层怎么主动调用webview中的方法?或者说RN层可以主动向webview中提交数据么?
react-native-webview 5.x 之后 使用window.ReactNativeWebView.postMessage发消息,
这个库就不能用了。 @pinqy520
cannot invoke anything. syntax is obscure, no editor, even compiler cannot solve that syntax. A and B confusion (can be native and browser), is it compiled from TypeScript? Should be ts files included.
感谢分享,
首先说明这并不算这个RN插件的问题,只是在使用这个插件的时候遇到的使用上的问题,
webView中绑定的方法最后会更改 window.location.href 原地刷新页面,
安卓版没有任何问题,
然而iOS版的话,不会自动去更新页面,
怀疑时iOS的WebView相关设定的问题,
有遇到过类型情况么?
非常感谢
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;
非常感谢您的辛苦分享,但是demo运行不了哦?
看见react-native 的 pr也有人提交了,需要修改几个文件,但是这样不太方便呐,我没去修改,特来问问大神有没有什么解决方案?
我这边有问题请教您?
有个需求是这样的,web调用要rn接口改变header右侧的菜单按钮,每个菜单肯定都会有点击事件,我能把方法作为参数传过去,rn来调用这个方法吗?谢谢!
RN端 :
this.invoke.define('test', () => {return Promise.reject(false)})
WebView端:
window.WebViewInvoke.fn.test()
.then(function(res){ console.log(res) })
.catch(function(err){ console.error(err) })
这时候catch就不生效了,没有false的log
catch可以log出false
this.invoke.define('test', () => {return Promise.resolve(true)})
是正常的,then是能正常打出true结果的
Hi @pinqy520 , thanks for the great work 👍
I need some help invoking functions with Promise as return Value.
Any idea of how we can handle such use case?
提示是,存在箭头函数导致UglifyJs压缩失败
在iframe里加载invoke,调用native的方法不生效,是不是invoke.listener无法监听到iframe的window.postMessage方法
你好,我找不到示例的examples文件夹啊
请问0.2版本生到0.31版本有哪些更新呢? #
0
React 引入项目 后
import invoke from 'react-native-webview-invoke/browser'
用invoke.bind 出现 _browser2.default.bind is not a function
let _refWebview = React.useRef()
let invoke = createInvoke(() => _refWebview.current)
React.useEffect(() => {
// 暴露方法给 H5
invoke.define('route', setRoute)
return () => {}
}, [])
return (
<WebView
useWebKit
ref={_refWebview}
style={{ flex: 1 }}
source={{ uri: config.h5 + route.params.uri, headers: { 'Cache-Control': 'no-cache' } }}
automaticallyAdjustContentInsets={true}
decelerationRate="normal"
scrollEnabled={true}
javaScriptEnabled={true}
domStorageEnabled={true}
onMessage={invoke.listener}
nativeConfig={{ props: { flex: 1 } }}
onLoad={syntheticEvent => {
const { nativeEvent } = syntheticEvent
console.log(`nativeEvent.url: ${nativeEvent.url}`)
}}
onLoadProgress={({ nativeEvent }) => {
console.log(`nativeEvent.progress: ${nativeEvent.progress}`)
}}
onLoadStart={syntheticEvent => {
// update component to be aware of loading status
const { nativeEvent } = syntheticEvent
console.log(`onLoadStart nativeEvent.loading: ${nativeEvent.loading}`)
}}
onLoadEnd={syntheticEvent => {
// update component to be aware of loading status
const { nativeEvent } = syntheticEvent
console.log(`onLoadEnd nativeEvent.loading: ${nativeEvent.loading}`)
}}
onError={syntheticEvent => {
const { nativeEvent } = syntheticEvent
console.warn('WebView error: ', nativeEvent)
}}
onHttpError={syntheticEvent => {
const { nativeEvent } = syntheticEvent
console.warn(
'onHttpError WebView received error status code: ',
nativeEvent.statusCode
)
}}
originWhitelist={['*']}
allowFileAccessFromFileURLs={true}
allowFileAccess={true}
allowUniversalAccessFromFileURLs={true}
allowingReadAccessToURL={'file://'}
/>
)
H5 那边 会报 invoke.fn.route is not function
首先感谢楼主的分享
我的项目使用:
react native 0.39.2,
react-native-webview-invoke 0.2.2
react: 15.4.1
我的问题是:运行案例画面显示没问题,就是无法通信,也没有报错,按钮也可以点击
我是直接拷贝你的文件到我的项目,html文件放在网络使用http链接,界面运行没有报任何错误,只是无法通信,
我将html放在本地localhost访问也无法通信
proguard-rules.pro 中设置了 也不起作用
我也不知道为啥我提交了一次,出来了两次,这个我关了
Hi @pinqy520 thanks for the great work.
I am trying to test the package with the dev
the project work as expected on IOS but look like the invoking system didn't work on android platform in case we are using the new react-native-webview
any thoughts?
ios的debug 、 Android 的debug 和release都正常
Android7+都是对的,能够双方传递数据,Android6上面就不行了
去掉本库,用普通的window.ReactNativeWebView.postMessage和onMessage就可以,麻烦能修复下这个问题嘛?
web端和Rn代码是分开的,web怎么引用呢?
rn0.58以上,webview将要替换成react-native-webview,适用于这个三方的交互么,我替换成这个三方之后好像交互都失败了
《1》我在真机上使用时调取RN 的封装的方法回馈很慢,例如调取我封装的拍照功能,就需要等个7,8秒
《2》文档上的写法和Demo的不一样咧
《3》RN怎样调取html的方法呢?
Hi, thanks for this lib !
i have one question, how i can retrieve this
in react native function ?
this.Native.define('myFunc', this.myFunc)
After in the function
myFunc() {
console.log(this)
// can't access to this component
}
I have tried with .bind(this)
but nothing work.
Have you a idea ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.