I am experiencing issues regarding using the injectJavascript
method to inject and call a function from the WebView
component from the library: react-native-web-view
. I am doing this to workaround the limitations of GUN.js. Instead of running the gun.js on react native, I am abstracting it onto a webview. (Quite hacky though.)
Enviroment:
Computer: Apple Macbook Pro 2017 - 13"
OS: Macos 13.4.1
Xcode: 14.3.1
Error message:
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}
Package.json:
"dependencies": {
"@react-navigation/native": "^6.1.7",
"@react-navigation/native-stack": "^6.9.13",
"expo": "~48.0.18",
"expo-font": "~11.1.1",
"expo-splash-screen": "~0.18.2",
"expo-status-bar": "~1.4.4",
"react": "18.2.0",
"react-native": "0.71.8",
"react-native-get-random-values": "~1.8.0",
"react-native-safe-area-context": "4.5.0",
"react-native-screens": "~3.20.0",
"react-native-uuid": "^2.0.1",
"react-native-webview": "11.26.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "~18.0.27",
"@types/react-native": "^0.72.2",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"eslint": "~8.4.1",
"eslint-plugin-react": "^7.32.2",
"typescript": "^4.9.4"
},
Anyways Here's my code: webview component:
// ...
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-- -->
How I am calling it:
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 ...
});
}
I have tried to use the injectJavascript
prop and injecting the whole HTML code along with the calling logic. However, there is an error message and I am not expecting it to throw an error.