How to create multiple shortcuts at application start - ios

So what I am trying is to donate multiple shortcuts (like 20 types of activites) at app delegate...it is weird that it works if I donate in a specific view controller, but if I make a for loop in a app delegate it doesnt work...here is the code:
activity = NSUserActivity(activityType: activityType)
activity?.title = activityTitle
if #available(iOS 12.0, *) {
activity?.suggestedInvocationPhrase = suggestedPhrase
activity?.isEligibleForPrediction = true
activity?.persistentIdentifier = NSUserActivityPersistentIdentifier(activityType)
}
activity?.isEligibleForSearch = true
//self.activities.append(activity!)
if #available(iOS 12.0, *) {
NSUserActivity.deleteSavedUserActivities(withPersistentIdentifiers: [activityType], completionHandler: {[weak self] in
self?.activity?.becomeCurrent()
})
}

Appdelegate is the first thing that's run on app load, this can cause it not to load your shortcuts, consider running them from the first viewcontroller the app opens

Related

EKEventViewController wont show Edit Button on iOS 13

i got a simple app where i want to present an event within an EKEventViewController.
// the button action which validates if the event store access is granted and presents the given alert if true
#IBAction func actionButtonShowPopover(_ sender: Any) {
eventStore.requestAccess(to: .event) { (granted, _) in
guard granted else { return }
let event = self.generateAndSaveEvent()
self.presentEventViewController(withEvent: event)
}
}
// creates and tries to save an sample even and returns it
private func generateAndSaveEvent() -> EKEvent {
let event = EKEvent(eventStore: eventStore)
event.title = "Event Title"
event.startDate = Date()
event.endDate = Date().addingTimeInterval(1800)
event.calendar = eventStore.defaultCalendarForNewEvents
do {
try eventStore.save(event, span: .thisEvent)
} catch(let error) {
print(error)
}
return event
}
// displays an EKEventViewController with our newly created event within an popover
private func presentEventViewController(withEvent event: EKEvent) {
DispatchQueue.main.async {
let eventVC = EKEventViewController()
eventVC.event = event
eventVC.allowsEditing = true
eventVC.modalPresentationStyle = .popover
eventVC.popoverPresentationController?.sourceView = self.buttonShowPopover
eventVC.popoverPresentationController?.sourceRect = self.buttonShowPopover.frame.offsetBy(dx: 0, dy: -10)
eventVC.popoverPresentationController?.backgroundColor = .white
eventVC.popoverPresentationController?.permittedArrowDirections = .up
self.present(eventVC, animated: false, completion: nil)
}
}
i created an event as shown in the code above and simply displaying it within the popover view controller. since ios 13 i got a different result:
iOS 12.4 with edit button
iOS 13 without edit button
is there any chance i'm missing changes from iOS12 -> iOS13?
thanks upfront - i'm grateful for any advice!
Edit button has moved to navigation bar in iOS 13. You need to present it without popover style.
In my app, that's been around for a while, I was experiencing the same problem with the edit button no longer appearing in iOS13. Unlike other users, my EKEventViewController was already wrapped in a navigation controller, so it wasn't that issue.
Several hours of going down rabbit holes, I've found a fix. Here's where the problems were occurring in my app:
Debugging just before opening the view, the EKEvent object I was trying to edit didn't have a value set for .eventIdentifier. Reading into this, it seems this property is lazy loaded, so not being able to retrieve the value here suggests the link between the EKEvent and the EKStore I used to fetch it has been lost somewhere in the application lifecycle. This is a change that been introduced somewhere along the iOS/Swift upgrade journey - I can't pin down the change that has caused this.
By accessing the EKEvent.eventIdentifier at the time I first retrieved the EKEvent, I now had this identifier for later use
Before presenting the EKEventViewController, I fetch a fresh copy of this event and use the fresh event in the controller:
let freshEvent = store.event(withIdentifier: staleEvent.eventIdentifier)
eventViewController.event = freshEvent

Siri shortcuts work on iPhone, but not on HomePod

I’m working on app that uses Siri Shortcuts, and I’ve met one strange issue:
If I run a shortcut on iPhone, it works well. If I do the same with HomePod, connected to the same iPhone, I get “There is a problem with your app” from Siri. My shortcuts are created within the app.
if #available(iOS 12.0, *) {
let activity = NSUserActivity(activityType: command.rawValue)
activity.title = selectTitle(activityType: command)
activity.isEligibleForSearch = true
activity.isEligibleForPrediction = true
activity.persistentIdentifier = NSUserActivityPersistentIdentifier(command.rawValue)
responder.userActivity = activity
activity.becomeCurrent()
}
Any ideas how to make them work via HomePod?
Thanks in advance!

How to detect a call made using openUrl() is ended in ios

In my application, there is an option to make a call when the user taps a phone number. I'm implementing this as shown below:
if let url = URL(string:"tel://\(String(describing: Util.checkForNullString(contactNo)))"), UIApplication.shared.canOpenURL(url){
if #available(iOS 10, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
}
I want to do another action soon after the user finishes the call. But how to get notified when the call is finished ?

Add function for cancel in UIAlert of Phone Call function

I have a function that places a phone call when a button is pressed.
private func callNumber(phoneNumber:String) {
if let phoneCallURL = URL(string: "tel://\(phoneNumber)") {
let application:UIApplication = UIApplication.shared
if (application.canOpenURL(phoneCallURL)) {
application.open(phoneCallURL, options: [:], completionHandler: nil)
}
}
}
I want to add some functionality if the users hit cancel when the alert pops up to confirm the call. How would I do that?
According to this question: Prompt when trying to dial a phone number using tel:// scheme on iOS 10.3
This alert is actually a bug in iOS 10.3 and should be removed at some point in the future. It isn't supposed to come up for "tel:" links in native apps.
That said, I don't believe there is a way to detect the alert and how the user interacts with it.

Schedule and handle local notifications in iOS 10

I've been working on one of my project where I allow users to schedule multiple notifications at their desired time.
iOS 10 gave us the ability to use a DateComponents as the fire date for our notification but I'm kind of lost as to how I'm supposed to schedule and handle multiple notifications.
Each notification needs its own request which then in turn needs its own identifier else you cannot create multiple notifications.
I figured I had to work with the identifier to schedule and handle notifications, but now my code is such a mess that I've been seriously asking myself if there hasn't been an easier way of doing this.
According to my data model the notification unique identifier is composed of :
The id of my model
A number that increments each time a new notification is created
The above is separated by an underscore
So for example if I had to schedule 10 notifications for the object with the id 3 it would look like this : 3_1, 3_2, 3_3...
Every time I receive a notification I loop trough the received notifications to update my UI. And when the user desires to delete the received notifications for a specific model, I loop through the received notification's unique identifiers by checking the identifiers that starts with the same ID.
I don't really see how I could manage to do it otherwise because according to the documentation, the only way of deleting a delivered notification is by using the identifier : UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers:)
The thing is, it's creating all sort of problems and while I could easily correct them it looks very hacky. I'm not really proud of what I've done and I am looking for more clever ways of getting around it. I intentionally did not post any code because that's not the problem. The approach is the real problem.
I'm asking here because the UserNotifications framework is pretty new and I haven't been able to find ressources taking about this subject.
Any idea ? Thanks in advance.
Edit : Here's some code.
#available(iOS 10.0, *)
func checkDeliveredAndPendingNotifications(completionHandler: #escaping (_ identifierDictionary: Dictionary<String, Int>) -> ()) {
var identifierDictionary:[String: Int] = [:]
UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
for notification in notifications {
let identifierArraySplit = notification.request.identifier.components(separatedBy: "_")
if identifierDictionary[identifierArraySplit[0]] == nil || identifierDictionary[identifierArraySplit[0]]! < Int(identifierArraySplit[1])! {
identifierDictionary[identifierArraySplit[0]] = Int(identifierArraySplit[1])
}
}
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { (requests) in
for request in requests {
let identifierArraySplit = request.identifier.components(separatedBy: "_")
if identifierDictionary[identifierArraySplit[0]] == nil || Int(identifierArraySplit[1])! > identifierDictionary[identifierArraySplit[0]]! {
identifierDictionary[identifierArraySplit[0]] = Int(identifierArraySplit[1])
}
}
completionHandler(identifierDictionary)
})
}
}
#available(iOS 10.0, *)
func generateNotifications() {
for medecine in medecines {
self.checkDeliveredAndPendingNotifications(completionHandler: { (identifierDictionary) in
DispatchQueue.main.async {
self.createNotification(medecineName: medecine.name, medecineId: medecine.id, identifierDictionary: identifierDictionary)
}
})
}
}
#available(iOS 10.0, *)
func createNotification(medecineName: String, medecineId: Int identifierDictionary: Dictionary<String, Int>) {
let takeMedecineAction = UNNotificationAction(identifier: "TAKE", title: "Take your medecine", options: [.destructive])
let category = UNNotificationCategory(identifier: "message", actions: [takeMedecineAction], intentIdentifiers:[], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
let takeMedecineContent = UNMutableNotificationContent()
takeMedecineContent.userInfo = ["id": medecineId]
takeMedecineContent.categoryIdentifier = "message"
takeMedecineContent.title = medecineName
takeMedecineContent.body = "It's time for your medecine"
takeMedecineContent.badge = 1
takeMedecineContent.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: false)
var takeMedecineIdentifier = ""
for identifier in identifierDictionary {
if Int(identifier.key) == medecineId {
let nextIdentifierValue = identifier.value + 1
takeMedecineIdentifier = String(medecineId) + "_" + String(nextIdentifierValue)
}
}
let takeMedecineRequest = UNNotificationRequest(identifier: takeMedecineIdentifier, content: takeMedecineContent, trigger: trigger)
UNUserNotificationCenter.current().add(takeMedecineRequest, withCompletionHandler: { (error) in
if let _ = error {
print("There was an error : \(error)")
}
})
}
In the checkDeliveredAndPendingNotifications method, I loop through all the pending and delivered notifications, so later on I can create an identifier that does not exist already. I haven't found another way to generate unique identifiers for each notification.
As most of the work is done on another async queue, I've also created a completion handler when he has finished its job. I then call the createNotification method on the main thread (because I'm using Realm, and I'm obliged too do this) which should create a notification.
The problem here is the func add(UNNotificationRequest, withCompletionHandler: (Error?) -> Void)? = nil) method which is also doing work asynchronously. So when I go back to my loop in generateNotifications the checkDeliveredAndPendingNotifications return incorrect data. Well not incorrect it's just that the notification hasn't been created yet...
I'm a total noob with threading and I'm stuck with these kind of operations and I don't know where to go. I'm not sure I'm approaching the problem the right way.
You can get all notification and set/Delete as you need. Have a look on this accepted answer for both Objc c and swift.
How to schedule a local notification in iOS 10 (objective-c)

Resources