highcharts / highcharts-react-native

Other
103 stars 81 forks source link

Chart is not rendering after generating apk file and installed on mobile #130

Open Gangeshwar3 opened 3 years ago

Gangeshwar3 commented 3 years ago

Hello,

i am using highcharts in my project,it worked well in development mode and when it is installed on mobile through apk or publish through expo, the charts are not rendering, i have done all the things adding merto.config.js, editing the method

    getAssetAsString = async (asset) => {
        const downloadedModules = await FileSystem.readDirectoryAsync(FileSystem.cacheDirectory)
        let fileName = 'ExponentAsset-' + asset.hash + '.' + asset.type

        if (!downloadedModules.includes(fileName)) {
            await asset.downloadAsync()
        }

        return await FileSystem.readAsStringAsync(FileSystem.cacheDirectory + fileName)
    }

and also edited this method: ` setLayout = async () => { const indexHtml = Asset.fromModule(require('../highcharts-layout/index.html'))

    this.setState({
        layoutHTML: await this.getAssetAsString(indexHtml)
    })
}`

as per the comments from github issues nothing worked for me.

my package.json file { "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", "eject": "expo eject" }, "dependencies": { "@highcharts/highcharts-react-native": "^3.1.3", "expo": "~40.0.0", "expo-status-bar": "~1.0.3", "react": "16.13.1", "react-dom": "16.13.1", "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz", "react-native-web": "~0.13.12", "react-native-webview": "^11.0.3", "react-select": "^3.2.0" }, "devDependencies": { "@babel/core": "~7.9.0" }, "private": true }

metro.config.js

`const { getDefaultConfig } = require("metro-config");

module.exports = (async () => { const { resolver: { sourceExts, assetExts } } = await getDefaultConfig(); return { transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, inlineRequires: false } }) }, resolver: { sourceExts, assetExts: [...assetExts, "hcscript"] } }; })();`

I have created project using the command:expo init myProject. build the project by using the command: expo build:android.

any other configuration is required to render the charts after build, any one can help on this.

Thanks.

Denyllon commented 3 years ago

Hi @Gangeshwar3 ,

Thank you for the report. This problem is known to this wrapper's community, but unfortunately the package is no longer maintained since 1st of January 2021, what means that is not developed anymore, due to a significant range of differences between different React Native app environments and the ways of building them.

EDIT: Closed by accident. It should, of course, remain kept open.

Kind regards!

hungdev commented 3 years ago

I get the same issue :/

jabusir commented 3 years ago

Also having this issue. Anyone find a solution?

hungdev commented 3 years ago

@jabusir i fixed in this pull request https://github.com/highcharts/highcharts-react-native/pull/131 did you install the last version?

jabusir commented 3 years ago

I have @highcharts/highcharts-react-native": "^3.1.7" in my project. Is this the latest?

Denyllon commented 3 years ago

@jabusir That's right. It's the latest version of this package.

hungdev commented 3 years ago

I have @highcharts/highcharts-react-native": "^3.1.7" in my project. Is this the latest?

i don't know, but currently, it runs fine.

yutaro47 commented 3 years ago

I tested with App.js in this latest repository and having the same issue. Expo simulator works fine on both android and ios, but when build to apk or ipa, App does not show charts.

Following #104, I still got this error 'https://d1wp6m56sqw74a.cloudfront.net/~assets/ffceb4b4585b380fc666d3882abee7e5'isn't readable

devonkoch commented 3 years ago

I've been able to get a build running in iOS in Expo, iOS Simulator, and iOS App Store build by adding the following to package.json as a dependency

"@expo/metro-config": "^0.1.60",

I think it stems from recent versions of Expo having compatibility issues with the metro-config in the highcharts. This makes it so hcscripts are bundled and used when useCdn={false}

Still working on trying to get it running for Android

devonkoch commented 3 years ago

The fix was simply updating to upgrading to Expo 42.0.0 for me. Working on both iOS and Android

yutaro47 commented 3 years ago

The fix was simply updating to upgrading to Expo 42.0.0 for me. Working on both iOS and Android

Thank you for the information! I could solved the problem in the same way!

devonkoch commented 3 years ago

Update - after going on vacation, my simple "upgrade to expo 42.0.0" quickfix stopped working so I had to get a little creative. As others have mentioned, the issue lies in the return await FileSystem.readAsStringAsync(FileSystem.cacheDirectory + fileName) line of getAssetAsString. In my case (developing in Expo), it works in the Expo Go client, but fails as a simulator or archive build. To get around this I did 2 things:

1) copy paste the contents of highcharts-layout/index.html directly as the value in the <WebView> component's source>html:

<WebView
    ref={ref => { this.webviewRef = ref }}
    onMessage={this.props.onMessage ? (event) => this.props.onMessage(event.nativeEvent.data) : () => { }}
    source={
        {
            html: `
            <html>
                <head>
                    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0" />
                    <style>
                        #container {
                            width:100%;
                            height:100%;
                            top:0;
                            left:0;
                            right:0;
                            bottom:0;
                            position:absolute;
                            user-select: none;
                            -webkit-user-select: none;
                        }

                        * {
                            -webkit-touch-callout: none;
                            -webkit-user-select: none; /* Disable selection/copy in UIWebView */
                            -khtml-user-select: none;
                            -moz-user-select: none;
                            -ms-user-select: none;
                            user-select: none;
                        }
                    </style>
                    <script>
                        const hcUtils = {
                            // convert string to JSON, including functions.
                            parseOptions: function (chartOptions) {
                                const parseFunction = this.parseFunction;

                                const options = JSON.parse(chartOptions, function (val, key) {
                                    if (typeof key === 'string' && key.indexOf('function') > -1) {
                                        return parseFunction(key);
                                    } else {
                                        return key;
                                    }
                                });

                                return options;
                            },
                            // convert funtion string to function
                            parseFunction: function (fc) {

                                const fcArgs = fc.match(/\((.*?)\)/)[1],
                                    fcbody = fc.split('{');

                                return new Function(fcArgs, '{' + fcbody.slice(1).join('{'));
                            }
                        };

                        // Communication between React app and webview. Receive chart options as string.
                        document.addEventListener('message', function (data) {
                            Highcharts.charts[0].update(
                                hcUtils.parseOptions(data.data),
                                true,
                                true,
                                true
                            );
                        });

                        window.addEventListener('message', function (data) {
                            Highcharts.charts[0].update(
                                hcUtils.parseOptions(data.data),
                                true,
                                true,
                                true
                            );
                        });
                    </script>
                </head>
                <body>
                    <div id="container"></div>
                </body>
                </html>

            `
        }
    }
    injectedJavaScript={runFirst}
    javaScriptEnabled={true}
    originWhitelist={["*"]}
    automaticallyAdjustContentInsets={true}
    allowFileAccess={true}
    domStorageEnabled={true}
    useWebKit={true}
    scrollEnabled={false}
    mixedContentMode='always'
    allowFileAccessFromFileURLs={true}
    startInLoadingState={this.props.loader}
    style={this.props.webviewStyles}
    androidHardwareAccelerationDisabled
    {...this.props.webviewProps}
/>

2) Log the final result of the stringifiedScripts object, copy paste the result into a separate JSON, and then import it and script

HighchartsReactNative.js:

import * as stringifiedScripts from './stringifiedScripts';

..

setHcAssets = async (useCDN) => {
      try {
          await this.setLayout() // deleted await this.setScripts() lines, but left await this.setLayout() to prevent unmounted React Component error
          this.setState({
              hcModulesReady: true
          })
      } catch (error) {
          console.error("Failed to fetch scripts or layout. " + error.message)
      }
  }

setLayout = async () => {
        // const indexHtml = Asset.fromModule(require('../highcharts-layout/index.html'))

        // this.setState({
        //     layoutHTML: await this.getAssetAsString(indexHtml)
        // })
    }

stringifiedScripts.json: https://gist.github.com/devonkoch/bd9b9c64149f9f71eb1c1e05ea994f75

In order to get the contents of the gist, I used console.dir

setHcAssets = async (useCDN) => {
      try {
          await this.setLayout()
          await this.addScript('highcharts', null, useCDN)
          await this.addScript('highcharts-more', null, useCDN)
          await this.addScript('highcharts-3d', null, useCDN)
          for (const mod of this.state.modules) {
              await this.addScript(mod, true, useCDN)
          }

          console.dir(stringifiedScripts);

          this.setState({
              hcModulesReady: true
          })
      } catch (error) {
          console.error("Failed to fetch scripts or layout. " + error.message)
      }
  }

below the last call to the call to await this.setLayout() using React Native Debugger tools in the Chrome Dev tools console (right-click, copy paste). It was a bit of a struggle to find a way to get the long contents since Expo by default truncates logging to 10,000 characters