iOS 10 UNNotification doesn't show alert - xcode

The code is very easy:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { (granted, error) in
if !granted {
print("Not allowed")
}
})
let content = UNMutableNotificationContent()
content.title = "Alert"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 20, repeats: false)
let request = UNNotificationRequest(identifier: "test", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
return true
}
It works well on iOS 11, like this:
but on iOS 10, the alert doesn't show.
On both iOS 10 and iOS 11, the sound did appear.
My Xcode version is 9.2(9C40b)
Any help is appreciated.

Try to add the body of notification like this
content.body = "Any text/Blank Space"
Hope this will help you

Related

XCode 11: Background region monitoring does not work

After hours of reading and re-coding I still can't find a solution.
I want to build a simple app, that tracks my location in the background. On first application load I set up a region around my current location, start monitoring for exactly this region and stopUpdatingLocations. Once the app gets the didExitRegion event, I again get the current location, set up another region (after cleaning all other monitored regions) and it all starts again.
The app has alwaysAuthorization for location, background mode for location updates is set, PList contains LocationAlwaysAndWhenInUseUsageDescription and LocationWhenInUseUsageDescription.
For some time, it works great. But after many hours of not moving, the app gets suspended and does not receive any more location updates, not even the monitor event, which should relaunch the app when I understand this () correctly.
Could anyboy give me a hint?
Thanks.
import UIKit
import CoreLocation
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
let locationManager = CLLocationManager()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let currentNotifications = UNUserNotificationCenter.current()
currentNotifications.getNotificationSettings { (settings) in
if settings.authorizationStatus == .notDetermined {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, error) in }
}
}
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
return true
}
}
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let now = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
for region in locationManager.monitoredRegions {
locationManager.stopMonitoring(for: region)
}
var regionIdentifier = String(format: "%f", location.coordinate.latitude) + ", " + String(format: "%f", location.coordinate.latitude) + "( set on " + formatter.string(from: now) + ")"
var geofenceRegion = CLCircularRegion(center: CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude), radius: 250, identifier: regionIdentifier)
geofenceRegion.notifyOnExit = true
locationManager.startMonitoring(for: geofenceRegion)
locationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
locationManager.stopMonitoring(for: region)
sendNotification(title: "Event triggered", subtitle: "Region exit", body: region.identifier)
locationManager.startUpdatingLocation()
}
}
public func sendNotification(title: String, subtitle: String, body: String) {
let content = UNMutableNotificationContent()
content.title = title
content.subtitle = subtitle
content.body = body
content.sound = .default
let identifier = "geoStalker4_notification_" + String(format: "%f", NSDate().timeIntervalSince1970)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
Try adding this to your locationManager settings:
locationManager.pausesLocationUpdatesAutomatically = false

Remote Push notifications actions

I created a code that receive remote push norification, this code is worked ok. Now I need to add two "buttons" that swip left and do a action. I know that this below code is used to indetify the action
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
if identifier == "optin1" {
//do something
}
else identifier == "option2" {
//do something
}
completionHandler()
}
But I dont knew how to create the buttons to swip left. How can I do it
This is my AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
// Override point for customization after application launch.
let types:UIUserNotificationType = [.Alert, .Sound, .Badge]
application.registerForRemoteNotifications()
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: types, categories: nil))
initLocationManager()
return true
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
//print(error)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
print(deviceToken)
}
func application(application: UIApplication, didReceiveRemoteNotificationuserInfo userInfo: [NSObject : AnyObject]) {
print(userInfo)
}
Update: new version Swift 4 compatible. This example was adapted from this amazing tutorial https://cocoacasts.com/actionable-notifications-with-the-user-notifications-framework
Configure User Notification Center
import UserNotifications
...
UNUserNotificationCenter.current().delegate = self
Define Actions
let actionReadLater = UNNotificationAction(identifier: Constants.Action.readLater,
title: "Read Later",
options: [])
Define Category
let tutorialCategory = UNNotificationCategory(identifier: Constants.Category.tutorial,
actions: [actionReadLater],
intentIdentifiers: [],
options: [])
Register Category
UNUserNotificationCenter.current().setNotificationCategories([tutorialCategory])
Schedule local notifications by instance from an IBAction
// Request Notification Settings
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
self.requestAuthorization(completionHandler: { (success) in
guard success else { return }
// Schedule Local Notification
self.scheduleLocalNotification()
})
case .authorized:
// Schedule Local Notification
self.scheduleLocalNotification()
case .denied:
print("Application Not Allowed to Display Notifications")
case .provisional:
print("provisional")
}
}
previous version
You can copy&paste this code in didFinishLaunchingWithOptions method:
Create the action
// NOTFICATION
let incrementAction = UIMutableUserNotificationAction()
incrementAction.identifier = "HI_ACTION"
incrementAction.title = "Hi!"
incrementAction.activationMode = UIUserNotificationActivationMode.Background
incrementAction.authenticationRequired = false
incrementAction.destructive = false
Create the category
let counterCategory = UIMutableUserNotificationCategory()
counterCategory.identifier = "HELLO_CATEGORY"
Associate action and category
counterCategory.setActions([incrementAction],
forContext: UIUserNotificationActionContext.Default)
counterCategory.setActions([incrementAction],
forContext: UIUserNotificationActionContext.Minimal)
Registration
let categories = NSSet(object: counterCategory) as! Set<UIUserNotificationCategory>
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound], categories: categories)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
The last step is only for demostration
let notification = UILocalNotification()
notification.alertBody = "Hey!"
notification.soundName = UILocalNotificationDefaultSoundName
notification.fireDate = NSDate(timeIntervalSinceNow: 5)
notification.category = "HELLO_CATEGORY"
UIApplication.sharedApplication().scheduleLocalNotification(notification)
When the app is launched you have to push CMD+L
Here's a link to an example

TableView not updating

I'm currently struggling with getting my TableView to update after I finish performing some functions called in viewDidLoad and viewDidAppear. I tried using self.tableView.reloadData() at the end of my viewDidLoad but it didn't work and upon reloading the tab, the app would crash.
Here is some of my code (I'm trying to fetch events from a Google Calendar and display it in a TableView). I'm trying to display an array of strings named listOfEvents and it is being populated after the tableView is already loaded.
I also tried adding self.tableView.reloadData() at the end of my fetchEvents() but it also killed my app upon reloading the tab
class CalendarViewController: UITableViewController {
var listOfEvents: [String] = []
private let kKeychainItemName = "Google Calendar API"
private let kClientID = "clientID"
// If modifying these scopes, delete your previously saved credentials by
// resetting the iOS simulator or uninstall the app.
private let scopes = [kGTLAuthScopeCalendarReadonly]
private let service = GTLServiceCalendar()
let output = UITextView()
// When the view loads, create necessary subviews
// and initialize the Google Calendar API service
override func viewDidLoad() {
super.viewDidLoad()
if let auth = GTMOAuth2ViewControllerTouch.authForGoogleFromKeychainForName(
kKeychainItemName,
clientID: kClientID,
clientSecret: nil) {
service.authorizer = auth
}
}
// When the view appears, ensure that the Google Calendar API service is authorized
// and perform API calls
override func viewDidAppear(animated: Bool) {
if let authorizer = service.authorizer,
canAuth = authorizer.canAuthorize where canAuth {
fetchEvents()
} else {
presentViewController(
createAuthController(),
animated: true,
completion: nil
)
}
}
// Construct a query and get a list of upcoming events from the user calendar
func fetchEvents() {
let query = GTLQueryCalendar.queryForEventsListWithCalendarId("primary")
query.maxResults = 10
query.timeMin = GTLDateTime(date: NSDate(), timeZone: NSTimeZone.localTimeZone())
query.singleEvents = true
query.orderBy = kGTLCalendarOrderByStartTime
service.executeQuery(
query,
delegate: self,
didFinishSelector: "displayResultWithTicket:finishedWithObject:error:"
)
}
// Display the start dates and event summaries in the UITextView
func displayResultWithTicket(
ticket: GTLServiceTicket,
finishedWithObject response : GTLCalendarEvents,
error : NSError?) {
if let error = error {
showAlert("Error", message: error.localizedDescription)
return
}
var eventString = ""
if let events = response.items() where !events.isEmpty {
for event in events as! [GTLCalendarEvent] {
let start : GTLDateTime! = event.start.dateTime ?? event.start.date
let startString = NSDateFormatter.localizedStringFromDate(
start.date,
dateStyle: .ShortStyle,
timeStyle: .ShortStyle
)
eventString += "\(startString) - \(event.summary)\n"
// An array holding all my upcoming events
listOfEvents.append("\(startString) - \(event.summary)")
print(listOfEvents)
}
} else {
eventString = "No upcoming events found."
}
output.text = eventString
self.tableView.reloadData()
}
// Creates the auth controller for authorizing access to Google Calendar API
private func createAuthController() -> GTMOAuth2ViewControllerTouch {
let scopeString = scopes.joinWithSeparator(" ")
return GTMOAuth2ViewControllerTouch(
scope: scopeString,
clientID: kClientID,
clientSecret: nil,
keychainItemName: kKeychainItemName,
delegate: self,
finishedSelector: "viewController:finishedWithAuth:error:"
)
}
// Handle completion of the authorization process, and update the Google Calendar API
// with the new credentials.
func viewController(vc : UIViewController,
finishedWithAuth authResult : GTMOAuth2Authentication, error : NSError?) {
if let error = error {
service.authorizer = nil
showAlert("Authentication Error", message: error.localizedDescription)
return
}
service.authorizer = authResult
dismissViewControllerAnimated(true, completion: nil)
}
// Helper for showing an alert
func showAlert(title : String, message: String) {
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert
)
let ok = UIAlertAction(
title: "OK",
style: UIAlertActionStyle.Default,
handler: nil
)
alert.addAction(ok)
presentViewController(alert, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(self.listOfEvents.count)
return self.listOfEvents.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Events Cell", forIndexPath: indexPath) as UITableViewCell
var event = ""
event = listOfEvents[indexPath.row]
cell.textLabel?.text = event
return cell
}
}
I would appreciate any help and insight :-) Thanks so much!
After output.text = eventString, you should reload the tableview.

Apple - Provisioning profile + Push Notifications

I followed the guide on Parse.com on how to create a certificate and prepare a provisioning account to accept Push Notifications. When i go to Preferences/Accounts :
It shows on the bottom, but when i try to choose it from the Build Settings Tab, it doesn't show, and i always get this error : "no valid 'aps-environment' entitlement string found for application"
I tried this from scratch several times, using several Xcode & parse Apps, Please help me.
Appdelegate code :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
Parse.setApplicationId("MyAppId", clientKey: "MyAppClientKey")
var notificationType: UIUserNotificationType = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound
var settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationType, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
var currentInstallation: PFInstallation = PFInstallation()
currentInstallation.setDeviceTokenFromData(deviceToken)
currentInstallation.saveInBackground()
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println(error.localizedDescription)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
PFPush.handlePush(userInfo)
}
Have you added the device onto the Development Provisioning Profile, then download and installed it? I got that same error until the device was added.

Xcode , Parse.com - Push notifications don't show on my phone.

followed the guide on Parse.com on how to create a certificate and prepare a provisioning account to accept Push Notifications. When i go to Preferences/Accounts : It shows on the bottom, but when i try to choose it from the Build Settings Tab, it doesn't show, and i always get this error : "no valid 'aps-environment' entitlement string found for application"
My phone is recognised by the Parse app, and it sends notifications successfully, but my phone never receives them. I tried this from scratch several times, using several Xcode & Parse Apps.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
Parse.setApplicationId("MyAppId", clientKey: "MyAppClientKey")
var notificationType: UIUserNotificationType = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound
var settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationType, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
var currentInstallation: PFInstallation = PFInstallation()
currentInstallation.setDeviceTokenFromData(deviceToken)
currentInstallation.saveInBackground()
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println(error.localizedDescription)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
PFPush.handlePush(userInfo)
}
1) Did you allow push notifications from your app project?
2) Do you have the correct build identifiers set in parse and in your app?
I have another delegate method that I don't see in your post.
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings!)
{
UIApplication.sharedApplication().registerForRemoteNotifications()
}

Resources