Expo Push Notifications Not Pushing to Physical Device - react-native

My application in React Native using Expo was sending notifications beautifully using the code below to all of the tokens stored in Firebase. Now, after I published my app on the Expo.io website, it won't work and won't push any notification to any physical device at all. I have tried to rebuild the project in my local machine and run expo on my phone from my computer, and I console logged the information and all of the expo token information is correct and being pulled correctly. Why are the notifications not pushing now to any physical device? Please help. The try block below executes without error, but why aren't notifications pushing then? My component did mount also calls loadInformation & generateToken, and my render and return just call the sendPushNotif function when the user presses the send notification button.
My this.state.finalArray console logs the following: "Array [
Object {
"body": "test",
"title": "this is a test",
"to": Array [
"ExponentPushToken[.......]",
"ExponentPushToken[........]",
], }, ]"
constructor() {
super()
this.state = {
tokenArray: [],
finalArray: [],
}
}
loadInformation = async () => {
var tokens = []
firebase.database().ref('tokens/`).once('value', snapshot => {
const token = Object.values(snapshot.val());
token.map((item) => {
tokens.push(item.data)
return this.setState({ tokenArray: tokens })
})
})
}
generateToken = async () => {
this.state.finalArray = []
this.state.finalArray.push({
to: this.state.tokenArray,
title: this.state.title,
body: this.state.notification
})
}
sendPushNotification = async () => {
//these functions load all the token info from firebase and stores it into an array
this.loadInformation();
this.generateToken();
try {
let response = await fetch("https://exp.host/--/api/v2/push/send", {
method: "POST",
headers: {
Accept: "application/json",
"Accept-encoding": "gzip, deflate",
"Content-Type": "application/json",
},
body: JSON.stringify(this.state.finalArray), //final array has all the tokens and title and body info for the notif. i console logged this and it outputs the correct info
});
alert("Your notification was sent!");
} catch (error) {
console.log(error);
alert("Error! Your notification was not sent.");
}
};

The tokens you have in this.state.finalArray are Expo Push token which every Expo Go app has. So it will not work in Production as every device has its own devicePushToken.
ExponentPushToken[........] tokens work only on Expo Go App and not in Production. See this

Here is the Answer
As expo handle the notification registration for IOS but for android you have to register your app with firebase
So you have to register your app with firebase for this
Click here to get full information
https://docs.expo.dev/push-notifications/using-fcm/
all steps are mentioned
OR for Video information Click here
https://www.youtube.com/watch?v=oRNwNintDW0

Related

Expo facebook login fails: error : server with the specified hostname could not be found?

UPDATE: it works in the IOS simulator, but only doesnt work in my expo go app.
I have an expo react native managed app. I tried to implement the facebook login but I always get the following error:
my code (there should not be problems with it, its just the sample code from expo)
const AuthScreen = () => {
import * as Facebook from 'expo-facebook';
const loginWithFacebook = async () => {
try {
await Facebook.initializeAsync({
appId: '<MYAPPID>',
});
const {type, token, expirationDate, permissions, declinedPermissions} =
await Facebook.logInWithReadPermissionsAsync({
permissions: ['public_profile'],
});
if (type === 'success') {
const response = await fetch(`https://graph.facebook.com/me?access_token=${token}`);
Alert.alert('Logged in!', `Hi ${(await response.json()).name}!`);
} else {
// type === 'cancel'
}
} catch ({message}) {
alert(`Facebook Login Error: ${message}`);
}
};
return (
<FontAwesome.Button name="facebook" onPress={loginWithFacebook}>Login With Facebook</FontAwesome.Button>
)
};
What I did so when registering my app:
in facebook developers I created my app 'rainy'.
In settings/basic I added IOS and Android.
a. in IOS I only added host.exp.Exponent as the Bundle ID
b. In android I only added the hash key: rRW++LUjmZZ+58EbN5DVhGAnkX4= (I couldnt find that hash on expo docs anymore but found it elsewhere and it should be up to date)
in app.json I added infoPlist with properties to ios as following:
...
"ios": {
"supportsTablet": true,
"infoPlist": {
"facebookScheme": "fb<MYAPPID>",
"facebookAppId": "<MYAPPID>",
"FacebookClientToken": "abcxxxxx", //got it from Settings > Advanced > Client Token
"facebookDisplayName": "rainy",
"facebookAutoLogAppEventsEnabled": false,
"facebookAdvertiserIDCollectionEnabled": false
}
},
...
I wasnt sure but also (after getting the error) tried to add to Valid OAuth Redirect URIs the following: https://auth.expo.io/#/rainy. not sure if even needed but the error is still the same
Also I expo installed expo-facebook.
Did I miss any step or did something wrong? Thank you!!

React Native w/ Expo: Axios post works on emulator, but not on physical device

I'm trying to upload an image and some data to my API with Axios on my Expo app. Here's the code:
// api.ts
import axios from 'axios'
const api = axios.create({
baseURL: 'http://999.999.999.999/api', // <-- my cloud server ip
responseType: 'json'
})
export default api
// register.ts
import FormData from 'form-data' // https://www.npmjs.com/package/form-data
import api from '../services/api'
const options = { headers: 'Content-Type': 'multipart/form-data' } }
export const register = async (formData: FormData): Promise<boolean> => {
try {
const response = api.post<{ error: boolean, data: string }>(
'/authentication/register',
formData,
options
)
return Boolean(response.data?.data)
} catch (error) {
return false
}
}
I'm also using the expo-image-picker and appending the result to FormData:
const result = await ImagePicker.launchCameraAsync({})
if (result.cancelled) {
return
}
const personalPhotoUriParts = result.uri.split('.')
const personalPhotoFileType = personalPhotoUriParts[personalPhotoUriParts.length - 1]
const formData = new FormData()
formData.append('email', 'teste#mail.com')
formData.appent('password', '123456')
formData.append('personal_photo', {
uri: result.uri,
name: `personal_photo.${personalPhotoFileType}`,
type: `image/${personalPhotoFileType}`
})
register(formData) // from register.ts
All the things work as expected on the emulator, send and print from PHP API body content I get:
// var_dump($_POST);
Array [
"email": "test#mail.com",
"password": "123456"
]
// var_dump($_FILES)
Object {
"personal_photo": Object {
"error": 0,
"name": "document_photo.jpg",
"size": 135327,
"tmp_name": "/tmp/php5o11qT",
"type": "image/jpg",
}
}
But when I try to send it from a physical device, I get an empty body on both cases:
// var_dump($_POST);
Array []
// var_dump(get_file_contents('php://input'));
// nothing
// var_dump($_FILES);
Array []
My bet is on FormData, I was using other API routes without problems (on physical device), but when I had to use multipart/form-data I've got this problem. For me, does not make sense since the same API worked with React JS (WEB), Postman, and RN w/ Expo on emulator.
Maybe you need to enable on your Android Manifest
android:usesCleartextTraffic="true"
your problem is on Android or iOS device ?

Send push notification using Expo

I am trying to send push notification using Expo, and I receive it. But there is no vibrate or sound and no pop up as well on my device. I am using Galaxy S9 with Android 9. I have not tried on Iphone yet.
Push notification is sent by nodejs and the user who installed the app will receive the push notification. User expo token is saved in firebase database. I succeed to save and fetch the token.
Below is from expo app
class App extends Component {
componentWillMount() {
firebase.initializeApp(config);
this.registerForPushNotificationsAsync();
}
async registerForPushNotificationsAsync(){
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
let finalStatus = existingStatus;
if (Platform.OS === 'android') {
Notifications.createChannelAndroidAsync('chat-messages', {
name: 'Chat messages',
sound: true,
priority: 'high', // was max
vibrate: [0, 250, 250, 250],
});
}
if (existingStatus !== 'granted') {
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
Below is from nodejs server-side
function sendMessage(to, title, body) {
const expo = new Expo();
let messages = [];
messages.push({
to, // Expo user token
body,
data: { withSome: 'data' },
ios: {
sound: true
},
android: {
"channelId": "chat-messages" //and this
}
})
let chunks = expo.chunkPushNotifications(messages);
let tickets = [];
(async () => {
for (let chunk of chunks) {
try {
let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
tickets.push(...ticketChunk);
} catch (error) {
console.error(error);
}
}
})();
}
Also could we redirect to web page when user click the push notification?
I see three problems on your backend code ( expo push notification docs for reference https://docs.expo.io/versions/latest/guides/push-notifications/):
According to the docs, there should be no ios or android properties on the request body;
sound should be either 'default' or null, instead of true;
You created the notification channel on the device, but when you send the notification, you forgot to tell which channel you are sending to.
All that said, your code that calls the expo push notifications api should look something like this:
messages.push({
to, // Expo user token
title: 'some title', //it is good practice to send title, and it will look better
body,
data: { withSome: 'data' },
priority: 'high', //to make sure notification is delivered as fast as possible. see documentation for more details
sound: true, //for iOS devices and android below 8.0
channelId: 'chat-messages', //for devices on android 8.0 and above
})
I hope this helps.

Correct setup with react-native-fcm

I feel like the docs at react-native-fcm are a bit of a mess and I am having a hard time figuring this out.
I currently have a production app and my android users are telling me they are not receiving notifications for events where they should be. So this is stressing me out a lot right now. On iOS everything seems fine.
In the react-native-fcm example app you can see the following:
//FCM.createNotificationChannel is mandatory for Android targeting >=8. Otherwise you won't see any notification
componentDidMount() {
FCM.createNotificationChannel({
id: 'default',
name: 'Default',
description: 'used for example',
priority: 'high'
})
}
Do I need to call FCM.createNotificationChannel()?? I mainly use remote notifications so is this relevant in any way?
Here is MY setup:
import FCM, {
FCMEvent,
NotificationType,
RemoteNotificationResult,
WillPresentNotificationResult,
} from 'react-native-fcm';
FCM.on(FCMEvent.Notification, async (notif) => {
// there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
FCM.presentLocalNotification({
id: "new_message", // (optional for instant notification)
title: notif.fcm.title, // as FCM payload
body: notif.fcm.body, // as FCM payload (required)
sound: "default", // as FCM payload
priority: "high", // as FCM payload
click_action: "com.myapp.MyCategory", // as FCM payload - this is used as category identifier on iOS.
badge: 10, // as FCM payload IOS only, set 0 to clear badges
number: 10, // Android only
ticker: "My Notification Ticker", // Android only
auto_cancel: true, // Android only (default true)
large_icon: "ic_launcher", // Android only
icon: "ic_launcher", // as FCM payload, you can relace this with custom icon you put in mipmap
color: "blue", // Android only
vibrate: 300, // Android only default: 300, no vibration if you pass 0
wake_screen: true, // Android only, wake up screen when notification arrives
group: "group", // Android only
picture: "https://google.png", // Android only bigPicture style
ongoing: false, // Android only
my_custom_data:'my_custom_field_value', // extra data you want to throw
lights: true, // Android only, LED blinking (default false)
});
if(Platform.OS ==='ios'){
//optional
//iOS requires developers to call completionHandler to end notification process. If you do not call it your background remote notifications could be throttled, to read more about it see https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application.
//This library handles it for you automatically with default behavior (for remote notification, finish with NoData; for WillPresent, finish depend on "show_in_foreground"). However if you want to return different result, follow the following code to override
//notif._notificationType is available for iOS platfrom
switch(notif._notificationType){
case NotificationType.Remote:
notif.finish(RemoteNotificationResult.NewData) //other types available: RemoteNotificationResult.NewData, RemoteNotificationResult.ResultFailed
break;
case NotificationType.NotificationResponse:
notif.finish();
break;
case NotificationType.WillPresent:
notif.finish(WillPresentNotificationResult.All) //other types available: WillPresentNotificationResult.None
break;
}
}
});
FCM.on(FCMEvent.RefreshToken, (token) => {
try {
const { currentUser } = firebase.auth();
let updates = {};
updates[`/allUsers/serviceUsers/${currentUser.uid}/userInfo/fcmToken`] = token;
return firebase.database().ref().update(updates).catch(err => console.log('fcm refresh error', err))
} catch (e) {
console.log('couldnt update fcm refresh token', e)
}
});
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
class App extends Component {
componentWillMount() {
let config = {configgg}
!firebase.apps.length ? firebase.initializeApp(config) : firebase.app();
FCM.requestPermissions();
}
render() {
return (
<Provider store={store}>
<Router/>
</Provider>
);
}
}
export default App;
I mainly use remote notifications and it is critical for my app for it to work. Is there anything I am missing in my setup?
Any hint or suggestions will help me out a lot! Thanks!
EDIT:
Found this in adb logcat when receiving a notification (that did not show up)
NotificationService: No Channel found for pkg=com.lisdoworker, channelId=null, id=0, tag=GCM-Notification:9015992, opPkg=com.lisdoworker, callingUid=10487, userId=0, incomingUserId=0, notificationUid=10487, notification=Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
Does this have to do with FCM.createNotificationChannel()??
Yeah, apparently createNotificationChannel was added in version 16 to support Android 8 and it is barely documented.

React-Native: Can't receive expo push notification on stand alone app

This is ss from standalone app, its gettings expo token but for some reason it wont show notifications
I can't receive push notification on my standalone apps and if someone else used the app from expo (not my phone) then he won't receive it either,
For some reason only i receive it ..that too on expo client and if i install the apk on my phone, then i get the error....
In these all situations the error is same,
{
"data": {
"status": "error",
"message": "SNS failed to send the notification (reason: EndpointDisabled, status code: 400).",
"details": {
"error": "DeviceNotRegistered",
"sns": {
"statusCode": 400,
"reason": "EndpointDisabled",
"__message": "Endpoint is disabled"
}
}
}
}
my notification js
import { Permissions, Notifications } from 'expo';
import { AsyncStorage } from 'react-native';
import axios from 'axios';
import {
IUSTCONNECT_URL
} from '../actions/types';
const server = IUSTCONNECT_URL;
export default async function registerForPushNotificationsAsync() {
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
let finalStatus = existingStatus;
// only ask if permissions have not already been determined, because
// iOS won't necessarily prompt the user a second time.
if (existingStatus !== 'granted') {
// Android remote notification permissions are granted during the app
// install, so this will only ask on iOS
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
// Stop here if the user did not grant permissions
if (finalStatus !== 'granted') {
return;
}
// Get the token that uniquely identifies this device
let token = await Notifications.getExpoPushTokenAsync();
console.log(token);
await AsyncStorage.setItem('notificationToken', token);
const adminFlag = await AsyncStorage.getItem('admin');
try {
const { data } = await axios.post(`${server}/admin/app_bridge/user.php`, {
job: 'updateExpoToken',
admin: adminFlag,
token: token
});
if(data.trim() === 'success') {
console.log('expo push notification token sent:');
} else {
console.log('error sending notification token:');
console.log(data);
}
} catch (e) {
console.log(e);
}
}
and i am calling registerForPushNotificationsAsync() on my child tab,
Everything works well for my expo app...rest it doesn't...
Any help?
The issue is with the device. you can see in error DeviceNotRegistered.
see expo docs here.
DeviceNotRegistered: the device cannot receive push notifications
anymore and you should stop sending messages to the given Expo push
token.
The problem is that in docs no information why this error is happening. Try with some other device's.
if you develop with firebase you need update your token, the steps are:
1 in your page of project firebase, select option setting.
2 navigate to option project settings.
3 select option cloud messasging.
4 on credetial of project copy the token.
5. in your terminal in root directory of project type:
expo push:android:upload --api-key <your token>
for more information visit
enter link description here
try send push notification Manually
enter link description here
i'm working with sdk 37.0.0