react-native - Expo.FileSystem.downloadAsync不显示下载通知

标签 react-native expo

我正在使用expo FileSystem下载pdf文件。 API响应进入成功功能。但是,我无法将下载的文件显示给用户。

预期的行为应类似于我们通常在状态栏上看到通知图标,然后单击该图标会打开您的文件。

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);
 });

最佳答案

这有一个或两个技巧,但这是使用Expo的解决方案,该技术可在iOS和Android上使用。

在一个新的Expo项目中,修改以下两个文件:

  • 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:添加以下依赖项(react-native-easy-toast的分支)
  • "react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"
    

    关于此解决方案,有两个重要的注意事项:
  • 最多使用Expo API,用于外部本地通知和文件读写操作,这限制了当前解决方案to being unable写入Expo自己目录以外的其他位置。
  • 文件下载后,如果应用程序处于事件状态(Expo当前不支持前台通知),则向用户显示可自定义的Toast,或者发送本地推送通知以使用户知道下载已完成。单击这两者中的任何一个,将使用<Text>组件在 View 中显示文件的内容。
  • 由于 toast 的限制,尚未直接使用crazycodeboy/react-native-easy-toast存储库,这是当前不考虑触摸事件的原因。在原始请求中实现合并请求之前, fork 的仓库使此功能可用。我建议一旦修补后再切换回原始版本,因为我可能不会维护我的版本。
  • 尽管Snack中的此项目is also available,但由于如上所述的package.json中的using a git repository的需要以及变量作用域中的其他明显矛盾,它无法运行。这将通过合并请求或Snack中的新功能来解决。
  • 可以支持by Expo itself或通过诸如this PDF viewer之类的外部软件包来支持其他文件类型。但是,必须进一步修改代码。
  • 尽管React Native中有 TouchableWithoutFeedback ,但差异很大,但Toast(内部通知)是使用other similar ones组件创建的。可以在代码中自定义此组件(搜索toastDOM),但将来可以通过Expo中的内部通知来定制might even be replaceable
  • 最后,文件下载后,通知会被故意延迟三秒钟-这使我们可以在应用程序处于后台时测试通知。随时删除延迟和trigger the notification immediately

  • 就是这样!我认为这为使用Expo进行文件下载和预览提供了一个很好的起点。

    代码库also available on GitHub

    关于react-native - Expo.FileSystem.downloadAsync不显示下载通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47979921/

    相关文章:

    node.js - 为什么需要在 git repo 中删除 node_modules 文件夹?

    react-native - RNFS.exists() 总是返回 TRUE

    javascript - react native : Unable to change color of text within <TextInput> component

    javascript - React Native AsyncStorage 保存多个项目

    android - 有没有办法反编译通过 Expo 构建的 apk 并在 Android Studio 中打开生成的项目?

    Firebase 云函数和 React Native

    javascript - 添加正文时在 POST 请求中响应 native 网络错误

    react-native - FormProvider 内的 useFormContext 为 null

    android - Expo.Pedometer.getStepCountAsync 的奇怪属性

    android - 应用程序仅在真实设备上崩溃 | react 原生 |世博会