How to set up push notifications in Swift - ios

I am trying to set up a push notification system for my application. I have a server and a developer license to set up the push notification service.
I am currently running my app in Swift. I would like to be able to send the notifications remotely from my server. How can I do this?

Swift 2:
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()

While the answer is given well to handle push notification, still I believe to share integrated complete case at once to ease:
To Register Application for APNS, (Include the following code in didFinishLaunchingWithOptions method inside AppDelegate.swift)
IOS 9
var settings : UIUserNotificationSettings = UIUserNotificationSettings(forTypes:UIUserNotificationType.Alert|UIUserNotificationType.Sound, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
After IOS 10
Introduced UserNotifications framework:
Import the UserNotifications framework and add the UNUserNotificationCenterDelegate in AppDelegate.swift
To Register Application for APNS
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// If granted comes true you can enabled features based on authorization.
guard granted else { return }
application.registerForRemoteNotifications()
}
This will call following delegate method
func application(application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
//send this device token to server
}
//Called if unable to register for APNS.
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println(error)
}
On Receiving notification following delegate will call:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
println("Recived: \(userInfo)")
//Parsing userinfo:
var temp : NSDictionary = userInfo
if let info = userInfo["aps"] as? Dictionary<String, AnyObject>
{
var alertMsg = info["alert"] as! String
var alert: UIAlertView!
alert = UIAlertView(title: "", message: alertMsg, delegate: nil, cancelButtonTitle: "OK")
alert.show()
}
}
To be identify the permission given we can use:
UNUserNotificationCenter.current().getNotificationSettings(){ (setttings) in
switch setttings.soundSetting{
case .enabled:
print("enabled sound")
case .disabled:
print("not allowed notifications")
case .notSupported:
print("something went wrong here")
}
}
So the checklist of APNS:
Create AppId allowed with Push Notification
Create SSL certificate with valid certificate and app id
Create Provisioning profile with same certificate and make sure to add device in case of sandboxing(development provisioning)
Note: That will be good if Create Provisioning profile after SSL Certificate.
With Code:
Register app for push notification
Handle didRegisterForRemoteNotificationsWithDeviceToken method
Set targets> Capability> background modes> Remote Notification
Handle didReceiveRemoteNotification

To register to receive push notifications via Apple Push Service you have to call a registerForRemoteNotifications() method of UIApplication.
If registration succeeds, the app calls your app delegate object’s application:didRegisterForRemoteNotificationsWithDeviceToken: method and passes it a device token.
You should pass this token along to the server you use to generate push notifications for the device. If registration fails, the app calls its app delegate’s application:didFailToRegisterForRemoteNotificationsWithError: method instead.
Have a look into Local and Push Notification Programming Guide.

registerForRemoteNotification() has been removed from ios8.
So you should use UIUserNotification
CODE EXAMPLE:
var type = UIUserNotificationType.Badge | UIUserNotificationType.Alert | UIUserNotificationType.Sound;
var setting = UIUserNotificationSettings(forTypes: type, categories: nil);
UIApplication.sharedApplication().registerUserNotificationSettings(setting);
UIApplication.sharedApplication().registerForRemoteNotifications();
Hope this will help you.

To support ios 8 and before, use this:
// Register for Push Notitications, if running iOS 8
if application.respondsToSelector("registerUserNotificationSettings:") {
let types:UIUserNotificationType = (.Alert | .Badge | .Sound)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
// Register for Push Notifications before iOS 8
application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}

Swift 4
I think this is the correct way for setup in iOS 8 and above.
Turn on Push Notifications in the Capabilities tab
Import UserNotifications
import UserNotifications
Modify didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let notification = launchOptions?[.remoteNotification] as? [String: AnyObject] {
// If your app wasn’t running and the user launches it by tapping the push notification, the push notification is passed to your app in the launchOptions
let aps = notification["aps"] as! [String: AnyObject]
UIApplication.shared.applicationIconBadgeNumber = 0
}
registerForPushNotifications()
return true
}
It’s extremely important to call registerUserNotificationSettings(_:) every time the app launches. This is because the user can, at any time, go into the Settings app and change the notification permissions. application(_:didRegisterUserNotificationSettings:) will always provide you with what permissions the user currently has allowed for your app.
Copy paste this AppDelegate extension
// Push Notificaion
extension AppDelegate {
func registerForPushNotifications() {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] (granted, error) in
print("Permission granted: \(granted)")
guard granted else {
print("Please enable \"Notifications\" from App Settings.")
self?.showPermissionAlert()
return
}
self?.getNotificationSettings()
}
} else {
let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
UIApplication.shared.registerForRemoteNotifications()
}
}
#available(iOS 10.0, *)
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
print("Device Token: \(token)")
//UserDefaults.standard.set(token, forKey: DEVICE_TOKEN)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// If your app was running and in the foreground
// Or
// If your app was running or suspended in the background and the user brings it to the foreground by tapping the push notification
print("didReceiveRemoteNotification /(userInfo)")
guard let dict = userInfo["aps"] as? [String: Any], let msg = dict ["alert"] as? String else {
print("Notification Parsing Error")
return
}
}
func showPermissionAlert() {
let alert = UIAlertController(title: "WARNING", message: "Please enable access to Notifications in the Settings app.", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) {[weak self] (alertAction) in
self?.gotoAppSettings()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alert.addAction(settingsAction)
alert.addAction(cancelAction)
DispatchQueue.main.async {
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
}
private func gotoAppSettings() {
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.openURL(settingsUrl)
}
}
}
Check out: Push Notifications Tutorial: Getting Started

Thanks for the earlier answers. Xcode has made some changes and here's the SWIFT 2 code that passes XCode 7 code check and supports both iOS 7 and above:
if #available(iOS 8.0, *) {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
} else {
let settings = UIRemoteNotificationType.Alert.union(UIRemoteNotificationType.Badge).union(UIRemoteNotificationType.Sound)
UIApplication.sharedApplication().registerForRemoteNotificationTypes(settings)
}

Swift 4
Import the UserNotifications framework and add the UNUserNotificationCenterDelegate in AppDelegate
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate
To Register Application for APNS, (Include the following code in didFinishLaunchingWithOptions method inside AppDelegate.swift)
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
application.registerForRemoteNotifications()
This will call following delegate method
func application(_ application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//send this device token to server
}
//Called if unable to register for APNS.
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print(error)
}
On Receiving notification following delegate will call:
private func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print("Recived: \(userInfo)")
//Parsing userinfo:
}

Swift 3:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
UIApplication.shared.registerForRemoteNotifications()
Make sure to import UserNotifications at the top of your view controller.
import UserNotifications

You can send notification using the following code snippet:
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
if(UIApplication.sharedApplication().currentUserNotificationSettings() == settings ){
//OK
}else{
//KO
}

I use this code snip in AppDelegate.swift:
let pushType = UIUserNotificationType.alert.union(.badge).union(.sound)
let pushSettings = UIUserNotificationSettings(types: pushType
, categories: nil)
application.registerUserNotificationSettings(pushSettings)
application.registerForRemoteNotifications()

100% Working... You Can read onesignal document and setup properly https://documentation.onesignal.com/docs/ios-sdk-setup
OneSignal below code import in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
OneSignal.setLogLevel(.LL_VERBOSE, visualLevel: .LL_NONE)
// OneSignal initialization
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: false, kOSSettingsKeyInAppLaunchURL: false]
OneSignal.initWithLaunchOptions(launchOptions,
appId: "YOUR_ONE_SIGNAL_ID",
handleNotificationAction: nil,
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = OSNotificationDisplayType.inAppAlert;
// promptForPushNotifications will show the native iOS notification permission prompt.
// We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 8)
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
return true
}

Related

iOS 11.2.5 - didRegisterForRemoteNotificationWithDeviceToken - no response

Starting with the OS 11.2.5 my devices weren't able to register a remote notification (e.g. for silent push purposes. I implemented the registration process within these code lines:
// Ask for notification permission
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {(accepted, error) in
if !accepted {
print("Notification access denied.")
}
}
application.registerForRemoteNotifications()
Additionally, as you already know, you need to implement the following two methods, in order to register a remote notification at Apple:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
// Get my token here and do additionally stuff
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Handling error for registering here
}
So my question would be the following: This implementation has been working until Apple OS Update 11.2.4: The didRegisterForRemoteNotificationsWithDeviceToken was successfully called after registering a device and in case of an error the other method didFailToRegisterForRemoteNotificationsWithError was called -> everything perfect!
But starting with OS 11.2.5 I got no response from Apple anymore. I spent a lot of time investigating this issue. After Apple released OS 11.2.6 it worked like charm again -> I'm totally confused.
Does anybody know, if this is a known issue in OS 11.2.5? - Thanks Alex
I guess the problem caused at registering for remote notification, try below code please:
// Ask for notification permission
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {(accepted, error) in
if accepted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}else{
print("Notification access denied.")
}
}
use updated methods.
// Push Notifications
func registerForPushnotifications(application: UIApplication)
{
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
guard granted else{ return }
self.getNotificationSetting()
}
}
else
{
// Fallback on earlier versions
let notificationSettings = UIUserNotificationSettings(
types: [.badge, .sound, .alert], categories: nil)
application.registerUserNotificationSettings(notificationSettings)
}
}
// Push Notification settings
func getNotificationSetting()
{
if #available(iOS 10.0, *)
{
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
guard settings.authorizationStatus == .authorized else {return}
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
}
// Push Notifications Delegates
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error)
{
print("Failed to register for remote Notifications due to: \(error.localizedDescription)")
}

How to ask user permission for receiving notifications?

I am using Swift 3.0 and I want the user to be able to click on a button to trigger the alert box that requests his permission for using notifications.
I am surprised not to find more information about that.
I would like to support iOS 9.0 as well as 10.
What is the way to trigger this ask-for-permission alert box again ?
import UserNotifications
and Declare this UNUserNotificationCenterDelegate Method in header
in appDelegates just put this code :
func registerForRemoteNotification() {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
if error == nil{
UIApplication.shared.registerForRemoteNotifications()
}
}
}
else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
}
And when user give permission at that time you can get user token via didRegisterForRemoteNotificationsWithDeviceToken Delegates method
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
print(token)
print(deviceToken.description)
if let uuid = UIDevice.current.identifierForVendor?.uuidString {
print(uuid)
}
UserDefaults.standard.setValue(token, forKey: "ApplicationIdentifier")
UserDefaults.standard.synchronize()
}
Below is the full code for all the scenarios, check with break points
Working copy of code, copy paste in your Appdelegate.
XCode 9 , iOS 11, Swift 4
//
// AppDelegate.swift
// PushNotification
import UIKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10, *)
{ // iOS 10 support
//create the notificationCenter
let center = UNUserNotificationCenter.current()
center.delegate = self
// set the type as sound or badge
center.requestAuthorization(options: [.sound,.alert,.badge]) { (granted, error) in
if granted {
print("Notification Enable Successfully")
}else{
print("Some Error Occure")
}
}
application.registerForRemoteNotifications()
}
else if #available(iOS 9, *)
{
// iOS 9 support
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
else if #available(iOS 8, *)
{
// iOS 8 support
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound,
.alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
else
{ // iOS 7 support
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
return true
}
//get device token here
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: Data)
{
var token = ""
for i in 0..<deviceToken.count {
token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
print("Registration succeeded!")
print("Token: ", token)
//send tokens to backend server
// storeTokens(token)
}
//get error here
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error:
Error) {
print("Registration failed!")
}
//get Notification Here below ios 10
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
// Print notification payload data
print("Push notification received: \(data)")
}
//This is the two delegate method to get the notification in iOS 10..
//First for foreground
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (_ options:UNNotificationPresentationOptions) -> Void)
{
print("Handle push from foreground")
// custom code to handle push while app is in the foreground
print("\(notification.request.content.userInfo)")
}
//Second for background and close
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response:UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void)
{
print("Handle push from background or closed")
// if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background
print("\(response.notification.request.content.userInfo)")
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
You can use UserNotifications framework to handle notifications for iOS app. Once you ask for authorization system will automatically prompts alert to user.
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
else{
//Success.. do something on success
}
}
For iOS 9.0 :
private func requestAuthorizationForiOS9AndBelow(){
let notificationSettings = UIUserNotificationSettings(
types: [.badge, .sound, .alert], categories: nil)
UIApplication.shared.registerUserNotificationSettings(notificationSettings)
}
You can do this way
In AppDelegate inside the didFinishLaunching method
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { (granted, error) in
if (granted == true){
}else{
print("request authorisation error: \(error)")
}
})
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()

Notification not coming via Firebase console

I have tried every possible solutions for above issue but still not getting notification to my device via Firebase Console. Please suggest.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
self.handleNotification(remoteNotification as! [NSObject : AnyObject])
}
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
// Add observer for InstanceID token refresh callback.
NSNotificationCenter
.defaultCenter()
.addObserver(self, selector: #selector(AppDelegate.tokenRefreshNotificaiton),
name: kFIRInstanceIDTokenRefreshNotification, object: nil)
return true }
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
FIRMessaging.messaging().appDidReceiveMessage(userInfo)
NSNotificationCenter.defaultCenter().postNotificationName("reloadTheTable", object: nil)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox)
}
func tokenRefreshNotificaiton(notification: NSNotification) {
guard let refreshedToken = FIRInstanceID.instanceID().token()
else {
return
}
print("InstanceID token: \(refreshedToken)")
utill.tokenDefault.setValue(refreshedToken, forKey: "tokenId")
connectToFcm()
}
Few firebase warnings are also displaying in the debugger:
Please make sure you have enabled push notification capabilities from project target capabilities section shown in the picture if you are deploying the application from Xcode 8 or later.
I think the problem is because of the ios version. ios 10 requires UNUserNotificationCenter. Try the code below and add the function to your application didFinishLaunching.
func registerForRemoteNotification() {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
if error == nil{
UIApplication.shared.registerForRemoteNotifications()
}
}
}
else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
}
Issue Resolved for me.
I skipped uploading APNs development certificate.

Registering for Push Notifications in Xcode 8/Swift 3.0?

I'm trying to get my app working in Xcode 8.0, and am running into an error. I know this code worked fine in previous versions of swift, but I'm assuming the code for this is changed in the new version. Here's the code I'm trying to run:
let settings = UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.shared().registerForRemoteNotifications()
The error that I'm getting is "Argument labels '(forTypes:, categories:)' do not match any available overloads"
Is there a different command that I could try to get this working?
Import the UserNotifications framework and add the UNUserNotificationCenterDelegate in AppDelegate.swift
Request user permission
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
application.registerForRemoteNotifications()
return true
}
Getting device token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(deviceTokenString)
}
In case of error
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("i am not available in simulator \(error)")
}
In case if you need to know the permissions granted
UNUserNotificationCenter.current().getNotificationSettings(){ (settings) in
switch settings.soundSetting{
case .enabled:
print("enabled sound setting")
case .disabled:
print("setting has been disabled")
case .notSupported:
print("something vital went wrong here")
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if #available(iOS 10, *) {
//Notifications get posted to the function (delegate): func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void)"
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
guard error == nil else {
//Display Error.. Handle Error.. etc..
return
}
if granted {
//Do stuff here..
//Register for RemoteNotifications. Your Remote Notifications can display alerts now :)
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
else {
//Handle user denying permissions..
}
}
//Register for remote notifications.. If permission above is NOT granted, all notifications are delivered silently to AppDelegate.
application.registerForRemoteNotifications()
}
else {
let settings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
return true
}
import UserNotifications
Next, go to the project editor for your target, and in the General tab, look for the Linked Frameworks and Libraries section.
Click + and select UserNotifications.framework:
// iOS 12 support
if #available(iOS 12, *) {
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound, .provisional, .providesAppNotificationSettings, .criticalAlert]){ (granted, error) in }
application.registerForRemoteNotifications()
}
// iOS 10 support
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in }
application.registerForRemoteNotifications()
}
// iOS 9 support
else if #available(iOS 9, *) {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
// iOS 8 support
else if #available(iOS 8, *) {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
// iOS 7 support
else {
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
Use Notification delegate methods
// Called when APNs has assigned the device a unique token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// Convert token to string
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print("APNs device token: \(deviceTokenString)")
}
// Called when APNs failed to register the device for push notifications
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Print the error to console (you should alert the user that registration failed)
print("APNs registration failed: \(error)")
}
For receiving push notification
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
completionHandler(UIBackgroundFetchResult.noData)
}
Setting up push notifications is enabling the feature within Xcode 8
for your app. Simply go to the project editor for your target and then
click on the Capabilities tab. Look for Push Notifications and toggle
its value to ON.
Check below link for more Notification delegate methods
Handling Local and Remote Notifications UIApplicationDelegate - Handling Local and Remote Notifications
https://developer.apple.com/reference/uikit/uiapplicationdelegate
I had issues with the answers here in converting the deviceToken Data object to a string to send to my server with the current beta of Xcode 8. Especially the one that was using deviceToken.description as in 8.0b6 that would return "32 Bytes" which isn't very useful :)
This is what worked for me...
Create an extension on Data to implement a "hexString" method:
extension Data {
func hexString() -> String {
return self.reduce("") { string, byte in
string + String(format: "%02X", byte)
}
}
}
And then use that when you receive the callback from registering for remote notifications:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.hexString()
// Send to your server here...
}
In iOS10 instead of your code, you should request an authorization for notification with the following: (Don't forget to add the UserNotifications Framework)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization([.alert, .sound, .badge]) { (granted: Bool, error: NSError?) in
// Do something here
}
}
Also, the correct code for you is (use in the else of the previous condition, for example):
let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
UIApplication.shared().registerUserNotificationSettings(setting)
UIApplication.shared().registerForRemoteNotifications()
Finally, make sure Push Notification is activated under target-> Capabilities -> Push notification. (set it on On)
Well this work for me.
First in AppDelegate
import UserNotifications
Then:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
registerForRemoteNotification()
return true
}
func registerForRemoteNotification() {
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
if error == nil{
UIApplication.shared.registerForRemoteNotifications()
}
}
}
else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
}
To get devicetoken:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
}
Heads up, you should be using the main thread for this action.
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
if granted {
DispatchQueue.main.async(execute: {
UIApplication.shared.registerForRemoteNotifications()
})
}
}
First, listen to user notification status, i.e., registerForRemoteNotifications() to get APNs device token;
Second, request authorization. When being authorized by the user, deviceToken will be sent to the listener, the AppDelegate;
Third, report the device token to your server.
extension AppDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// 1. listen(监听) to deviceToken
UIApplication.shared.registerForRemoteNotifications()
// 2. request device token
requestAuthorization()
}
func requestAuthorization() {
if #available(iOS 10, *) {
let uc = UNUserNotificationCenter.current()
uc.delegate = UIApplication.shared.delegate as? AppDelegate
uc.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if let error = error { // 无论是拒绝推送,还是不提供 aps-certificate,此 error 始终为 nil
print("UNUserNotificationCenter 注册通知失败, \(error)")
}
DispatchQueue.main.async {
onAuthorization(granted: granted)
}
}
} else {
let app = UIApplication.shared
app.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
}
}
// 在 app.registerUserNotificationSettings() 之后收到用户接受或拒绝及默拒后,此委托方法被调用
func application(_ app: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
// 已申请推送权限,所作的检测才有效
// a 征询推送许可时,用户把app切到后台,就等价于默拒了推送
// b 在系统设置里打开推送,但关掉所有形式的提醒,等价于拒绝推送,得不token,也收不推送
// c 关掉badge, alert和sound 时,notificationSettings.types.rawValue 等于 0 和 app.isRegisteredForRemoteNotifications 成立,但能得到token,也能收到推送(锁屏和通知中心也能看到推送),这说明types涵盖并不全面
// 对于模拟器来说,由于不能接收推送,所以 isRegisteredForRemoteNotifications 始终为 false
onAuthorization(granted: app.isRegisteredForRemoteNotifications)
}
static func onAuthorization(granted: Bool) {
guard granted else { return }
// do something
}
}
extension AppDelegate {
func application(_ app: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//
}
// 模拟器得不到 token,没配置 aps-certificate 的项目也得不到 token,网络原因也可能导致得不到 token
func application(_ app: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
//
}
}
The answer from ast1 is very simple and useful. It works for me, thank you so much.
I just want to poin it out here, so people who need this answer can find it easily. So, here is my code from registering local and remote (push) notification.
//1. In Appdelegate: didFinishLaunchingWithOptions add these line of codes
let mynotif = UNUserNotificationCenter.current()
mynotif.requestAuthorization(options: [.alert, .sound, .badge]) {(granted, error) in }//register and ask user's permission for local notification
//2. Add these functions at the bottom of your AppDelegate before the last "}"
func application(_ application: UIApplication, didRegister notificationSettings: UNNotificationSettings) {
application.registerForRemoteNotifications()//register for push notif after users granted their permission for showing notification
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print("Device Token: \(tokenString)")//print device token in debugger console
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")//print error in debugger console
}
Simply do the following in didFinishWithLaunching::
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: []) { _, _ in
application.registerForRemoteNotifications()
}
}
Remember about import statement:
import UserNotifications
Take a look at this commented code:
import Foundation
import UserNotifications
import ObjectMapper
class AppDelegate{
let center = UNUserNotificationCenter.current()
}
extension AppDelegate {
struct Keys {
static let deviceToken = "deviceToken"
}
// MARK: - UIApplicationDelegate Methods
func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if let tokenData: String = String(data: deviceToken, encoding: String.Encoding.utf8) {
debugPrint("Device Push Token \(tokenData)")
}
// Prepare the Device Token for Registration (remove spaces and < >)
setDeviceToken(deviceToken)
}
func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
debugPrint(error.localizedDescription)
}
// MARK: - Private Methods
/**
Register remote notification to send notifications
*/
func registerRemoteNotification() {
center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
// Enable or disable features based on authorization.
if granted == true {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
} else {
debugPrint("User denied the permissions")
}
}
}
/**
Deregister remote notification
*/
func deregisterRemoteNotification() {
UIApplication.shared.unregisterForRemoteNotifications()
}
func setDeviceToken(_ token: Data) {
let token = token.map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
UserDefaults.setObject(token as AnyObject?, forKey: “deviceToken”)
}
class func deviceToken() -> String {
let deviceToken: String? = UserDefaults.objectForKey(“deviceToken”) as? String
if isObjectInitialized(deviceToken as AnyObject?) {
return deviceToken!
}
return "123"
}
func isObjectInitialized(_ value: AnyObject?) -> Bool {
guard let _ = value else {
return false
}
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping(UNNotificationPresentationOptions) -> Swift.Void) {
("\(notification.request.content.userInfo) Identifier: \(notification.request.identifier)")
completionHandler([.alert, .badge, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping() -> Swift.Void) {
debugPrint("\(response.notification.request.content.userInfo) Identifier: \(response.notification.request.identifier)")
}
}
Let me know if there is any problem!

How to control when to prompt user for push notification permissions in iOS

I've built an application for iPhone using Swift and Xcode 6, and the Parse framework to handle services.
While following the Parse tutorials on how to set up push notifications, the instructions advised that I put the push notifications in the App Delegate file.
This is the code that I have added to the App Delegate file...
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var pushNotificationsController: PushNotificationController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Register for Push Notifications
self.pushNotificationsController = PushNotificationController()
if application.respondsToSelector("registerUserNotificationSettings:") {
println("registerUserNotificationSettings.RegisterForRemoteNotificatios")
let userNotificationTypes: UIUserNotificationType = (.Alert | .Badge | .Sound)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
return true;
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
println("didRegisterForRemoteNotificationsWithDeviceToken")
let installation = PFInstallation.currentInstallation()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackground()
}
}
So what happens is that as soon as the application is launched for the first time, the user is prompted to grant these permissions.
What I want to do, is only prompt for these permissions after a certain action has taken place (ie, during a walkthrough of the features of the app) so I can provide a little more context on why we would want them to allow push notifications.
Is it as simple as just copying the below code in the relevant ViewController where I will be expecting to prompt the user?
// In 'MainViewController.swift' file
func promptUserToRegisterPushNotifications() {
// Register for Push Notifications
self.pushNotificationsController = PushNotificationController()
if application.respondsToSelector("registerUserNotificationSettings:") {
println("registerUserNotificationSettings.RegisterForRemoteNotificatios")
let userNotificationTypes: UIUserNotificationType = (.Alert | .Badge | .Sound)
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
println("didRegisterForRemoteNotificationsWithDeviceToken")
let installation = PFInstallation.currentInstallation()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackground()
}
thanks!
The answer is simple. If you want the user to be prompted some other time, for instance on a button press then simply move the code regarding the request into that function (or call promptUserToRegisterPushNotifications() from somewhere else).
To get a hold of the application variable outside the AppDelegate, simply do this:
let application = UIApplication.shared
Hope that helps :)
This is for Swift 2. I have placed promptUserToRegisterPushNotifications() in MainViewController.swift, but I have left didRegisterForRemoteNotificationsWithDeviceToken in AppDelegate because it didn't work when I place it on the same MainViewController.swift.
// In 'MainViewController.swift' file
func promptUserToRegisterPushNotifications() {
// Register for Push Notifications
let application: UIApplication = UIApplication.sharedApplication()
if application.respondsToSelector(#selector(UIApplication.registerUserNotificationSettings(_:))) {
print("registerUserNotificationSettings.RegisterForRemoteNotificatios")
let notificationSettings = UIUserNotificationSettings(
forTypes: [.Badge, .Sound, .Alert], categories: nil)
application.registerUserNotificationSettings(notificationSettings) // Register for Remote Push Notifications
application.registerForRemoteNotifications()
}
}
// In AppDelegate
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for i in 0..<deviceToken.length {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
NSUserDefaults.standardUserDefaults().setObject(tokenString, forKey: "deviceToken")
print("Device Token:", tokenString)
}
This is method I have written in the code and works fine once it called on launch (didFinishLaunch)
class func registerNotification() {
if #available(iOS 10.0, *) {
// push notifications
UNUserNotificationCenter.current().requestAuthorization(options: [.sound, .alert, .badge]) {
(granted, error) in
if (granted) {
UIApplication.shared.registerForRemoteNotifications()
}
}
let center = UNUserNotificationCenter.current()
center.delegate = AppManager.appDel()
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
if error == nil {
UIApplication.shared.registerForRemoteNotifications()
}
}
} else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
}

Resources