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.
Related
I am working on adding Remote push notification support in my OSX application. I can successfully receive the push notification in my PC via apns and when I click the notification banner this is the behavior I am seeing.
If my app is not running , it will launch the application. But never hits on "ReceivedRemoteNotification()". Is this expected behavior ? Is there any way to receive the apns payload in this case ?
If my app is running I get the payload via "ReceivedRemoteNotification" and things are working fine.
So we cannot get apns payload in our app if it is not running?
Any help really appreciated.
thanks,
Jithesh
Figured it out. The payload is available through "NSNotification" parameter of DidFinishLaunching.
public override void DidFinishLaunching(NSNotification notification)
{
var uInfo = notification.UserInfo;
if(uInfo["NSApplicationLaunchUserNotificationKey"] != null)
{
var payLoad = uInfo["NSApplicationLaunchUserNotificationKey"] as NSUserNotification;
if(payLoad.ActivationType == NSUserNotificationActivationType.ActionButtonClicked)
{
NSAlert alert = new NSAlert();
alert.MessageText = "Button Clicked";
alert.RunModal();
}
var userInfo = payLoad.UserInfo;
//not.ActivationType ==
if (userInfo != null && userInfo.ContainsKey(new NSString("aps")))
{
//Get the aps dictionary
NSDictionary aps = userInfo.ObjectForKey(new NSString("aps")) as NSDictionary;
if (aps.ContainsKey(new NSString("content")))
{
var deepLink = (aps[new NSString("content")] as NSString).ToString();
NSAlert alert = new NSAlert();
alert.MessageText = deepLink;
alert.RunModal();
//DisplaySubView(deepLink);
//Console.WriteLine($"Deeplink : {deepLink}");
}
}
}
I checked OneSignal documentation but I couldn't understand clearly as beginner how setting dictionary as a post notification's additional data (like postID, userID, type) in iOS Native SDK using Swift to decide and redirect when user interacted with notification.
For posting I'm doing only like that:
OneSignal.sendTag("username", value: "\(user)")
OneSignal.postNotification(["contents": ["en": "#\(user) added an additive to your '\(title)' experience: \"\(strLast)\""],
"include_player_ids": [postOwnerPlayerID],
For receiving:
OneSignal.initWithLaunchOptions(launchOptions, appId: "______", handleNotificationReceived: nil, handleNotificationAction: {
(result) in
// This block gets called when the user reacts to a notification received
let payload = result?.notification.payload
//Try to fetch the action selected
if let additionalData = payload?.additionalData {
print("payload")
print(additionalData)
}
// After deciding which action then I can redirect user..
let username: String? = UserDefaults.standard.string(forKey: KEY_UID)
if username != nil {
if let tabbarController = self.window!.rootViewController as? UITabBarController {
tabbarController.selectedViewController = tabbarController.viewControllers?[2]
// NotificationCenter.default.post(name: Foundation.Notification.Name(rawValue: "notificationsUp"), object: nil)
}
}
}, settings: [kOSSettingsKeyInFocusDisplayOption : OSNotificationDisplayType.none.rawValue])
You set the data field as a key in the dictionary passed to OneSignal.postNotification like the following.
OneSignal.postNotification(["contents": ["en": "Test Message"],
"include_player_ids": ["3009e210-3166-11e5-bc1b-db44eb02b120"],
"data": ["postID": "id"]])
Then you need to get ready your keys from additionalData from the payload in the handleNotificationAction function.
if let additionalData = payload?.additionalData {
let postID: String? = additionalData["postID"]
}
Example from iOS in objC to send additional data...
[OneSignal postNotification:#{#"contents":#{#"en":text},
#"include_player_ids":oneSignalIds,
#"data":#{#"key": #"value"},
}];
And to receive the data...
[OneSignal initWithLaunchOptions:launchOptions
appId:ONESIGNAL_APPID
handleNotificationReceived:^(OSNotification *notification) {
if (notification.payload.additionalData) {
NSDictionary* additionalData = notification.payload.additionalData;
if (additionalData[#"key"]){
NSLog(#"Received Data - %#", additionalData[#"key"]);
}
}
}
handleNotificationAction:nil
settings:#{kOSSettingsKeyInAppAlerts:#YES}];
Hope it helps someone :)
Thanks to #jkasten helped me in the right direction! helped me get rid of the AnyHashable warning I was getting.
Swift 3 code (change PATH to the additionalData parameter you want to output):
let PATH = notification!.payload.additionalData["PATH"]
print("PATH: ",PATH as Any)
If you're looking to do the same but in the Notification Service Extension, take a look at our updated documentation.
The Notification Service Extension is used for:
- Badges
- Influenced Opens with Firebase Analytics
- Media Attachments
- Action Buttons
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()
I need registrationId from Azure. Is it possible to get the registrationId from Azure?
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *) deviceToken {
SBNotificationHub* hub = [[SBNotificationHub alloc] initWithConnectionString:HUBLISTENACCESS
notificationHubPath:HUBNAME];
[hub registerNativeWithDeviceToken:deviceToken tags:nil completion:^(NSError* error) {
if (error != nil) {
NSLog(#"Error registering for notifications: %#", error);
}
else {
[self MessageBox:#"Registration Status" message:#"Registered"];
}
}];
}
Notifications are working fine but I need registrationId from Azure to send back to server.
I pored through the NotificationHub SDK code available at https://github.com/Azure/azure-notificationhubs/tree/master/iOS/WindowsAzureMessaging/WindowsAzureMessaging and found that the registration methods are all internal to the SDK class SBNotificationHub and are not exposed via the ObjC header file. Until they do that you either override the SDK header file with your own or accept that you can't access the registrationId from the SDK. The methods in question are retrieveAllRegistrationsWithDeviceToken or extractRegistrationIdFromLocationUri. The latter also requires that you call composeCreateRegistrationIdUri and then registrationOperationWithRequestUri.
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