DEV Community

Takuya Matsuyama
Takuya Matsuyama

Posted on

Fixing an error: JSON value '1' of type NSNumber cannot be converted to NSString

After having upgraded React Native to 0.62.2, it got the following error:

JSON value '1' of type NSNumber cannot be converted to NSString
Enter fullscreen mode Exit fullscreen mode

TL;DR

  • Check your callstack
  • Check if you pass prop value wrong
    • In my case, I was passing boolean value instead of string

Callstack

Callstack

Look into variable contents at 13rd stack:

props

Most props are YES of boolean type for some reason. Weird.
It looks like it's WebView component:

WebView

The error happens when processing allowingReadAccessToURL:

allowingReadAccessToURL

allowingReadAccessToURL should be string

The error message was right.
allowingReadAccessToURL expects String:

RCT_EXPORT_VIEW_PROPERTY(allowingReadAccessToURL, NSString)
Enter fullscreen mode Exit fullscreen mode

in RNCWebView.m of react-native-webview:

- (void)visitSource
{
    // Check for a static html source first
    NSString *html = [RCTConvert NSString:_source[@"html"]];
    if (html) {
        NSURL *baseURL = [RCTConvert NSURL:_source[@"baseUrl"]];
        if (!baseURL) {
            baseURL = [NSURL URLWithString:@"about:blank"];
        }
        [_webView loadHTMLString:html baseURL:baseURL];
        return;
    }

    NSURLRequest *request = [self requestForSource:_source];
    // Because of the way React works, as pages redirect, we actually end up
    // passing the redirect urls back here, so we ignore them if trying to load
    // the same url. We'll expose a call to 'reload' to allow a user to load
    // the existing page.
    if ([request.URL isEqual:_webView.URL]) {
        return;
    }
    if (!request.URL) {
        // Clear the webview
        [_webView loadHTMLString:@"" baseURL:nil];
        return;
    }
    if (request.URL.host) {
        [_webView loadRequest:request];
    }
    else {
        NSURL* readAccessUrl = _allowingReadAccessToURL ? [RCTConvert NSURL:_allowingReadAccessToURL] : request.URL;
        [_webView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl];
    }
}
Enter fullscreen mode Exit fullscreen mode

So, it looks like I'm using it wrong:

  return (
    <WebView
      ref={webViewRef}
      source={source}
      originWhitelist={['*']}
      style={[styles.webView]}
      startInLoadingState
      hideKeyboardAccessoryView
      allowUniversalAccessFromFileURLs
      allowingReadAccessToURL
      onMessage={handleMessageFromWebView}
      onLoadEnd={handleWebViewLoad}
    />
  )
Enter fullscreen mode Exit fullscreen mode

It should be URL or something, according to the doc:

A String value that indicates which URLs the WebView's file can then reference in scripts, AJAX requests, and CSS imports. This is only used in for WebViews that are loaded with a source.uri set to a 'file://' URL. If not provided, the default is to only allow read access to the URL provided in source.uri itself.

So, the fix for my case would be:

diff --git a/src/components/mde-webview-bridge.js b/src/components/mde-webview-bridge.js
index 9ff7894..2401e5e 100644
--- a/src/components/mde-webview-bridge.js
+++ b/src/components/mde-webview-bridge.js
@@ -39,6 +39,9 @@ const MDEWebViewBridge = (props: Props) => {
           ? `file://${MainBundlePath.bundlePath}/webeditor/index.html`
           : 'file:///android_asset/webeditor/index.html'
       }
+  const allowingReadAccessToURL = isIOS()
+    ? `file://${MainBundlePath.bundlePath}/webeditor/`
+    : 'file:///android_asset/webeditor/'

   const sendMessageToWebView = useCallback(
     (message: BridgeMessage) => {
@@ -273,7 +276,7 @@ const MDEWebViewBridge = (props: Props) => {
       startInLoadingState
       hideKeyboardAccessoryView
       allowUniversalAccessFromFileURLs
-      allowingReadAccessToURL
+      allowingReadAccessToURL={allowingReadAccessToURL}
       onMessage={handleMessageFromWebView}
       onLoadEnd={handleWebViewLoad}
     />
Enter fullscreen mode Exit fullscreen mode

Okay, now it works fine!

Discussion (0)