I’ve a react native app which contains expo-notifications library that sends notifications to customers on iOS and android gadgets. I’m dealing with an enormous subject. I used to be in a position to configure the venture on expo to allow push notification assist and likewise generated a certificates for the iOS half. Notifications are working completely high quality on android as they request for permissions for the android half and even show the expo push token for the notification and ship notifications usually. Nevertheless, concerning the iOS half, the notification permissions are being requested, and the expo push token exists, however the notification is just not being despatched on the iOS simulator whether or not the app is in foreground and even background. It doesn’t show an error, it simply doesn’t ship a notification.
Right here is the code
import { useFonts } from "expo-font";
import * as SplashScreen from "expo-splash-screen";
import { useCallback, useEffect } from "react";
import {
Alert,
Platform,
StyleSheet,
View,
PermissionsAndroid,
} from "react-native";
import { fonts } from "./constants/fonts";
import CustomNavigation from "./routes/CustomNavigation";
import * as Notifications from "expo-notifications";
import Constants from "expo-constants";
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "./retailer";
import { setPushToken } from "./retailer/options/pushtoken.slice";
import { Textual content } from "react-native-paper";
import { useNavigation } from "@react-navigation/native";
import { usePostUserLocationMutation } from "./retailer/api/profile";
import * as Location from "expo-location";
import * as TaskManager from "expo-task-manager";
import { useGetDriverShipmentsQuery } from "./retailer/api/shipments";
import { setUserLocation } from "./retailer/options/consumer.slice";
const LOCATION_TRACKING = "location-tracking";
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
async operate registerForPushNotificationsAsync() {
let token;
const { standing: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { standing } = await Notifications.requestPermissionsAsync();
finalStatus = standing;
}
if (finalStatus !== "granted") {
console.log("Did not get push token for push notification!");
return;
}
// Challenge ID may be present in app.json | app.config.js; additional > eas > projectId
// token = (await Notifications.getExpoPushTokenAsync({ projectId: "YOUR_PROJECT_ID" })).information;
token = (
await Notifications.getExpoPushTokenAsync({
projectId: Constants.manifest?.additional!.eas.projectId,
})
).information;
console.log(token);
// The token must be despatched to the server in order that it may be used to ship push notifications to the machine
// console.log(token);
return token;
}
const Index = () => {
const navigation = useNavigation<any>();
SplashScreen.preventAutoHideAsync();
const [fontsLoaded] = useFonts(fonts());
const [notification, setNotification] = React.useState<any>(false);
const dispatch = useDispatch<AppDispatch>();
const userState = useSelector<RootState, RootState["user"]>(
(state) => state.consumer
);
const expoPushToken = useSelector<RootState, RootState["pushToken"]>(
(state) => state.pushToken
);
const [postUserLocation, { data, isLoading, isSuccess, isError, error }] =
usePostUserLocationMutation();
const {
information: dataShipments,
isLoading: isLoadingShipments,
isSuccess: isSuccessShipments,
isFetching: isFetchingShipments,
} = useGetDriverShipmentsQuery(
{ web page: 0, expired: 0 },
{ pollingInterval: 10000 }
);
const notificationListener = React.useRef<any>();
const responseListener = React.useRef<any>();
React.useEffect(() => {
registerForPushNotificationsAsync().then((token) => {
dispatch(setPushToken({ pushToken: token }));
});
// This listener is fired at any time when a notification is obtained whereas the app is foregrounded
notificationListener.present =
Notifications.addNotificationReceivedListener((notification) => {
setNotification(notification);
});
// This listener is fired at any time when a consumer faucets on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
responseListener.present =
Notifications.addNotificationResponseReceivedListener((response) => {
const {
notification: {
request: {
content material: {
information: { display, props },
},
},
},
} = response;
// When the consumer faucets on the notification, this line checks in the event that they //are suppose to be taken to a selected display
if (display) {
if (props) {
navigation.navigate(display, { ...props });
} else {
navigation.navigate(display);
}
}
});
return () => {
Notifications.removeNotificationSubscription(
notificationListener.present
);
Notifications.removeNotificationSubscription(responseListener.present);
};
}, []);
if (dataShipments && dataShipments.shipments.size > 0) {
TaskManager.defineTask(LOCATION_TRACKING, async ({ information, error }) => {
attempt {
if (error) {
console.log("LOCATION_TRACKING process ERROR:", error);
return;
}
if (information) {
//@ts-ignore
const { areas } = information;
let lat = areas[0].coords.latitude;
let lengthy = areas[0].coords.longitude;
if (Boolean(userState.electronic mail)) {
const res = await postUserLocation({
lat: lat,
lng: lengthy,
}).unwrap();
console.log("res ", lat, lengthy);
dispatch(setUserLocation({ lat: lat, lng: lengthy }));
}
}
} catch (err) {
console.warn(err);
}
});
}
React.useEffect(() => {
if (expoPushToken) {
async operate requestLocationPermission() {
let hasPermissions = true;
attempt {
let resf = await Location.requestForegroundPermissionsAsync();
let resb = await Location.requestBackgroundPermissionsAsync();
if (resf.standing != "granted" && resb.standing != "granted") {
return;
}
hasPermissions = resf.standing == "granted" && resb.standing == "granted";
} catch (err: any) {
console.warn(err.message);
hasPermissions = false;
} lastly {
return hasPermissions;
}
}
async operate getLocation() {
const permissionsStatus = await requestLocationPermission();
if (
permissionsStatus &&
dataShipments &&
dataShipments.shipments.size > 0
) {
await Location.startLocationUpdatesAsync(LOCATION_TRACKING, {
accuracy: Location.Accuracy.Highest,
timeInterval: 5000,
distanceInterval: 0,
showsBackgroundLocationIndicator: true,
foregroundService: {
notificationTitle: "Location Monitoring",
notificationBody: `From the second you might be assigned the supply of a cargo, your location can be tracked to make sure the logistics of the cargo for the shipper's information. Whenever you end all of your deliveries, your location will not be tracked.`,
},
});
} else {
if (dataShipments && dataShipments.shipments.size === 0) {
await Location.stopLocationUpdatesAsync(LOCATION_TRACKING);
}
}
}
getLocation();
}
return () => {};
}, [expoPushToken, dataShipments]);
const cb = useCallback(async () => {
if (fontsLoaded) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) {
return null;
} else {
cb();
}
return <CustomNavigation />;
};
export default Index;
const types = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "middle",
justifyContent: "middle",
},
});
It is a portion of the server facet code on how we ship notifications
export const updateStatus = async (
req: Request,
res: Response,
subsequent: NextFunction
) => {
const { id, motion } = req.physique;
console.log("up to date");
const expo = req.expo;
const messages = [] as ExpoPushMessage[];
const currentUser = req.consumer;
const error = new CustomError("One thing went flawed!", 500);
attempt {
const foundShipment = await cargo
.findById(id)
.populate(["driver", "host"]);
if ((motion as actionType) === "select_driver") {
error.message = "forbidden motion";
error.standing = 403;
throw error;
}
console.log(motion);
console.log(currentUser._id.toString());
if (
(foundShipment.host as IUser)._id.toString() ===
currentUser._id.toString()
) {
const allowedActionsCustomer = getShipmentStatus(foundShipment.standing)[
"hostActions"
];
if (!allowedActionsCustomer.consists of(motion)) {
console.log("error");
error.message = "forbidden motion";
error.standing = 403;
throw error;
}
change (motion as actionType) {
case "acknowledge_completion":
for (let token of (foundShipment.driver as IUser).push_token) {
messages.push({
to: token,
information: { display: "driver" },
sound: "default",
title: "Cargo acknowledgement",
physique: "Your cargo has been acknowledged",
channelId: "default",
});
}
break;
case "cancel_shipment":
if (foundShipment.driver)
for (let token of (foundShipment.driver as IUser).push_token) {
messages.push({
to: token,
sound: "default",
information: { display: "driver" },
title: "Cargo canceled",
physique: "Your cargo has been cancelled",
channelId: "default",
});
}
break;
case "mark_late":
for (let token of (foundShipment.driver as IUser).push_token) {
messages.push({
to: token,
sound: "default",
information: { display: "driver" },
title: "Cargo delayed",
physique: "Your cargo is marked late",
channelId: "default",
});
}
break;
}
} else if (
(foundShipment.driver as IUser)._id.toString() ===
currentUser._id.toString()
) {
const allowedActionsDriver = getShipmentStatus(foundShipment.standing)[
"driverActions"
];
if (!allowedActionsDriver.consists of(motion)) {
error.message = "forbidden motion";
error.standing = 403;
throw error;
}
change (motion as actionType) {
case "cancel_shipment":
for (let token of (foundShipment.host as IUser).push_token) {
messages.push({
to: token,
sound: "default",
information: { display: "shipper" },
title: "Cargo canceled",
physique: "Your cargo has been cancelled",
channelId: "default",
});
}
break;
case "deliver_shipment":
for (let token of (foundShipment.host as IUser).push_token) {
messages.push({
to: token,
sound: "default",
information: { display: "shipper" },
title: "Cargo delivered",
physique: "Your cargo has been delivered",
channelId: "default",
});
}
break;
case "pick_up":
for (let token of (foundShipment.host as IUser).push_token) {
messages.push({
to: token,
sound: "default",
information: { display: "shipper" },
title: "Cargo picked up",
physique: "Your cargo has been picked up",
channelId: "default",
});
}
break;
}
} else {
error.message = "forbidden motion";
error.standing = 403;
throw error;
}
foundShipment.standing = getNewStatus(motion as actionType);
if (foundShipment.standing === "fulfilled") {
const foundDriver = await usersModel.findById(
(foundShipment.driver as IUser)._id.toString()
);
foundDriver.nb_successful_deliveries =
foundDriver.nb_successful_deliveries + 1;
if (foundShipment.shipment_payment_type !== "money") {
foundDriver.wallet_balance += foundShipment.shipment_price * 0.6;
}
await foundDriver.save();
} else if (foundShipment.standing === "unfulfilled") {
let foundDriver;
if (foundShipment.driver) {
foundDriver = await usersModel.findById(
(foundShipment.driver as IUser)._id.toString()
);
}
const foundShipper = await usersModel.findById(
(foundShipment.host as IUser)._id.toString()
);
if (foundShipment.shipment_payment_type !== "money") {
foundShipper.wallet_balance += foundShipment.shipment_price;
}
if (foundDriver) {
foundDriver.nb_failed_deliveries = foundDriver.nb_failed_deliveries + 1;
await foundDriver.save();
}
}
console.log(messages);
const chunks = expo.chunkPushNotifications(messages as any);
for (let chunk of chunks) {
if (chunk) {
await expo.sendPushNotificationsAsync(chunk);
}
}
await foundShipment.save();
res.ship({ standing: true });
} catch (err) {
return subsequent(err);
}
};
Can somebody please inform me what to do? I recognize your assist yall.
If anybody wants any extra code content material please let me know what to ship.
I attempted to console log the expo push token and it gave the push token on iOS simulator but it surely didnt ship the notification