我有一个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>
);
}
}
我整天都尝试了许多教程中的建议,但是我无法使它起作用。我在这里想念什么?
答案 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"
}
}