Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Gangeshwar3 opened this issue Feb 1, 2021 · 12 comments

Comments

@Gangeshwar3
Copy link

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
Copy link
Contributor

Denyllon commented Feb 3, 2021

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!

@Denyllon Denyllon closed this as completed Feb 3, 2021
@Denyllon Denyllon reopened this Feb 3, 2021
@hungdev
Copy link
Contributor

hungdev commented Mar 22, 2021

I get the same issue :/

@jabusir
Copy link

jabusir commented Jun 1, 2021

Also having this issue. Anyone find a solution?

@hungdev
Copy link
Contributor

hungdev commented Jun 2, 2021

@jabusir i fixed in this pull request #131
did you install the last version?

@jabusir
Copy link

jabusir commented Jun 2, 2021

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

@Denyllon
Copy link
Contributor

Denyllon commented Jun 7, 2021

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

@hungdev
Copy link
Contributor

hungdev commented Jun 11, 2021

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
Copy link

yutaro47 commented Jun 27, 2021

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
Copy link

devonkoch commented Jul 14, 2021

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
Copy link

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

@yutaro47
Copy link

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
Copy link

devonkoch commented Aug 20, 2021

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}
/>
  1. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants