We migrated from UA to One Signal. We are sending push from cloud code like
var pushInfo = {
"app_id" : "xxxxxx",
"data": {
"objectId": objectId,
"placeId": placeId,
},
"included_segments": ["All Users"],
"contents": {"en": message}
};
var headers = {
"Content-Type": "application/json; charset=utf-8",
"Authorization": "Basic XXXXX"
};
var options = {
host: "onesignal.com",
port: 443,
path: "/api/v1/notifications",
method: "POST",
headers: headers,
};
var https = require('https');
var req = https.request(options, function(res) {
res.on('data', function(data) {
console.log("Response:");
console.log(JSON.parse(data));
});
});
req.on('error', function(e) {
console.log("ERROR:");
console.log(e);
});
req.write(JSON.stringify(pushInfo));
req.end();
In my AppDelegate.m I do
[OneSignal initWithLaunchOptions:launchOptions appId:#"XXXXX"];
Now earlier when a notification is received and user Taps on it, it used to call
-(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
Q. This is not getting called now. How do I handle it with OneSignal.
Q. What I need to do to handle a silent notification (no visible badge/banner etc)
I Assume you are testing/running your app on an iOS10 device,
I looked at OneSignal SDK Code and I think the SDK automatically uses the new UserNotifications Framework (add in iOS10), when iOS10 is detected on device.
In this case, the AppDelegate method you mentioned above does not get invoked, instead methods in UNUserNotificationCenterDelegate get invoked, which are captured by SDK to record clicks/views.
To Fix the issue, Create a new class which implements OSUserNotificationCenterDelegate and provide its instance to OneSignal using [OneSignal setNotificationCenterDelegate:yourCustomNotificationCenterDelegateInstance]
Please note that application:didReceiveRemoteNotification:fetchCompletionHandler: is still called when a silent push notification (content-available: 1) arrives, but its not called when user taps the notification if UNUserNotificationCenterDelegate is used.
Also, there was an issue on iOS 10.0.X where the application:didReceiveRemoteNotification was called instead of application:didReceiveRemoteNotification:fetchCompletionHandler: See: https://forums.developer.apple.com/thread/54332 , but I doubt if this is the case with you.
One Signal Notification Integration
Use Following Block Of Code TO Handle PushNotification Message Content
Put below code in AppDelegate's ApplicationDidFinishLaunch Options method
let notificationReceivedBlock: OSHandleNotificationReceivedBlock = { notification in
print("Received Notification: \(notification!.payload.notificationID)")
}
let notificationOpenedBlock: OSHandleNotificationActionBlock = { result in
// This block gets called when the user reacts to a notification received
let payload: OSNotificationPayload = result!.notification.payload
var fullMessage = payload.body
print("Message = \(String(describing: fullMessage))")
if payload.additionalData != nil {
if payload.title != nil {
let messageTitle = payload.title
print("payload.category \(payload.category)")
print("payload.subtitle \(payload.subtitle)")
print("Message Title = \(messageTitle!)")
}
let additionalData = payload.additionalData
if additionalData?["actionSelected"] != nil {
fullMessage = fullMessage! + "\nPressed ButtonID: \(String(describing: additionalData!["actionSelected"]))"
}
}
}
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: false,
kOSSettingsKeyInAppLaunchURL: true]
OneSignal.initWithLaunchOptions(launchOptions,
appId: "Your App Id",
handleNotificationReceived: notificationReceivedBlock,
handleNotificationAction: notificationOpenedBlock,
settings: onesignalInitSettings)
**Use following block of code To Receive OneSingnal Notification Content**
OneSignal.inFocusDisplayType = OSNotificationDisplayType.notification;
// Recommend moving the below line to prompt for push after informing the user about
// how your app will use them.
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
application:didReceiveRemoteNotification:fetchCompletionHandler: is the correct selector for background silent content-available notifications. Make sure you are using the latest 2.2.2 OneSignal SDK as there were some fixes to maintain compatibility with the older AppDelegate selectors.
You may want to look into using UNNotificationServiceExtension with mutable-content for iOS 10 devices as this still works when the app has been swiped away.
In my case all I had to do is remove the Firebase handlers in app delegate. OneSignal can hijack the events from FCM. This way I had both the OneSingal Push notification and the ones delivered by Firebase. As for One signal I used a simple copy and paste from their examples.
THIS ARE THE PARTS THAT I REMOVED FROM MY AppDelegate.m
REMOVE IMPORTS -> #import "RNFirebaseMessaging.h"
REMOVE IMPORTS -> #import "RNFirebaseNotifications.h"
IN: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
REMOVE ->[RNFirebaseNotifications configure];
REMOVE HANDLERS:
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification {
[[RNFirebaseNotifications instance]
didReceiveLocalNotification:notification];
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
fetchCompletionHandler:(nonnull void (^).
(UIBackgroundFetchResult))completionHandler{
[[RNFirebaseNotifications instance]
didReceiveRemoteNotification:userInfo
fetchCompletionHandler:completionHandler];
[UIApplication sharedApplication].applicationIconBadgeNumber += 1;
}
- (void)application:(UIApplication *)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings
*)notificationSettings {
[[RNFirebaseMessaging instance]
didRegisterUserNotificationSettings:notificationSettings];
}
import { Platform } from 'react-native'
import OneSignal, { NotificationReceivedEvent, OpenedEvent } from 'react-native-onesignal'
import Config from '../../Config/Config'
import State from '../../State/State'
interface WithSuccess {
success: boolean
}
interface ExternalUserIdResultI {
push: WithSuccess
email: WithSuccess
sms: WithSuccess
}
class Messaging {
public Init = () => {
//OneSignal Init Code
OneSignal.setLogLevel(Config.messaging.debugLevel, 0)
OneSignal.setAppId(Platform.OS === 'ios' ? Config.messaging.iosAppId : Config.messaging.androidAppId)
//END OneSignal Init Code
//Prompt for push on iOS
OneSignal.promptForPushNotificationsWithUserResponse((response: boolean) => {
console.log("Prompt response:", response);
})
//Method for handling notifications received while app in foreground
OneSignal.setNotificationWillShowInForegroundHandler((notificationReceivedEvent: NotificationReceivedEvent) => {
console.log("OneSignal: notification will show in foreground:", notificationReceivedEvent);
let notification = notificationReceivedEvent.getNotification();
console.log("notification: ", notification);
notificationReceivedEvent.complete(notification)
})
//Method for handling notifications opened
OneSignal.setNotificationOpenedHandler((notification: OpenedEvent) => {
console.log("OneSignal: notification opened:", notification);
})
OneSignal.addSubscriptionObserver(event => {
console.log("OneSignal: subscription changed:", event);
})
}
public SendTag = (key: string, value: string) => {
OneSignal.sendTag(key, value)
}
public SetExternalUserId = (externalUserId: string) => {
//#ts-ignore
OneSignal.setExternalUserId(externalUserId, (results: ExternalUserIdResultI) => {
// The results will contain push and email success statuses
console.log('Results of setting external user id');
console.log(results);
// Push can be expected in almost every situation with a success status, but
// as a pre-caution its good to verify it exists
if (results.push && results.push.success) {
console.log('Results of setting external user id push status:');
console.log(results.push.success);
}
// Verify the email is set or check that the results have an email success status
if (results.email && results.email.success) {
console.log('Results of setting external user id email status:');
console.log(results.email.success);
}
// Verify the number is set or check that the results have an sms success status
if (results.sms && results.sms.success) {
console.log('Results of setting external user id sms status:');
console.log(results.sms.success);
}
});
}
public RemoveExternalUserId = () => {
//#ts-ignore
OneSignal.removeExternalUserId((results: ExternalUserIdResultI) => {
// The results will contain push and email success statuses
console.log('Results of removing external user id');
console.log(results);
// Push can be expected in almost every situation with a success status, but
// as a pre-caution its good to verify it exists
if (results.push && results.push.success) {
console.log('Results of removing external user id push status:');
console.log(results.push.success);
}
// Verify the email is set or check that the results have an email success status
if (results.email && results.email.success) {
console.log('Results of removoing external user id email status:');
console.log(results.email.success);
}
});
}
}
export default new Messaging()
Related
Hello I need some suggestions what may be the reason why my notifications are sent but I never receive them on my phone, also its debugged on physical device -> iPhone X (14.3).
I have followed this article https://github.com/xamarin/GoogleApisForiOSComponents/blob/main/docs/Firebase/CloudMessaging/GettingStarted.md for implementing firebase notifications on IOS.
I added APNs Authentication Key to firebase that i downloaded from my developer acc.
I added in my info.plist
property FirebaseMessagingAutoInitEnabled -> No
selected Enable Background Modes and selected Remote Notifications
In GoogleService-Info.plist Build Action -> Bundle Resource
I have double checked my bundle_id, my project and in GoogleService-Info are the same.
In Entitlements.plist selected Remote Notifications
Here is my AppDelegate.cs
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUNUserNotificationCenterDelegate, IMessagingDelegate
{
private App app;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Rg.Plugins.Popup.Popup.Init();
global::Xamarin.Forms.Forms.Init();
DependencyService.Register<ILocalStorageManager, LocalStorageManager>();
DependencyService.Register<ILauncherService, LauncherService>();
LoadApplication(new App());
Firebase.Core.App.Configure();
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => {
Console.WriteLine(granted);
});
}
else
{
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes(allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings(settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications();
Messaging.SharedInstance.Delegate = this;
var token = Messaging.SharedInstance.FcmToken ?? "";
Console.WriteLine($"FCM token: {token}");
return base.FinishedLaunching(app, options);
}
[Export("messaging:didReceiveRegistrationToken:")]
public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
{
Console.WriteLine($"Firebase registration token: {fcmToken}");
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine(userInfo);
}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine(userInfo);
completionHandler(UIBackgroundFetchResult.NewData);
}
// Receive displayed notifications for iOS 10 devices.
// Handle incoming notification messages while app is in the foreground.
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
var userInfo = notification.Request.Content.UserInfo;
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
// Print full message.
Console.WriteLine(userInfo);
// Change this to your preferred presentation option
completionHandler(UNNotificationPresentationOptions.None);
}
// Handle notification messages after display notification is tapped by the user.
[Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
var userInfo = response.Notification.Request.Content.UserInfo;
// Print full message.
Console.WriteLine(userInfo);
completionHandler();
}
}}
In Console it generates my FCM token and when I try to send notification from Firebase Console nothing is printed in the console but it says its completed. Then I tried to sent it from postman and I received the next message.
{
"multicast_id": 5300302940762876386,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1627386458132596%db948e52db948e52"
}
]}
My nugget packages IOS.CloudMessaging, IOS.Core, iOS.Installations and iOS.IstanceID are up todate.
I found my problem.
I overrided FailedToRegisterForRemoteNotifications and saw that it throwed
"no valid “aps-environment” entitlement string found for application"
and I checked that my bundle identifier in info.plist was ok, but in my xCode project was wrong and that solved my problem.
I am trying to integrate OneSignal into my app.
What I want is when user tap a notification to present desired ViewController modally. I implemented opening VC logic in handleNotificationAction while init of OneSignal.
The problem is that OneSignal still opens its WebView, and I don't want it to. Is there any way to disable opening WebView when user taps notification?
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: false]
OneSignal.initWithLaunchOptions(launchOptions,
appId: "myAppID",
handleNotificationAction: { result in
guard let payload = result?.notification.payload else { return }
guard let additionalData = payload.additionalData else { return }
guard let venueID = additionalData["internal"] as? String else { return }
DispatchQueue.main.async {
self.showVenueDetails(venueID)
}
},
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = .notification
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
Yes, add kOSSettingsKeyInAppLaunchURL: false to your onesignalInitSettings. This will open URL in default browser instead of UIWebView.
If you want to display your custom view then don't use the URL parameter in the payload. Instead, use custom key-value pair in additional data.
For OneSignal SDK 3.x.x
As suggested by OneSignal, add the following key to the project's info.plist:
OneSignal_suppress_launch_urls = true
For OneSignal SDK version 2.x.x
add kOSSettingsKeyInAppLaunchURL: false to OneSignal's initSetting
Search for initOneSignal in project. There in setting parameneter pass
kOSSettingsKeyInAppLaunchURL: #false
- (void)initOneSignal {
[OneSignal setValue:#"react" forKey:#"mSDKType"];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didBeginObserving) name:#"didSetBridge" object:nil];
[OneSignal initWithLaunchOptions:nil appId:nil handleNotificationReceived:^(OSNotification* notification) {
[self handleRemoteNotificationReceived:[notification stringify]];
} handleNotificationAction:^(OSNotificationOpenedResult *result) {
if (!RCTOneSignal.sharedInstance.didStartObserving)
coldStartOSNotificationOpenedResult = result;
else
[self handleRemoteNotificationOpened:[result stringify]];
} settings:#{#"kOSSettingsKeyInOmitNoAppIdLogging" : #true, kOSSettingsKeyAutoPrompt : #false, kOSSettingsKeyInAppLaunchURL: #false}]; //default autoPrompt to false since init will be called again
didInitialize = false;
}
I wonder, is there another way to get the push device token without the delegate method:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(nonnull NSData *)deviceToken
because I used OneSignal, and they don't need to conform that method to get the device token.
You can get the push token for OneSignal SDK like this:
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
if let deviceState = OneSignal.getDeviceState() {
let userId = deviceState.userId
let pushToken = deviceState.pushToken
let subscribed = deviceState.isSubscribed
print("pushToken ====> \(pushToken)") //Here you can get the token
}
})
Keep coding........... :)
OneSignal API states IdsAvailable is the method you would use:
[OneSignal IdsAvailable:^(NSString* userId, NSString* pushToken) {
NSLog(#"UserId:%#", userId);
if (pushToken != nil)
NSLog(#"pushToken:%#", pushToken);
}];
Is the method to get the token; mentioned here.
I want to send tag to a specific user after he/she logged in so he/she can receive notifications. Only logged in users will receive notifications.
When he/she logs out, I will delete his/her tag.
How can I do this?
My code in AppDelegate:
let oneSignal: OneSignal = OneSignal(launchOptions: launchOptions, appId: "<my-app-id>") {
(message, additionalData, isActive) in
if (additionalData != nil) {
NSLog("APP LOG ADDITIONALDATA: %#", additionalData);
let displayMessage: NSString = NSString(format:"NotificationMessage:%#", message);
var messageTitle: NSString = "";
if (additionalData["discount"] != nil) {
messageTitle = additionalData["discount"] as String
}
else if (additionalData["bonusCredits"] != nil) {
messageTitle = additionalData["bonusCredits"] as String;
}
else if (additionalData["actionSelected"] != nil) {
messageTitle = NSString(format:"Pressed ButtonId:%#", additionalData["actionSelected"] as String);
}
var alertView: UIAlertView = UIAlertView(title: messageTitle,
message:displayMessage,
delegate:self,
cancelButtonTitle:"Close");
alertView.show();
}
else if (isActive) {
var alertView: UIAlertView = UIAlertView(title:"OneSignal Message",
message:message,
delegate:self,
cancelButtonTitle:"Close");
alertView.show();
}
}
My code in my LogInViewController:
let oneSignal = OneSignal()
oneSignal.sendTag("username", value: self.usernameTextField.text)
The code in my appDelegate is working fine, my users already receive notifications. But they can receive notifications even if they're not logged in.
You need to use the same oneSignal instance from AppDelegate in your LogInViewController. You can make oneSignal static at the class level so it can be shared between both classes.
To delete a tag you can call oneSignal.deleteTag("username")
Update:
As of the iOS 2.0 SDK all methods on the OneSignal class are now static.
Objective-C:
// Send tag: After login
[OneSignal sendTag:#"key" value:#"value"];
// Delete tag: After logout
[OneSignal deleteTag:#"key"];
Swift:
// Send tag: After login
OneSignal.sendTag("key", value: "value") // for sending that is inserting tag in OneSignal
// Delete tag: After logout
OneSignal.deleteTag("key") // delete that specific tag from OneSignal db
I am using Parse as my backend for my iOS app to send push notifications. My problem is that the app icon never shows a badge after receiving push notifications (Besides for the badge, everything works fine).
I've checked the "badge" field in the Installation DB on Parse and it is increasing with every push, so I feel it might be a client-side issue
Here is my cloud code:
Parse.Push.send({
where: pushQuery,
data: {
aps: {
alert: "Your friend " + request.user.get("Name") + " just joined VoiceMe!",
sound: "default",
AlertType: "NewFriend"
},
badge: "Increment"
}
}, {
success: function() {
/*all is good*/
},
error: function(error) {
outcome = false;
errorOutput = error;
}
});
And the code in my app:
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let currentInstallation = PFInstallation.currentInstallation()
if PFUser.currentUser() != nil {
currentInstallation.setObject(PFUser.currentUser()!, forKey: kParseInstallationUserKey)
}
currentInstallation.setDeviceTokenFromData(deviceToken)
currentInstallation.channels = ["global"]
currentInstallation.saveInBackgroundWithBlock { (resultBool, error) -> Void in
println("register device: --- \(resultBool) ---- error: \(error)")
}
}
Image of Installation DB on Parse:
See my answer here: https://stackoverflow.com/a/27615528/2353523 for reference
you've created your own dictionary. That's used for interactive notifications etc. Badge is outside of that dictionary that you've created which is the correct dictionary for sending pushes. That's why it doesn't increment in the payload you created under the dictionary of aps. You have to tell it to. Else, just delete the aps dict and pass your parameters through the data dict