DeviceNotRegistered: "ExponentPushToken[***]" is not a registered push notification recipient - react-native

I'm trying to implement expo push notifications on react native app built with expo !
I did everything mentioned on their docs ! i'm getting the token successfully but when i try sending a push notification to that token using their api or the tool they provide i get this error
DeviceNotRegistered: "ExponentPushToken[***]" is not a registered push notification recipient
This is how i'm getting the token !
export const useNotifications = () => {
const registerForPushNotificationsAsync = async () => {
if (Device.isDevice) {
const { status: existingStatus } =
await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== "granted") {
alert("Failed to get push token for push notification!");
return;
}
const token = (await Notifications.getExpoPushTokenAsync()).data;
console.log("TOKEN------------", token);
alert(token);
} else {
alert("Must use physical device for Push Notifications");
}
if (Platform.OS === "android") {
Notifications.setNotificationChannelAsync("default", {
name: "default",
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
});
}
};
const handleNotification = (notification = Notifications.Notification) => {
// could be useful if you want to display your own toast message
// could also make a server call to refresh data in other part of the app
};
// This listener is fired whenever a user taps on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
const handleNotificationResponse = (
response = Notifications.NotificationResponse
) => {
const data = ({ url } = response.notification.request.content.data);
if (data?.url) Linking.openURL(data.url);
};
return {
registerForPushNotificationsAsync,
handleNotification,
handleNotificationResponse,
};
};
useEffect(() => {
registerForPushNotificationsAsync();
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: true,
}),
});
const responseListener =
Notifications.addNotificationResponseReceivedListener(
handleNotificationResponse
);
return () => {
if (responseListener) {
Notifications.removeNotificationSubscription(responseListener);
}
};
}, []);
i run the eas build eas build -p android --profile preview so i can test it on a real device since push notifications works only on real devices and after that i pushed the cloud messaging server key that i got from my firebase project with this command expo push:android:upload --api-key <your-token-here>
As i said i successfully get the token but the i get the error when trying to send the notification!
am i missing a step or something ?
I tried run the build on two devices and both not working !

Related

Expo React native asks for location permissions in simulator but not in built app

App has been working fine for a while but now it's not prompting users for location permission which results in the features using location failing. On both simulator and physical device running expo go, the user is prompted to give permission to location data. (both iOS and Android) All other permissions it needs it asks for (push, camera and calendar)
export default function CheckIn(props) {
const { todayEvents } = useSelector(({ checkin }) => checkin);
const [venueIdd, setVenueId] = useState(0);
const [modalVisible, setModalVisible] = useState(false);
const [status, setStatus] = useState(null);
const [backgroundLocationPermission, setBackgroundLocationPermission] =
useState(null);
const dispatch = useDispatch();
TaskManager.defineTask("updateLocation", ({ data: { locations }, error }) => {
if (error) {
return;
}
dispatch(sendBackgroundLocation(locations[0].coords, venueIdd));
});
async function registerBackgroundFetchAsync() {
return BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 60 * 15, // 15 minutes
stopOnTerminate: false, // android only,
startOnBoot: true, // android only
});
}
async function unregisterBackgroundFetchAsync() {
return BackgroundFetch.unregisterTaskAsync(BACKGROUND_FETCH_TASK);
}
React.useEffect(() => {
dispatch(getTodaysEvents());
const askPermission = async () => {
let getForeground = await Location.getForegroundPermissionsAsync();
if (getForeground.status !== "granted") {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
Alert.alert("Permission to access location was denied");
return;
} else {
let backgroundPermissions =
await Location.requestBackgroundPermissionsAsync();
if (backgroundPermissions.status == "granted") {
await AsyncStorage.setItem("background_permission", "true");
}
}
}
};
askPermission();
}, []);
const checkIn = async (index) => {
let temp = [...todayEvents];
temp[index].isCheckedIn = true;
setVenueId(temp[index].venueId);
const backgroundStatus = await AsyncStorage.getItem(
"background_permission"
);
// if (backgroundStatus !== null) {
Location.startLocationUpdatesAsync("updateLocation", {
timeInterval: 120,
distanceInterval: 0.01,
foregroundService: {
notificationTitle: "Company title",
notificationBody:
"Information in body",
},
accuracy: Location.Accuracy.Highest,
}).then((response) => {
// console.log("RESPONSE LOCATION", response);
});
// }
setTimeout(() => {
const stopped = Location.stopLocationUpdatesAsync("updateLocation");
}, 43200000);
let { coords } = await Location.getCurrentPositionAsync();
dispatch(userCheckIn({ lat: coords.latitude, long: coords.longitude }));
};
const checkOut = async (index) => {
const stopped = Location.stopLocationUpdatesAsync("updateLocation");
let temp = todayEvents;
temp[index].isCheckedIn = false;
//dispatch(userCheckOut()); // This is what I commented out
// And the two rows below is added
let { coords } = await Location.getCurrentPositionAsync();
dispatch(userCheckOut({ lat: coords.latitude, long: coords.longitude }));
};
const review = (index, value) => {
setModalVisible(true);
setTimeout(() => {
setModalVisible(false);
setTimeout(() => {
props.navigation.goBack();
}, 300);
}, 1500);
let temp = todayEvents;
temp[index].review = value;
dispatch(giveEventFeedBack(temp[index]));
};
From the app.json following iOS Location permissions are defined:
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
And for Android:
ACCESS_BACKGROUND_LOCATION
ACCESS_COARSE_LOCATION
ACCESS_FINE_LOCATION
There's a scenario when the user recently choose the NEVER ASK AGAIN option for that permission. The next time the app attempt to ask it, the request resolves in denied status silently without launching the request permission popup modal.
If this is the case, the app can force the user to grant permission manually in app settings
You can handle this situation like this
const permission = await Location.getForegroundPermissionsAsync();
// Detect if you can request this permission again
if (!permission.canAskAgain || permission.status === "denied") {
/**
* Code to open device setting then the user can manually grant the app
* that permission
*/
Linking.openSettings();
} else {
if (permission.status === "granted") {
// Your actually code require this permission
}
}
While the solution above doesn't work, Review this ongoing issue in Expo SDK 44 - https://github.com/expo/expo/issues/15273

Cannot retrieve ExpoPushToken on IOS

ExpoSDK Version - 42
Bare workflow
EAS version - 0.39.0
I have an react-native expo app build with eas build --profile preview --platform all, and on IOS i cannot seem to retrieve the ExpoPushToken. On Android it works just fine. I tried to fix the issue by removing the APN push key, the Provisioning Profile and the Distribution Certificate, and creating them again from the EAS prompts, but the problem persists.
The code I’m using for retrieving the Push token is the one from the Expo Documentation.
async function registerForPushNotificationsAsync() {
let token;
if (Constants.isDevice) {
const { status: existingStatus } =
await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== "granted") {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== "granted") {
alert("Failed to get push token for push notification!");
return;
}
token = await Notifications.getExpoPushTokenAsync();
} else {
alert("Must use physical device for Push Notifications");
return;
}
if (Platform.OS === "android") {
Notifications.setNotificationChannelAsync("default", {
name: "default",
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
});
}
return token;
}
I’m calling this function inside a useEffect, and sending the token to the server, to store it in the users data, but on IOS the token returned is undefined.

Why EXPO standalone app shows url_invalid?

i am working with Expo project using stripe react native , its work fine in local, publish but not working as expected in standalone app,
here i use stripe for payment and when i enter card info its returns erorr 400
400 Error
POST /v1/payment_intents/pi_3JSeHwSJwGztdZyL1BuqSJQq/confirm
"return_url": "myappname:///--/://safepay",
url_invalid - return_url Not a valid URL
here is my code :
<StripeProvider
publishableKey="xyz"
urlScheme={Linking.createURL('') + '/--/'}
setUrlSchemeOnAndroid = {true}
.............................../>
const handleDeepLink = useCallback(
async (url: string | null) => {
if (url && url.includes('safepay')) {
await handleURLCallback(url);
console.log('url',url)
navigation.navigate('Checkout', { url });
}
},
[navigation, handleURLCallback]
);
useEffect(() => {
const getUrlAsync = async () => {
const initialUrl = await Linking.getInitialURL();
handleDeepLink(initialUrl);
console.log('initialUrl',initialUrl)
};
const urlCallback = (event: { url: string }) => {
handleDeepLink(event.url);
};
getUrlAsync();
Linking.addEventListener('url', urlCallback);
return () => Linking.removeEventListener('url', urlCallback);
}, [handleDeepLink]);
how to achive deep link and how to resole this ?
Using: Standalone app, Expo 42, stripe-react-native :0.1.4

Notifications are not showing while the app is in foreground

I am trying to send push notifications using react-native-firebase through firebase console when my app is closed or in the background, the notifications are received and shown as a pop-up but if my app is in the foreground the notifications are not appearing
I have been trying to do some code in on notification method as suggested in the docs but it's not working
please suggest something that my app can show notifications in foreground
Please refer following link.
https://rnfirebase.io/docs/v5.x.x/messaging/android#(Optional)-Background-Messages
If you added, remove following line from your AndroidManifest.xml.
<service android:name="io.invertase.firebase.messaging.RNFirebaseBackgroundMessagingService" />
create a new notifactionHandler.js and import the code below.
import firebase from 'react-native-firebase';
exports.setNotificationListener = () => {
return new Promise((resolve, reject) => {
// triggers when notifiaction received while app on foreground
this.notificationListener = firebase.notifications().onNotification((notification) => {
console.log(notification.data);
setNotification({notification})
});
resolve(true);
})
};
const setNotification = ({notification}) => {
firebase.notifications().displayNotification(notification);
}
then import it on your splash or main page.
then call setNotificationListener function. basicly firebase.notifications().onNotification catches notifications while app on foreground, and displays it with firebase.notifications().displayNotification
in my case:
import firebase from 'firebase';
import * as Notice from "react-native-firebase";
componentDidMount() {
const firebaseConfig = {
apiKey: "**********",
authDomain: "**********",
databaseURL: "**********",
projectId: "**********",
storageBucket: "**********",
messagingSenderId: "**********",
appId: "**********"
};
this.mNotifiConfig()
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
}
mNotifiConfig = async() => {
Notice.messaging().hasPermission()
.then(enabled => {
console.log('HAS PERMISS: ', enabled)
if (enabled) {
Notice.messaging().getToken().then(token => {
console.log("LOG: ", token);
}).catch(err=> console.log(err))
} else {
Notice.messaging().requestPermission()
}
});
const notificationOpen = await Notice
.notifications()
.getInitialNotification();
if (notificationOpen) {
const action = notificationOpen.action;
const notification = notificationOpen.notification;
var seen = [];
// this.onActionWithNotification(notification)
console.log('NOTIFICATION IS OPNE')
}
// config android
const channel = new Notice.notifications.Android.Channel(
"test-channel",
"Test Channel",
Notice.notifications.Android.Importance.Max
).setDescription("My apps test channel");
// Create the channel
Notice.notifications().android.createChannel(channel);
this.notificationDisplayedListener = Notice
.notifications()
.onNotificationDisplayed((notification: Notification) => {
console.log('CREATED CHANNEL')
// Process your notification as required
// ANDROID: Remote notifications do not contain the channel ID. You will have to specify this manually if you'd like to re-display the notification.
});
this.notificationListener = Notice
.notifications()
.onNotification((notification: Notification) => {
console.log('HAS Notification: ', notification)
// Process your notification as required
// notification.android
// .setChannelId("test-channel")
// .android.setSmallIcon("ic_launcher");
// firebase.notifications().displayNotification(notification).catch(err => console.error(err));
let notification_to_be_displayed = new Notice.notifications.Notification({
data: notification.data,
sound: 'default',
show_in_foreground: true,
title: notification.title,
body: notification.body,
});
if(Platform.OS == "android") {
notification_to_be_displayed
.android.setPriority(Notice.notifications.Android.Priority.High)
.android.setChannelId("test-channel")
.android.setSmallIcon("ic_launcher")
.android.setVibrate(1000);
}
Notice.notifications().displayNotification(notification_to_be_displayed);
});
this.notificationOpenedListener = Notice
.notifications()
.onNotificationOpened((notificationOpen) => {
// Get the action triggered by the notification being opened
const action = notificationOpen.action;
// Get information about the notification that was opened
const notification = notificationOpen.notification;
var seen = [];
console.log('notification Day nay', notification)
Notice
.notifications()
.removeDeliveredNotification(notification.notificationId);
// this.onLinkingtoApp()
});
this.onMessageListener = Notice.messaging().onMessage((message: RemoteMessage) => {
const {data} = message
const showNotif = new Notice.notifications.Notification()
.setNotificationId('notificationId')
.setTitle(data.title || 'Thông báo')
.setBody(data.content || 'Bạn có một thông báo mới')
.setData(data)
.android.setChannelId('test-channel')
.android.setSmallIcon('ic_launcher')
Notice.notifications().displayNotification(showNotif)
})
}

react-native-linkdin-login is not working in ios?

I am using react-native-linkdin-login library to support linkding sigin in my application.It is working properly in android but in iOS it always ask to download an application rather than application already exist in device and redirect to the APP store. When I open and login to linkdin account, I can't come back to my react-native application, with user profile details.
Give me any suggestion as soon as possible.
async componentWillMount() {
LinkedinLogin.init(
[
'r_emailaddress',
'r_basicprofile'
]
);
}
async handleLinkedinLogin(){
LinkedinLogin.login().then((user) => {
alert("linkdin");
this.setState({ user : user });
this.getUserProfile();
}).catch((e) => {
var err = JSON.parse(e.description);
alert("ERROR: " + err.errorMessage);
alert('Error', e);
});
return true;
}
getUserProfile(user) {
LinkedinLogin.getProfile().then((data) => {
const userdata = Object.assign({}, this.state.user, data);
this.setState({ user: userdata });
const Email = userdata.emailAddress;
const Fullname = userdata.firstName+' '+userdata.lastName;
const SocialAppId = userdata.id;
const SignupType = 'Linkedin';
alert("Please wait....")
this.socialLogin(Fullname,Email,'null',SignupType);
}).catch((e) => {
alert(e);
});
}