Test OneSignal Push Notification on iOS Simulator - ios

I've set up react-native-onesignal on my project to implement Push Notification using OneSignal.
It is possible to test Push Notification on iOS simulators since Xcode 11.4 Beta. I created JSON formatted apns file to test Push Notification on Simulator and it worked very well.
But how can I emulate OneSignal Push Notification?
I followed OneSignal Documentation and want to receive Push Notification which is sent from OneSignal Dashboard.
Here's what I've implemented on my App.tsx file.
const initializeOneSignal = () => {
OneSignal.setLogLevel(6, 0);
OneSignal.init("MY_ONESIGNAL_APP_ID", {
kOSSettingsKeyAutoPrompt: false,
kOSSettingsKeyInAppLaunchURL: false,
kOSSettingsKeyInFocusDisplayOption: 2,
});
OneSignal.inFocusDisplaying(2);
OneSignal.promptForPushNotificationsWithUserResponse(myiOSPromptCallback);
OneSignal.addEventListener('received', onPNReceived);
OneSignal.addEventListener('opened', onPNOpened);
OneSignal.addEventListener('ids', onPNIds);
};
useEffect(() => {
initializeOneSignal();
return () => {
OneSignal.removeEventListener('received', onPNReceived);
OneSignal.removeEventListener('opened', onPNOpened);
OneSignal.removeEventListener('ids', onPNIds);
};
}, []);
const onPNReceived = notification => {
console.log('Notification received: ', notification);
};
const onPNOpened = openResult => {
console.log('Message: ', openResult.notification.payload.body);
console.log('Data: ', openResult.notification.payload.additionalData);
console.log('isActive: ', openResult.notification.isAppInFocus);
console.log('openResult: ', openResult);
};
const onPNIds = device => {
console.log('Device info: ', device);
};
const myiOSPromptCallback = permissions => {
console.log('Permissions: ', permissions);
};
I cannot see any logged message when I sent Push Notification from my OneSignal Dashboard.
Do I need to do any trick in apns file?
Any help would be appreciated.

tl;dr you can't send a real notification to a simulator. You can only send mocked notifications to a simulator
Your server is oblivious of a simulator, because simulators don't have device tokens. Apple decided not to give it one. I suppose this was so users can't fake their device token and get notifications on their simulator...
The 11.4 simply allows the drag and drop of a APNs payload into the simulator without any mention of device token.

You can check out this article on Medium enter link description here.
This article helped me test oneSignal push notifications on my iOS simulator and figure out the deep linking issue.
Here are my steps:
Create a payload.apns file on your desktop
Put the following code inside it:
{
"Simulator Target Bundle": "com.example.app",
"aps": {
"alert": {
"title": "Push Notification",
"subtitle": "Test Push Notifications",
"body": "Testing Push Notifications on iOS Simulator",
}
},
"custom": {
"i": "notificationId as UUID",
"a": {"deeplinkKey": "{\"deeplinkDetailKey\":\"deeplinkDetailValue\"}", "launchURL": "example://collection/myCollectionId/type/1"}
}
}
Remember to replace com.example.app with your app bundle ID.
Run your app on the simulator, then close the app and keep metro open
Drag and drop payload.apns file on the simulator, you will see the notification to click on it. If you have done the 3rd step right, you should be redirected to your app
(Optional) If you need to test a deep link with the push notification, I haven't yet found the key oneSignal uses, but as you see in the .apns file above, I added a launchURL to the a which represents additionalData and handled catching and opening it manually in the app to test what's wrong with the deep link.
(Optional) To open a deep link in your app, you can use Linking API from react-native:
import {Linking} from 'react-native'
Linking.openURL("Path/to/launchURL")

Related

Add deep link when creating Firebase message

I'm using the firebase Message class to create push notifications for a react native app. I want the notification to take users to a specific screen of the app. Right now tapping on the push notification just takes users to the last screen they were on before they back-grounded the app. I'm testing this on my iOS device. How can I embed a specific deep link in the message? Would I use setApnsConfig(ApnsConfig apnsConfig) or setFcmOptions(FcmOptions fcmOptions)?
I would use the APNS config since this is for an iOS app:
https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/messaging/ApnsConfig.Builder
You could approach it different ways, but you could either include a URL in the header field, and use it for custom deep link logic, or you can have custom data in the putCustomData(String key, Object value) and then have your app process that info to deep link into the correct part of your app.
Your app would process this notification in the application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application
I had integrated this feature in an app I made in react native aswell. Look at my solution below.
As you can see in the app I am waiting for a notification to come on and I check if it has a type available. My notifications are always routed to another page. In my case its the same page but I set a route as datatype in my payload.
After that you can use that route payload with your naviogator library in my case react-navigation to navigate to the correct screen.
You should chose which trigger works best for you ether onNotificationOpenedApp or getInitialNotification.
useEffect(() => {
// Assume a message-notification contains a "type" property in the data payload of the screen to open
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log(
"Notification caused app to open from background state:",
remoteMessage
);
//navigation.navigate(remoteMessage.data.type);
});
// Check whether an initial notification is available
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
console.log(
"Notification caused app to open from quit state:",
remoteMessage
);
const route = remoteMessage?.data?.route;
navigation.navigate(route, {
data: remoteMessage.data,
});
}
})
.catch((error) => console.log("Caught ", error));
}, []);

Firebase Cloud Messaging to Android works but iOS fails. How to structure payload for iOS?

I can send test notifications from Firebase console to my app both on iOS and Android. Therefore, my app is set up properly to receive push notifications on both platforms. However, when I use a cloud function to send notifications. Only, notifications on the Android device are received. No notifications show up on the iOS device. I suspect this may be related to the way that I create the payload in my cloud function. Maybe I am missing something for iOS. If you could give me some tips, that would be great.
I checked if the deviceToken for the iOS device is correct and it was correct.
I sent a test message using firebase console to the same deviceToken for the iOS device and the notification was delivered.
Therefore, I concluded my problem may arise from the cloud function I wrote. Thus, I share below the cloud function:
exports.notifToApp = functions.database.
ref(`/memInfo/{memId}/notifChoice/`).onWrite((snap, context) => {
//send only if exists and new notification OR if doesn't exist
if ((snap.before.exists() && (snap.after.val() !== snap.before.val())) || !snap.before.exists()) {
//get notification body
const notificationTitle = snap.after.val().memName;
const notificationText = snap.after.val().notifText;
//get and loop over notification subscribers
return admin.database().ref(`/notifics/${context.params.memId}/notifSubs/`).once("value", subs => {
if (subs.exists()) {
return subs.forEach(sub => {
//payload for notification
const payload = {
"notification":{
"title": notificationTitle,
"body": notificationText,
"sound": "default",
"click-action": "FCM_PLUGIN_ACTIVITY",
"priority": "high"
}
}
//deliver notification
return admin.messaging().sendToDevice(sub.val().deviceToken, payload).catch(e => {console.log(e);});
});
} else { //end: if returned any value
return 0;
}
});// end: get and loop over notification subscribers
} else { //end: send only if exists and new notification OR if doesn't exist
return 0;
}
});
I do not get any error messages. Function completes successfully with status "OK."
I test using two devices: one android and one iOS. Both device tokens are saved correctly in the database for the cloud function to retrieve and use for sending messages.
I see the notification on the Android device running my app. I wish the notification to show up on the iOS device running the same app.
Test message notification sent from the firebase console shows up on both devices correctly.
I realized that sendToDevice() used the legacy version of payload. I used send() in my function to use the newer version. (see answer: stackoverflow)
admin.messaging().send(payload).catch(e => console.log(e));
I changed the payload to include platform specific fields according to the latest guidelines (see firebase docs)
const payload = {
"token": sub.val().deviceToken,
"notification":{"title": notificationTitle,"body": notificationText},
"android": {"notification": {"sound": "default"}},
"apns": {"payload": {"aps": {"sound": "default"}}}
};
Now it works on both platforms.

How can I set notification sound when app is not running in React-Native firebase

I'm trying to make notification ringing when app is not running in IOS.
Here is my code.
this.notificationListener = firebase.notifications().onNotification((notification: Notification) => {
// SET SYSTEM DEFAULT SOUND!
notification.setSound("default");
firebase.notifications().displayNotification(notification);
});
When app is in background or foreground ( Maybe I can say 'app is running'), notification rings well.
Should I need to use other listener?
Or should I need to add my own sound file for ringing?
Finally, I know how to do this.
This issue was not related to react-native-firebase, it was related to my server.
When server post message to app, server can set several options like sound, badge.
https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1
If you set sound section to 'default', you can get default notification sound when notification is coming even if your app is on background.
I hope my answer can help react-native-firebase beginners like me.
Anyone Has issue with RNFIREBASE & REACT NATIVE, Try to send your notification via Firebase ADMIN SDK. That will work for Sure
//Notification Payload
const payload = {
notification: {
title: update.title,
body: update.body,
icon: "default",
badge: '1',
sound: 'default' // notification sound
},
};
//sending notification via Firebase Admin SDK
admin.messaging().sendToDevice('TOKEN_OR_TOKENS', payload)
.then( () => { return true; }).catch(function() {
console.log('error sendToDevice() ')
return null;
});

TopicDisallowed Push Notification

I have a small issue. I am trying to test my push notification feature but I can't figure it out. I set up a webRTC page that I'm using to send the notification (I don't own 2 IOS devices). All the certificates/keys were generated using fastlane actions (match and pem). I am aware I'm using a production feature for the apnOptions and I generated the correct certificates. When I write some gibberish on the key or teamID, I get errors so that means my certificate should be alright. The bundle identifier is exactly the one that appears on the developer Apple page.enter code here
Here are my token and my notification:
var apnProvider = new apn.Provider({
token: {
key: "cert/key.p8",
keyId: "#",
teamId: "#"
},
production: true
});
if (deviceToken) {
if (platform === 'ios') {
let note = new apn.Notification()
note.alert = 'Hello World'
note = Object.assign(note, {
// Expires 1 hour from now.
expiry: Math.floor(Date.now() / 1000) + 3600,
badge: 3,
payload: payloadBody,
topic: "org.#.#"
})
apnProvider.send(note, deviceToken).then((result) => {
console.log('APNPROVIDER RESULT', `PLATFORM: ${platform}, RESULT:${JSON.stringify(result)}`)
})
Thank you very much for your help!
I found out in the end. It turned out that if I use a voip bundle I need to add at the end of the bundle .voip. So, a bundle would look something like org.test.Test.voip. I'm done..
In my case, the problem was, Server was taking push kit device token i.e. voIP token, and the bundle id was "com.something".
Solution: For voIP type of notifications user, "com.something.voip" topic/bundle id.
IOS follows proper format for push notification. If you do not follow proper format your notifications won't be delivered. There should be a aps tag also.
{
"aps": {
"alert": "Hello World",
"sound": "default"
},
"customData": {
"CustomKey": "CustomValue",
}
}
You can follow this link for reference
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification
Double check the Topic Name, I've encountered this problem with a typo in the Topic Name.

Titanium Appcelerator ACS - (iPhone) Not able to receive Push Notifications which are sent successfully

For my titanium mobile application, I would like to integrate ACS Push Notifications. As a first step, I went through the Push Notifications doc. I've configured my settings for iOS as given in the doc. I've created two ACS users (lets say A & B) and subscribed them to my custom channel using the following code.
Cloud.PushNotifications.subscribe({
channel: '4fa8c8bfb6855370430092d1',
device_token: '0BCE1064500FBF6F122BB0000007D1B5F96BAC345FD0A950FD456098D36E0345'
}, function (e) {
if (e.success) {
alert('Success');
} else {
alert('Error:\n' +
((e.error && e.message) || JSON.stringify(e)));
}
});
Now, under my ACS Push Notification settings, am able to see that i currently have 2 iOS clients subscribed to Push Notifications.
With the below piece of code, i've sent a broadcast message from Device A in which the ACS_UserA has logged in.
Cloud.PushNotifications.notify({
channel: '4fa8c8bfb6855370430092d1',
payload: 'Welcome to push notifications'
}, function (e) {
if (e.success) {
alert('Success');
} else {
alert('Error:\n' +
((e.error && e.message) || JSON.stringify(e)));
}
});
I am getting the alert as 'Success'. But, am not able to receive the notification in another Device B in which the ACS_UserB has logged in.
According the documentation here, i should be receiving a Push message in the 'callback' callback. But it is never called.
Ti.Network.registerForPushNotifications({
types: [
Ti.Network.NOTIFICATION_TYPE_BADGE,
Ti.Network.NOTIFICATION_TYPE_ALERT,
Ti.Network.NOTIFICATION_TYPE_SOUND
],
success:function(e) {
Ti.API.info('Device Token : '+e.deviceToken);
},
error:function(e) {
Ti.API.warn("push notifications failed: "+e);
},
callback:function(e) {
alert ('Push received');
}
});
Titanium SDK version: 2.0.2 (04/18/12 12:18 0684d32)
Titanium Studio, build: 2.0.1.201204132053
iPhone Device family: iphone
iPhone SDK version: 5.0
iPhone simulated device: iphone.
Need to crack this badly. Any help will be appreciated.
is your application id: com.companyname.applicationname? make sure you do not use com.companyname.* instead!

Resources