Expo Push Notifications-当应用程序处于前台时会导致iOS崩溃

时间:2018-08-25 04:18:50

标签: react-native push-notification expo

我有一个Expo应用程序,我正在尝试处理该应用程序在前台时发送的推送通知。在Android上运行正常,但在iOS上,它在收到应用程序时便崩溃了。

我从Rails服务器发送了一个推送通知:

            params = ({
              to: token.expo_push_token,
              title: user.first_name,
              sound: "default",
              body: msg.body,
            })


            puts params
            puts params.class

            x = Net::HTTP.post_form(URI.parse('https://exp.host/--/api/v2/push/send'), params)
            puts x.body

我可以在它发送的服务器中看到

Hash
app[worker.1]: {"data":{"id":"9058abf3-7352-4181-a69d-0b5fc8a8525c","status":"ok"}}
4 TID-godk4ew98 ExpoPushWorker JID-51b823f8feeaf42c313e392e INFO: done: 2.005 sec

如果该应用已关闭,则推送通知将显示在锁定屏幕上。如果应用程序在前台打开,则不会发生任何事情。

我想在应用打开时监听通知,而App.js中有这个通知:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MessagesScreenRouter from './app/components/Router/MessagesScreenRouter';
import Sentry from 'sentry-expo';
import reducers from './app/reducers';

import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { Notifications } from 'expo';


export default class App extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      notification: {},
    }
    this._handleNotification = this._handleNotification.bind(this)
  }

  _handleNotification = (notification) => {
       console.log(notification)
       this.setState({notification: notification});
   };

  componentWillUnmount(){
    this._notificationSubscription && this._notificationSubscription.remove()
  }

  componentDidMount() {    
    this.notificationSubscription = Notifications.addListener(
      (notification) => this._handleNotification(notification),
    );
  }


  render() {
    return (
      <View style={{flex:1}}>
        <StatusBar hidden={true} />

        <View style={{height: 50, justifyContent: 'center', alignItems: 'center'}}>
          <Text>Origin: {this.state.notification.origin}</Text>
          <Text>Data: {JSON.stringify(this.state.notification)}</Text>
        </View>

        <Provider store={createStore(reducers)}>
            <MessagesScreenRouter/>
        </Provider>
      </View>
    );
  }
}

我整天都尝试了许多教程中的建议,但是我无法使它起作用。我在这里想念什么?

2 个答案:

答案 0 :(得分:0)

您不能像expo docs所述在模拟器上对其进行测试

  

注意:iOS和Android模拟器无法接收推送通知。要测试它们,您将需要使用真实的设备。此外,在模拟器上调用Permissions.askAsync时,无论是否选择允许,它都将以“不确定”状态立即解析。

只需运行exp publish并在expo客户端上对其进行测试。另外,您必须首先使用Permissions.askAsync寻求许可。

Doc的示例作品就像一个咒语,请查看:https://docs.expo.io/versions/v28.0.0/guides/push-notifications#__next

答案 1 :(得分:0)

此后,Expo可能已经在那方面进行了更新,现在它甚至可能正在使用您在注释(exp start -m tunnel中提到的命令。由于到目前为止,iOS上尚不提供前台通知(首先是might have even caused your issue),因此对于希望实现推送通知的人,此答案不是解决上面的问题。

我创建了一个文件下载器和预览器,可以在两个操作系统上同时显示内部和外部通知,而不会遇到此类问题。代码is available on GitHub和详细说明在this SO answer中给出。

与该帖子最相关的代码是在应用程序处于后台时使用Expo中的local notifications,并使用react-native-toast包中的烤面包在前台显示它们。实施this feature后,Expo Notifications可以替换此功能。

为完整起见,以下是该项目的代码:

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:当前使用分叉仓库,switch back时为feature becomes available

{
  "name": "local-notification-with-ios",
  "version": "0.0.0",
  "description": "No description",
  "author": null,
  "private": true,
  "main": "node_modules/expo/AppEntry.js",
  "dependencies": {
    "expo": "^32.0.0",
    "react": "16.5.0",
    "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
    "prop-types": "^15.5.7",
    "react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git#6eed52f4d64c796cb49bdafcd7b3986cf5975d62"
  }
}