Expo.FileSystem.downloadAsync do not show download notification












6















I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.



The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.



FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});









share|improve this question























  • Do you consider both Android and iOS? Which file types will be allowed for download?

    – Siavas
    Jan 21 at 23:35











  • @Siavas (Bounty giver) For me, both. In my case it's a simple *.txt

    – Charanor
    Jan 24 at 19:23











  • @Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.

    – Siavas
    Jan 24 at 22:45











  • @Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)

    – Charanor
    Jan 24 at 22:49













  • @Charanor have added a solution to your use-case. Let me know how this goes for you.

    – Siavas
    Jan 26 at 14:27
















6















I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.



The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.



FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});









share|improve this question























  • Do you consider both Android and iOS? Which file types will be allowed for download?

    – Siavas
    Jan 21 at 23:35











  • @Siavas (Bounty giver) For me, both. In my case it's a simple *.txt

    – Charanor
    Jan 24 at 19:23











  • @Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.

    – Siavas
    Jan 24 at 22:45











  • @Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)

    – Charanor
    Jan 24 at 22:49













  • @Charanor have added a solution to your use-case. Let me know how this goes for you.

    – Siavas
    Jan 26 at 14:27














6












6








6


1






I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.



The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.



FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});









share|improve this question














I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.



The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.



FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});






react-native expo






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 26 '17 at 14:26









CarlosCarlos

2,4881757124




2,4881757124













  • Do you consider both Android and iOS? Which file types will be allowed for download?

    – Siavas
    Jan 21 at 23:35











  • @Siavas (Bounty giver) For me, both. In my case it's a simple *.txt

    – Charanor
    Jan 24 at 19:23











  • @Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.

    – Siavas
    Jan 24 at 22:45











  • @Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)

    – Charanor
    Jan 24 at 22:49













  • @Charanor have added a solution to your use-case. Let me know how this goes for you.

    – Siavas
    Jan 26 at 14:27



















  • Do you consider both Android and iOS? Which file types will be allowed for download?

    – Siavas
    Jan 21 at 23:35











  • @Siavas (Bounty giver) For me, both. In my case it's a simple *.txt

    – Charanor
    Jan 24 at 19:23











  • @Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.

    – Siavas
    Jan 24 at 22:45











  • @Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)

    – Charanor
    Jan 24 at 22:49













  • @Charanor have added a solution to your use-case. Let me know how this goes for you.

    – Siavas
    Jan 26 at 14:27

















Do you consider both Android and iOS? Which file types will be allowed for download?

– Siavas
Jan 21 at 23:35





Do you consider both Android and iOS? Which file types will be allowed for download?

– Siavas
Jan 21 at 23:35













@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt

– Charanor
Jan 24 at 19:23





@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt

– Charanor
Jan 24 at 19:23













@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.

– Siavas
Jan 24 at 22:45





@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.

– Siavas
Jan 24 at 22:45













@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)

– Charanor
Jan 24 at 22:49







@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)

– Charanor
Jan 24 at 22:49















@Charanor have added a solution to your use-case. Let me know how this goes for you.

– Siavas
Jan 26 at 14:27





@Charanor have added a solution to your use-case. Let me know how this goes for you.

– Siavas
Jan 26 at 14:27












2 Answers
2






active

oldest

votes


















2














DownloadManager



I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.



However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:




Each app only has read and write access to locations under the following directories:




  • Expo.FileSystem.documentDirectory

  • Expo.FileSystem.cacheDirectory




https://docs.expo.io/versions/latest/sdk/filesystem



So there would be no way to access the file in Expo once it was downloaded.



Possible Solution



A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support



Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.



However, that would mean ejecting your application from Expo.






share|improve this answer































    2





    +50









    This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.



    In a new Expo project, amend the following two files:




    • App.js


    import React, { Component } from 'react';
    import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
    import { FileSystem, Constants, Notifications, Permissions } from 'expo';
    import Toast, {DURATION} from 'react-native-easy-toast';

    async function getiOSNotificationPermission() {
    const { status } = await Permissions.getAsync(
    Permissions.NOTIFICATIONS
    );
    if (status !== 'granted') {
    await Permissions.askAsync(Permissions.NOTIFICATIONS);
    }
    }

    export default class App extends Component {
    constructor(props) {
    super(props);
    // this.toast = null;
    this.listenForNotifications = this.listenForNotifications.bind(this);
    // this.openFile = this.openFile.bind(this);
    this.state = {
    filePreviewText: ''
    }
    }

    _handleButtonPress = () => {
    let fileName = 'document.txt';
    let fileUri = FileSystem.documentDirectory + fileName;
    FileSystem.downloadAsync(
    "https://raw.githubusercontent.com/expo/expo/master/README.md",
    fileUri
    ).then(({ uri }) => {
    console.log('Finished downloading to ', uri);

    const localnotification = {
    title: 'Download has finished',
    body: fileName + " has been downloaded. Tap to open file.",
    android: {
    sound: true,
    },
    ios: {
    sound: true,
    },

    data: {
    fileUri: uri
    },
    };
    localnotification.data.title = localnotification.title;
    localnotification.data.body = localnotification.body;
    let sendAfterFiveSeconds = Date.now();
    sendAfterFiveSeconds += 3000;

    const schedulingOptions = { time: sendAfterFiveSeconds };
    Notifications.scheduleLocalNotificationAsync(
    localnotification,
    schedulingOptions
    );
    })
    .catch(error => {
    console.error(error);
    Alert.alert(error);
    });
    };
    listenForNotifications = () => {
    const _this = this;

    Notifications.addListener(notification => {
    if (notification.origin === 'received') {
    // We could also make our own design for the toast
    // _this.refs.toast.show(<View><Text>hello world!</Text></View>);

    const toastDOM =
    <TouchableWithoutFeedback
    onPress={() => {this.openFile(notification.data.fileUri)}}
    style={{padding: '10', backgroundColor: 'green'}}>
    <Text style={styles.toastText}>{notification.data.body}</Text>
    </TouchableWithoutFeedback>;

    _this.toast.show(toastDOM, DURATION.FOREVER);
    } else if (notification.origin === 'selected') {
    this.openFile(notification.data.fileUri);
    }
    // Expo.Notifications.setBadgeNumberAsync(number);
    // Notifications.setBadgeNumberAsync(10);
    // Notifications.presentLocalNotificationAsync(notification);
    // Alert.alert(notification.title, notification.body);
    });
    };
    componentWillMount() {
    getiOSNotificationPermission();
    this.listenForNotifications();
    }
    componentDidMount() {
    // let asset = Asset.fromModule(md);
    // Toast.show('Hello World');
    }
    openFile = (fileUri) => {
    this.toast.close(40);
    console.log('Opening file ' + fileUri);
    FileSystem.readAsStringAsync(fileUri)
    .then((fileContents) => {
    // Get file contents in binary and convert to text
    // let fileTextContent = parseInt(fileContents, 2);
    this.setState({filePreviewText: fileContents});
    });
    }
    render() {
    return (
    <View style={styles.container}>
    <View style={styles.buttonsContainer}>
    <Button style={styles.button}
    title={"Download text file"}
    onPress={this._handleButtonPress}
    />
    <Button style={styles.button}
    title={"Clear File Preview"}
    onPress={() => {this.setState({filePreviewText: ""})}}
    />
    </View>
    <ScrollView style={styles.filePreview}>
    <Text>{this.state.filePreviewText}</Text>
    </ScrollView>
    <Toast ref={ (ref) => this.toast=ref }/>
    </View>
    );
    // <Toast
    // ref={ (ref) => this.toast=ref }
    // style={{backgroundColor:'green'}}
    // textStyle={{color:'white'}}
    // position={'bottom'}
    // positionValue={100}
    // opacity={0.8}
    // />
    }
    }

    const styles = StyleSheet.create({
    container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    },
    buttonsContainer: {
    flexDirection: 'row',
    },
    button: {
    flex: 1
    },
    filePreview: {
    flex: 1,
    padding: 10,
    },
    toastText: {
    color: 'white',
    padding: 5,
    justifyContent: 'flex-start',
    },
    });



    • package.json: Add the following dependency (fork of react-native-easy-toast)


    "react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"


    There are a couple of important notes about this solution:




    • Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.


    • Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the <Text> component.


    • The crazycodeboy/react-native-easy-toast repo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.


    • Although this project is also available in Snack, it will not run due to the need of using a git repository in package.json as mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.


    • Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.


    • The toast (internal notification) is created with a TouchableWithoutFeedback component, although there are other similar ones in React Native with various differences. This component can be customised in the code (search for toastDOM), but might even be replaceable in the future by internal notifications available in Expo.


    • Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.



    And that's it! I think this gives a good starting point for file downloading and previewing with Expo.



    Codebase also available on GitHub.






    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47979921%2fexpo-filesystem-downloadasync-do-not-show-download-notification%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2














      DownloadManager



      I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.



      However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:




      Each app only has read and write access to locations under the following directories:




      • Expo.FileSystem.documentDirectory

      • Expo.FileSystem.cacheDirectory




      https://docs.expo.io/versions/latest/sdk/filesystem



      So there would be no way to access the file in Expo once it was downloaded.



      Possible Solution



      A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
      https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support



      Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.



      However, that would mean ejecting your application from Expo.






      share|improve this answer




























        2














        DownloadManager



        I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.



        However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:




        Each app only has read and write access to locations under the following directories:




        • Expo.FileSystem.documentDirectory

        • Expo.FileSystem.cacheDirectory




        https://docs.expo.io/versions/latest/sdk/filesystem



        So there would be no way to access the file in Expo once it was downloaded.



        Possible Solution



        A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
        https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support



        Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.



        However, that would mean ejecting your application from Expo.






        share|improve this answer


























          2












          2








          2







          DownloadManager



          I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.



          However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:




          Each app only has read and write access to locations under the following directories:




          • Expo.FileSystem.documentDirectory

          • Expo.FileSystem.cacheDirectory




          https://docs.expo.io/versions/latest/sdk/filesystem



          So there would be no way to access the file in Expo once it was downloaded.



          Possible Solution



          A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
          https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support



          Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.



          However, that would mean ejecting your application from Expo.






          share|improve this answer













          DownloadManager



          I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.



          However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:




          Each app only has read and write access to locations under the following directories:




          • Expo.FileSystem.documentDirectory

          • Expo.FileSystem.cacheDirectory




          https://docs.expo.io/versions/latest/sdk/filesystem



          So there would be no way to access the file in Expo once it was downloaded.



          Possible Solution



          A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
          https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support



          Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.



          However, that would mean ejecting your application from Expo.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 20 at 11:35









          AndrewAndrew

          3,54911026




          3,54911026

























              2





              +50









              This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.



              In a new Expo project, amend the following two files:




              • App.js


              import React, { Component } from 'react';
              import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
              import { FileSystem, Constants, Notifications, Permissions } from 'expo';
              import Toast, {DURATION} from 'react-native-easy-toast';

              async function getiOSNotificationPermission() {
              const { status } = await Permissions.getAsync(
              Permissions.NOTIFICATIONS
              );
              if (status !== 'granted') {
              await Permissions.askAsync(Permissions.NOTIFICATIONS);
              }
              }

              export default class App extends Component {
              constructor(props) {
              super(props);
              // this.toast = null;
              this.listenForNotifications = this.listenForNotifications.bind(this);
              // this.openFile = this.openFile.bind(this);
              this.state = {
              filePreviewText: ''
              }
              }

              _handleButtonPress = () => {
              let fileName = 'document.txt';
              let fileUri = FileSystem.documentDirectory + fileName;
              FileSystem.downloadAsync(
              "https://raw.githubusercontent.com/expo/expo/master/README.md",
              fileUri
              ).then(({ uri }) => {
              console.log('Finished downloading to ', uri);

              const localnotification = {
              title: 'Download has finished',
              body: fileName + " has been downloaded. Tap to open file.",
              android: {
              sound: true,
              },
              ios: {
              sound: true,
              },

              data: {
              fileUri: uri
              },
              };
              localnotification.data.title = localnotification.title;
              localnotification.data.body = localnotification.body;
              let sendAfterFiveSeconds = Date.now();
              sendAfterFiveSeconds += 3000;

              const schedulingOptions = { time: sendAfterFiveSeconds };
              Notifications.scheduleLocalNotificationAsync(
              localnotification,
              schedulingOptions
              );
              })
              .catch(error => {
              console.error(error);
              Alert.alert(error);
              });
              };
              listenForNotifications = () => {
              const _this = this;

              Notifications.addListener(notification => {
              if (notification.origin === 'received') {
              // We could also make our own design for the toast
              // _this.refs.toast.show(<View><Text>hello world!</Text></View>);

              const toastDOM =
              <TouchableWithoutFeedback
              onPress={() => {this.openFile(notification.data.fileUri)}}
              style={{padding: '10', backgroundColor: 'green'}}>
              <Text style={styles.toastText}>{notification.data.body}</Text>
              </TouchableWithoutFeedback>;

              _this.toast.show(toastDOM, DURATION.FOREVER);
              } else if (notification.origin === 'selected') {
              this.openFile(notification.data.fileUri);
              }
              // Expo.Notifications.setBadgeNumberAsync(number);
              // Notifications.setBadgeNumberAsync(10);
              // Notifications.presentLocalNotificationAsync(notification);
              // Alert.alert(notification.title, notification.body);
              });
              };
              componentWillMount() {
              getiOSNotificationPermission();
              this.listenForNotifications();
              }
              componentDidMount() {
              // let asset = Asset.fromModule(md);
              // Toast.show('Hello World');
              }
              openFile = (fileUri) => {
              this.toast.close(40);
              console.log('Opening file ' + fileUri);
              FileSystem.readAsStringAsync(fileUri)
              .then((fileContents) => {
              // Get file contents in binary and convert to text
              // let fileTextContent = parseInt(fileContents, 2);
              this.setState({filePreviewText: fileContents});
              });
              }
              render() {
              return (
              <View style={styles.container}>
              <View style={styles.buttonsContainer}>
              <Button style={styles.button}
              title={"Download text file"}
              onPress={this._handleButtonPress}
              />
              <Button style={styles.button}
              title={"Clear File Preview"}
              onPress={() => {this.setState({filePreviewText: ""})}}
              />
              </View>
              <ScrollView style={styles.filePreview}>
              <Text>{this.state.filePreviewText}</Text>
              </ScrollView>
              <Toast ref={ (ref) => this.toast=ref }/>
              </View>
              );
              // <Toast
              // ref={ (ref) => this.toast=ref }
              // style={{backgroundColor:'green'}}
              // textStyle={{color:'white'}}
              // position={'bottom'}
              // positionValue={100}
              // opacity={0.8}
              // />
              }
              }

              const styles = StyleSheet.create({
              container: {
              flex: 1,
              alignItems: 'center',
              justifyContent: 'center',
              paddingTop: Constants.statusBarHeight,
              backgroundColor: '#ecf0f1',
              },
              buttonsContainer: {
              flexDirection: 'row',
              },
              button: {
              flex: 1
              },
              filePreview: {
              flex: 1,
              padding: 10,
              },
              toastText: {
              color: 'white',
              padding: 5,
              justifyContent: 'flex-start',
              },
              });



              • package.json: Add the following dependency (fork of react-native-easy-toast)


              "react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"


              There are a couple of important notes about this solution:




              • Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.


              • Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the <Text> component.


              • The crazycodeboy/react-native-easy-toast repo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.


              • Although this project is also available in Snack, it will not run due to the need of using a git repository in package.json as mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.


              • Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.


              • The toast (internal notification) is created with a TouchableWithoutFeedback component, although there are other similar ones in React Native with various differences. This component can be customised in the code (search for toastDOM), but might even be replaceable in the future by internal notifications available in Expo.


              • Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.



              And that's it! I think this gives a good starting point for file downloading and previewing with Expo.



              Codebase also available on GitHub.






              share|improve this answer




























                2





                +50









                This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.



                In a new Expo project, amend the following two files:




                • App.js


                import React, { Component } from 'react';
                import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
                import { FileSystem, Constants, Notifications, Permissions } from 'expo';
                import Toast, {DURATION} from 'react-native-easy-toast';

                async function getiOSNotificationPermission() {
                const { status } = await Permissions.getAsync(
                Permissions.NOTIFICATIONS
                );
                if (status !== 'granted') {
                await Permissions.askAsync(Permissions.NOTIFICATIONS);
                }
                }

                export default class App extends Component {
                constructor(props) {
                super(props);
                // this.toast = null;
                this.listenForNotifications = this.listenForNotifications.bind(this);
                // this.openFile = this.openFile.bind(this);
                this.state = {
                filePreviewText: ''
                }
                }

                _handleButtonPress = () => {
                let fileName = 'document.txt';
                let fileUri = FileSystem.documentDirectory + fileName;
                FileSystem.downloadAsync(
                "https://raw.githubusercontent.com/expo/expo/master/README.md",
                fileUri
                ).then(({ uri }) => {
                console.log('Finished downloading to ', uri);

                const localnotification = {
                title: 'Download has finished',
                body: fileName + " has been downloaded. Tap to open file.",
                android: {
                sound: true,
                },
                ios: {
                sound: true,
                },

                data: {
                fileUri: uri
                },
                };
                localnotification.data.title = localnotification.title;
                localnotification.data.body = localnotification.body;
                let sendAfterFiveSeconds = Date.now();
                sendAfterFiveSeconds += 3000;

                const schedulingOptions = { time: sendAfterFiveSeconds };
                Notifications.scheduleLocalNotificationAsync(
                localnotification,
                schedulingOptions
                );
                })
                .catch(error => {
                console.error(error);
                Alert.alert(error);
                });
                };
                listenForNotifications = () => {
                const _this = this;

                Notifications.addListener(notification => {
                if (notification.origin === 'received') {
                // We could also make our own design for the toast
                // _this.refs.toast.show(<View><Text>hello world!</Text></View>);

                const toastDOM =
                <TouchableWithoutFeedback
                onPress={() => {this.openFile(notification.data.fileUri)}}
                style={{padding: '10', backgroundColor: 'green'}}>
                <Text style={styles.toastText}>{notification.data.body}</Text>
                </TouchableWithoutFeedback>;

                _this.toast.show(toastDOM, DURATION.FOREVER);
                } else if (notification.origin === 'selected') {
                this.openFile(notification.data.fileUri);
                }
                // Expo.Notifications.setBadgeNumberAsync(number);
                // Notifications.setBadgeNumberAsync(10);
                // Notifications.presentLocalNotificationAsync(notification);
                // Alert.alert(notification.title, notification.body);
                });
                };
                componentWillMount() {
                getiOSNotificationPermission();
                this.listenForNotifications();
                }
                componentDidMount() {
                // let asset = Asset.fromModule(md);
                // Toast.show('Hello World');
                }
                openFile = (fileUri) => {
                this.toast.close(40);
                console.log('Opening file ' + fileUri);
                FileSystem.readAsStringAsync(fileUri)
                .then((fileContents) => {
                // Get file contents in binary and convert to text
                // let fileTextContent = parseInt(fileContents, 2);
                this.setState({filePreviewText: fileContents});
                });
                }
                render() {
                return (
                <View style={styles.container}>
                <View style={styles.buttonsContainer}>
                <Button style={styles.button}
                title={"Download text file"}
                onPress={this._handleButtonPress}
                />
                <Button style={styles.button}
                title={"Clear File Preview"}
                onPress={() => {this.setState({filePreviewText: ""})}}
                />
                </View>
                <ScrollView style={styles.filePreview}>
                <Text>{this.state.filePreviewText}</Text>
                </ScrollView>
                <Toast ref={ (ref) => this.toast=ref }/>
                </View>
                );
                // <Toast
                // ref={ (ref) => this.toast=ref }
                // style={{backgroundColor:'green'}}
                // textStyle={{color:'white'}}
                // position={'bottom'}
                // positionValue={100}
                // opacity={0.8}
                // />
                }
                }

                const styles = StyleSheet.create({
                container: {
                flex: 1,
                alignItems: 'center',
                justifyContent: 'center',
                paddingTop: Constants.statusBarHeight,
                backgroundColor: '#ecf0f1',
                },
                buttonsContainer: {
                flexDirection: 'row',
                },
                button: {
                flex: 1
                },
                filePreview: {
                flex: 1,
                padding: 10,
                },
                toastText: {
                color: 'white',
                padding: 5,
                justifyContent: 'flex-start',
                },
                });



                • package.json: Add the following dependency (fork of react-native-easy-toast)


                "react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"


                There are a couple of important notes about this solution:




                • Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.


                • Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the <Text> component.


                • The crazycodeboy/react-native-easy-toast repo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.


                • Although this project is also available in Snack, it will not run due to the need of using a git repository in package.json as mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.


                • Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.


                • The toast (internal notification) is created with a TouchableWithoutFeedback component, although there are other similar ones in React Native with various differences. This component can be customised in the code (search for toastDOM), but might even be replaceable in the future by internal notifications available in Expo.


                • Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.



                And that's it! I think this gives a good starting point for file downloading and previewing with Expo.



                Codebase also available on GitHub.






                share|improve this answer


























                  2





                  +50







                  2





                  +50



                  2




                  +50





                  This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.



                  In a new Expo project, amend the following two files:




                  • App.js


                  import React, { Component } from 'react';
                  import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
                  import { FileSystem, Constants, Notifications, Permissions } from 'expo';
                  import Toast, {DURATION} from 'react-native-easy-toast';

                  async function getiOSNotificationPermission() {
                  const { status } = await Permissions.getAsync(
                  Permissions.NOTIFICATIONS
                  );
                  if (status !== 'granted') {
                  await Permissions.askAsync(Permissions.NOTIFICATIONS);
                  }
                  }

                  export default class App extends Component {
                  constructor(props) {
                  super(props);
                  // this.toast = null;
                  this.listenForNotifications = this.listenForNotifications.bind(this);
                  // this.openFile = this.openFile.bind(this);
                  this.state = {
                  filePreviewText: ''
                  }
                  }

                  _handleButtonPress = () => {
                  let fileName = 'document.txt';
                  let fileUri = FileSystem.documentDirectory + fileName;
                  FileSystem.downloadAsync(
                  "https://raw.githubusercontent.com/expo/expo/master/README.md",
                  fileUri
                  ).then(({ uri }) => {
                  console.log('Finished downloading to ', uri);

                  const localnotification = {
                  title: 'Download has finished',
                  body: fileName + " has been downloaded. Tap to open file.",
                  android: {
                  sound: true,
                  },
                  ios: {
                  sound: true,
                  },

                  data: {
                  fileUri: uri
                  },
                  };
                  localnotification.data.title = localnotification.title;
                  localnotification.data.body = localnotification.body;
                  let sendAfterFiveSeconds = Date.now();
                  sendAfterFiveSeconds += 3000;

                  const schedulingOptions = { time: sendAfterFiveSeconds };
                  Notifications.scheduleLocalNotificationAsync(
                  localnotification,
                  schedulingOptions
                  );
                  })
                  .catch(error => {
                  console.error(error);
                  Alert.alert(error);
                  });
                  };
                  listenForNotifications = () => {
                  const _this = this;

                  Notifications.addListener(notification => {
                  if (notification.origin === 'received') {
                  // We could also make our own design for the toast
                  // _this.refs.toast.show(<View><Text>hello world!</Text></View>);

                  const toastDOM =
                  <TouchableWithoutFeedback
                  onPress={() => {this.openFile(notification.data.fileUri)}}
                  style={{padding: '10', backgroundColor: 'green'}}>
                  <Text style={styles.toastText}>{notification.data.body}</Text>
                  </TouchableWithoutFeedback>;

                  _this.toast.show(toastDOM, DURATION.FOREVER);
                  } else if (notification.origin === 'selected') {
                  this.openFile(notification.data.fileUri);
                  }
                  // Expo.Notifications.setBadgeNumberAsync(number);
                  // Notifications.setBadgeNumberAsync(10);
                  // Notifications.presentLocalNotificationAsync(notification);
                  // Alert.alert(notification.title, notification.body);
                  });
                  };
                  componentWillMount() {
                  getiOSNotificationPermission();
                  this.listenForNotifications();
                  }
                  componentDidMount() {
                  // let asset = Asset.fromModule(md);
                  // Toast.show('Hello World');
                  }
                  openFile = (fileUri) => {
                  this.toast.close(40);
                  console.log('Opening file ' + fileUri);
                  FileSystem.readAsStringAsync(fileUri)
                  .then((fileContents) => {
                  // Get file contents in binary and convert to text
                  // let fileTextContent = parseInt(fileContents, 2);
                  this.setState({filePreviewText: fileContents});
                  });
                  }
                  render() {
                  return (
                  <View style={styles.container}>
                  <View style={styles.buttonsContainer}>
                  <Button style={styles.button}
                  title={"Download text file"}
                  onPress={this._handleButtonPress}
                  />
                  <Button style={styles.button}
                  title={"Clear File Preview"}
                  onPress={() => {this.setState({filePreviewText: ""})}}
                  />
                  </View>
                  <ScrollView style={styles.filePreview}>
                  <Text>{this.state.filePreviewText}</Text>
                  </ScrollView>
                  <Toast ref={ (ref) => this.toast=ref }/>
                  </View>
                  );
                  // <Toast
                  // ref={ (ref) => this.toast=ref }
                  // style={{backgroundColor:'green'}}
                  // textStyle={{color:'white'}}
                  // position={'bottom'}
                  // positionValue={100}
                  // opacity={0.8}
                  // />
                  }
                  }

                  const styles = StyleSheet.create({
                  container: {
                  flex: 1,
                  alignItems: 'center',
                  justifyContent: 'center',
                  paddingTop: Constants.statusBarHeight,
                  backgroundColor: '#ecf0f1',
                  },
                  buttonsContainer: {
                  flexDirection: 'row',
                  },
                  button: {
                  flex: 1
                  },
                  filePreview: {
                  flex: 1,
                  padding: 10,
                  },
                  toastText: {
                  color: 'white',
                  padding: 5,
                  justifyContent: 'flex-start',
                  },
                  });



                  • package.json: Add the following dependency (fork of react-native-easy-toast)


                  "react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"


                  There are a couple of important notes about this solution:




                  • Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.


                  • Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the <Text> component.


                  • The crazycodeboy/react-native-easy-toast repo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.


                  • Although this project is also available in Snack, it will not run due to the need of using a git repository in package.json as mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.


                  • Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.


                  • The toast (internal notification) is created with a TouchableWithoutFeedback component, although there are other similar ones in React Native with various differences. This component can be customised in the code (search for toastDOM), but might even be replaceable in the future by internal notifications available in Expo.


                  • Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.



                  And that's it! I think this gives a good starting point for file downloading and previewing with Expo.



                  Codebase also available on GitHub.






                  share|improve this answer













                  This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.



                  In a new Expo project, amend the following two files:




                  • App.js


                  import React, { Component } from 'react';
                  import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
                  import { FileSystem, Constants, Notifications, Permissions } from 'expo';
                  import Toast, {DURATION} from 'react-native-easy-toast';

                  async function getiOSNotificationPermission() {
                  const { status } = await Permissions.getAsync(
                  Permissions.NOTIFICATIONS
                  );
                  if (status !== 'granted') {
                  await Permissions.askAsync(Permissions.NOTIFICATIONS);
                  }
                  }

                  export default class App extends Component {
                  constructor(props) {
                  super(props);
                  // this.toast = null;
                  this.listenForNotifications = this.listenForNotifications.bind(this);
                  // this.openFile = this.openFile.bind(this);
                  this.state = {
                  filePreviewText: ''
                  }
                  }

                  _handleButtonPress = () => {
                  let fileName = 'document.txt';
                  let fileUri = FileSystem.documentDirectory + fileName;
                  FileSystem.downloadAsync(
                  "https://raw.githubusercontent.com/expo/expo/master/README.md",
                  fileUri
                  ).then(({ uri }) => {
                  console.log('Finished downloading to ', uri);

                  const localnotification = {
                  title: 'Download has finished',
                  body: fileName + " has been downloaded. Tap to open file.",
                  android: {
                  sound: true,
                  },
                  ios: {
                  sound: true,
                  },

                  data: {
                  fileUri: uri
                  },
                  };
                  localnotification.data.title = localnotification.title;
                  localnotification.data.body = localnotification.body;
                  let sendAfterFiveSeconds = Date.now();
                  sendAfterFiveSeconds += 3000;

                  const schedulingOptions = { time: sendAfterFiveSeconds };
                  Notifications.scheduleLocalNotificationAsync(
                  localnotification,
                  schedulingOptions
                  );
                  })
                  .catch(error => {
                  console.error(error);
                  Alert.alert(error);
                  });
                  };
                  listenForNotifications = () => {
                  const _this = this;

                  Notifications.addListener(notification => {
                  if (notification.origin === 'received') {
                  // We could also make our own design for the toast
                  // _this.refs.toast.show(<View><Text>hello world!</Text></View>);

                  const toastDOM =
                  <TouchableWithoutFeedback
                  onPress={() => {this.openFile(notification.data.fileUri)}}
                  style={{padding: '10', backgroundColor: 'green'}}>
                  <Text style={styles.toastText}>{notification.data.body}</Text>
                  </TouchableWithoutFeedback>;

                  _this.toast.show(toastDOM, DURATION.FOREVER);
                  } else if (notification.origin === 'selected') {
                  this.openFile(notification.data.fileUri);
                  }
                  // Expo.Notifications.setBadgeNumberAsync(number);
                  // Notifications.setBadgeNumberAsync(10);
                  // Notifications.presentLocalNotificationAsync(notification);
                  // Alert.alert(notification.title, notification.body);
                  });
                  };
                  componentWillMount() {
                  getiOSNotificationPermission();
                  this.listenForNotifications();
                  }
                  componentDidMount() {
                  // let asset = Asset.fromModule(md);
                  // Toast.show('Hello World');
                  }
                  openFile = (fileUri) => {
                  this.toast.close(40);
                  console.log('Opening file ' + fileUri);
                  FileSystem.readAsStringAsync(fileUri)
                  .then((fileContents) => {
                  // Get file contents in binary and convert to text
                  // let fileTextContent = parseInt(fileContents, 2);
                  this.setState({filePreviewText: fileContents});
                  });
                  }
                  render() {
                  return (
                  <View style={styles.container}>
                  <View style={styles.buttonsContainer}>
                  <Button style={styles.button}
                  title={"Download text file"}
                  onPress={this._handleButtonPress}
                  />
                  <Button style={styles.button}
                  title={"Clear File Preview"}
                  onPress={() => {this.setState({filePreviewText: ""})}}
                  />
                  </View>
                  <ScrollView style={styles.filePreview}>
                  <Text>{this.state.filePreviewText}</Text>
                  </ScrollView>
                  <Toast ref={ (ref) => this.toast=ref }/>
                  </View>
                  );
                  // <Toast
                  // ref={ (ref) => this.toast=ref }
                  // style={{backgroundColor:'green'}}
                  // textStyle={{color:'white'}}
                  // position={'bottom'}
                  // positionValue={100}
                  // opacity={0.8}
                  // />
                  }
                  }

                  const styles = StyleSheet.create({
                  container: {
                  flex: 1,
                  alignItems: 'center',
                  justifyContent: 'center',
                  paddingTop: Constants.statusBarHeight,
                  backgroundColor: '#ecf0f1',
                  },
                  buttonsContainer: {
                  flexDirection: 'row',
                  },
                  button: {
                  flex: 1
                  },
                  filePreview: {
                  flex: 1,
                  padding: 10,
                  },
                  toastText: {
                  color: 'white',
                  padding: 5,
                  justifyContent: 'flex-start',
                  },
                  });



                  • package.json: Add the following dependency (fork of react-native-easy-toast)


                  "react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"


                  There are a couple of important notes about this solution:




                  • Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.


                  • Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the <Text> component.


                  • The crazycodeboy/react-native-easy-toast repo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.


                  • Although this project is also available in Snack, it will not run due to the need of using a git repository in package.json as mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.


                  • Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.


                  • The toast (internal notification) is created with a TouchableWithoutFeedback component, although there are other similar ones in React Native with various differences. This component can be customised in the code (search for toastDOM), but might even be replaceable in the future by internal notifications available in Expo.


                  • Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.



                  And that's it! I think this gives a good starting point for file downloading and previewing with Expo.



                  Codebase also available on GitHub.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Jan 26 at 1:31









                  SiavasSiavas

                  1,77111023




                  1,77111023






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47979921%2fexpo-filesystem-downloadasync-do-not-show-download-notification%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Callistus III

                      Ostreoida

                      Index Sanctorum