React Native WebView中injectJavascript调用函数失败问题求助
环境信息
- 设备:Apple Macbook Pro 2017 - 13英寸
- 系统:Macos 13.4.1
- Xcode:14.3.1
核心依赖版本
{ "dependencies": { "react-native": "0.71.8", "react-native-webview": "11.26.0" } }
错误提示
WARN Error evaluating injectedJavaScript: This is possibly due to an unsupported return type. Try adding true to the end of your injectedJavaScript string. Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=1, WKJavaScriptExceptionMessage=TypeError: window.login is not a function. (In 'window.login("John Smith", "John.Smith.1234", "*****")', 'window.login' is undefined), WKJavaScriptExceptionColumnNumber=13, WKJavaScriptExceptionSourceURL=about:blank, NSLocalizedDescription=A JavaScript exception occurred}
相关代码
WebView组件实现
// ... static webViewReference = null; static injectScriptCallback = null; static injectScript(script) { if (GunWebView.webViewReference) { GunWebView.webViewReference.injectJavaScript(script); } else { GunWebView.injectScriptCallback = () => { GunWebView.webViewReference.injectJavaScript(script); }; } } constructor(props) { super(props); } render() { return ( <WebView onMessage={this.props.onMessage} style={this.styles.webView} ref={(ref) => { GunWebView.webViewReference = ref; }} originWhitelist={["*"]} javaScriptEnabled={true} javaScriptEnabledAndroid={true} source={{ html: GUN_WEB_ABSTRACTION }} onLoadEnd={() => { if (GunWebView.injectScriptCallback) { GunWebView.injectScriptCallback(); GunWebView.injectScriptCallback = null; } }} /> ); } // ...
GUN_WEB_ABSTRACTION 页面代码
<script> // --END OF LIBRARY IMPORT-- (function (){ window.gun = new Gun("******************"); // Custom relay server (Unable to show) // Authentication functions: window.login = function (username, password, pid) { window.gun.user().auth(username, password, (ack) => { window.ReactNativeWebView.postMessage(JSON.stringify({pid ...ack})); }); } window.loginWithKeyPair = function (kayPair, pid) { window.gun.user().auth(keyPair, (ack) => { window.ReactNativeWebView.postMessage(JSON.stringify({pid ...ack})); }); }})(); </script> <!-- --END OF GUN HTML-- -->
调用逻辑
function injectJavascript(script: string) { GunWebView.injectScript(script); } // ... export function login(username: string, password: string) { // ... return new Promise((resolve, reject) => { const PID = uuid.v4(); registerProcess(PID, (ack: any) => { if (ack.err) { reject(ack.err); } else { resolve(ack); } }); injectJavascript(`window.login("${username}", "${password}", "${PID}");`); // ... Error handling and etc ... }); }
解决方案
1. 修复脚本语法错误
GUN页面代码存在两处语法错误,会导致脚本执行失败,window.login无法挂载:
- 对象展开语法错误:
{pid ...ack}→{pid, ...ack} - 参数名拼写错误:
kayPair→keyPair
修正后的脚本:
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script> <script> (function (){ window.gun = new Gun("******************"); // Custom relay server // Authentication functions: window.login = function (username, password, pid) { window.gun.user().auth(username, password, (ack) => { window.ReactNativeWebView.postMessage(JSON.stringify({pid, ...ack})); }); } window.loginWithKeyPair = function (keyPair, pid) { window.gun.user().auth(keyPair, (ack) => { window.ReactNativeWebView.postMessage(JSON.stringify({pid, ...ack})); }); }})(); // 通知RN脚本初始化完成 window.ReactNativeWebView.postMessage(JSON.stringify({type: 'GUN_INIT_SUCCESS'})); </script>
2. 确保GUN库已正确加载
原代码缺少GUN.js的引入,必须在初始化window.gun前加载GUN库,可使用CDN或本地打包的脚本文件。
3. 替换WebView加载完成逻辑
onLoadEnd触发时页面脚本可能还未完全执行,改为监听WebView发送的初始化完成消息再执行注入:
render() { return ( <WebView onMessage={(event) => { const messageData = JSON.parse(event.nativeEvent.data); // 处理GUN初始化完成的消息 if (messageData.type === 'GUN_INIT_SUCCESS') { if (GunWebView.injectScriptCallback) { GunWebView.injectScriptCallback(); GunWebView.injectScriptCallback = null; } } else { // 转发其他消息给父组件 this.props.onMessage(event); } }} style={this.styles.webView} ref={(ref) => { GunWebView.webViewReference = ref; }} originWhitelist={["*"]} javaScriptEnabled={true} javaScriptEnabledAndroid={true} domStorageEnabled={true} // 开启DOM存储,GUN依赖此特性 source={{ html: GUN_WEB_ABSTRACTION }} /> ); }
4. 修复injectJavaScript返回值问题
按照错误提示,在注入脚本末尾添加;true,确保返回支持的布尔类型:
injectJavascript(`window.login("${username}", "${password}", "${PID}");true;`);
5. 避免字符串插值的安全问题
如果用户名/密码包含引号,直接字符串插值会导致语法错误,建议用JSON.stringify处理参数:
const script = `window.login(${JSON.stringify(username)}, ${JSON.stringify(password)}, ${JSON.stringify(PID)});true;`; injectJavascript(script);
内容的提问来源于stack exchange,提问作者Alvin Cheng

