Notification service extension for Local notification - swift

will system loads Notification service extension and calls its didReceive(_:withContentHandler:) for local notifications in iOS 10?
If yes how we can do that?

No. The accepted answer describes Notification Content Extensions, which allow you to present a ViewController in the expanded notification view, and works with both remote and local notification.
Notification Service Extensions, that let you change the content of the notification (attaching images, etc) do not work with local notifications. However, you can attach images as part of the process to show a local notification.

Notification Service extension is for remote notification not for local notification.
As per apple doc
UNNotificationServiceExtension
An object that modifies the content of a remote notification before it's delivered to the user.

You need to create a Notification Content Extension for displaying custom notification with iOS10. In the Xcode menu bar, go to File->New->Target. Then from the list select Notification Content Extension.
Enter the corresponding details and click Finnish. You will see a new folder with the name of your extension. In the folder, there will be 3 files :
NotificationViewController : Here you can design your custom interface and implement responses.
MainStoryboard : You can use this to design your custom notification.
Info.plist
In the Info.plist file, add the following:
This will be the category identifier you will use in your main project when scheduling notifications.
let category = UNNotificationCategory(identifier: "myNotificationCategory", actions: [], intentIdentifiers:[], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
content.categoryIdentifier = "myNotificationCategory"
Your NotificationViewController class should look something like this.
func didReceive(_ notification: UNNotification) {
//change properties of notification here.
}
func didReceive(_ response: UNNotificationResponse, completionHandler completion: #escaping (UNNotificationContentExtensionResponseOption) -> Void) {
//implement response logic here.
}
There are a couple of good tutorials available online. You can check here, here & here.
Hope this helps.

Notification Extension is supported for local notifications too. It is clearly mentioned here
UNNotificationContentExtension
An object that presents a custom interface for a delivered local or remote notification.

Related

Local Notification overrides previous local notification

I have a macOS Swift app where I am using local notifications. Here is a small methode for sending these:
func sendPushMessage(title: String, message: String, userInfo: [String:Any]) {
let notification: NSUserNotification = NSUserNotification()
notification.title = title
notification.informativeText = message
notification.userInfo = userInfo
notification.soundName = NSUserNotificationDefaultSoundName
notification.deliveryDate = Date()
self.center.scheduledNotifications = [notification]
}
This works for a long time and I have received all my notification (as well all notifications were shown in notification center). But actually the latest notification overrides the previous one. Let's say there is only one notification slot that always get overridenn with the latest notification.
In my notification center there is also only a single notification visible (the latest) instead of all received notifications. I have no idea when this "stops working" but I think one or two month ago? I am still on 10.13.6 high sierra.
The notification settings are correct.
I have no idea whatg I have done "wrong".
Fixed the issue by changing notification order (in notification settings) to manually by app and then it worked. After that I could change it back to newest and still working. Was only a bug in macOS for sure.
As refer documentation, you should set different identifier for each notification.
The identifier is unique to a notification. A notification delivered
with the same identifier as an existing notification replaces the
existing notification rather than causing the display of a new
notification.
You can set like that
notification.identifier = "yourIdentifier"

CloudKit CKShare userDidAcceptCloudKitShareWith Never Fires on Mac App

I am working on accepting a CKShare in a macOS app in Swift 4. I've already done all the following:
Create the CKShare and save it with its rootRecord to CloudKit
Add a participant (CKShare.Participant)
I've confirmed that the CKShare is on the CloudKit server and that the person I invited has access to it. Here's a screenshot: https://d.pr/i/0sMFQq
When I click the share link associated with the CKShare, it opens my app, but nothing happens and userDidAcceptCloudKitShareWith doesn't fire.
func application(_ application: NSApplication, userDidAcceptCloudKitShareWith metadata: CKShareMetadata) {
print("Made it!") //<-- This never gets logged :(
let shareOperation = CKAcceptSharesOperation(shareMetadatas: [metadata])
shareOperation.qualityOfService = .userInteractive
shareOperation.perShareCompletionBlock = {meta, share, error in
print("meta \(meta)\nshare \(share)\nerror \(error)")
}
shareOperation.acceptSharesCompletionBlock = { error in
if let error = error{
print("error in accept share completion \(error)")
}else{
//Send your user to where they need to go in your app
print("successful share:\n\(metadata)")
}
}
CKContainer.default().add(shareOperation)
}
Is there some kind of URL scheme I have to include in my info.plist? Or perhaps a protocol I need to conform to in my NSApplicationDelegate delegate? I can't, for the life of me, figure out what to do. Thanks in advance!
Update
I've tried a few more things on this. When I open the share link in a web browser, I see this:
Clicking OK makes the screen fade away to this:
Not particularly helpful. :) After doing this, the participant's status in CloudKit is still Invited, so the share still hasn't been accepted.
When I click on a share link within Messages, I am shown a popup like this:
After I click open, a new copy of my app shows up in the dock, then the app suddenly closes. The crash log states:
Terminating app due to uncaught exception 'CKException', reason: 'The application is missing required entitlement com.apple.developer.icloud-services'
I've tried turning iCloud off and on again in the Capabilities section of Xcode, but nothing changes. I know this exception can't be right because I can start my app normally and use CloudKit all day long. Only the CKShare causes this crash.
This is a mess. Save me, Obi-wan Kenobi, you're my only hope.
Yes,
You need to add this to your info.plist.
<key>CKSharingSupported</key>
<true/>
** EDITED ANSWER **
I use this code to share, I don't do it manually... not sure if this is an option under OS X I must confess. I am using iOS.
let share = CKShare(rootRecord: record2S!)
share[CKShareTitleKey] = "My Next Share" as CKRecordValue
share.publicPermission = .none
let sharingController = UICloudSharingController(preparationHandler: {(UICloudSharingController, handler:
#escaping (CKShare?, CKContainer?, Error?) -> Void) in
let modifyOp = CKModifyRecordsOperation(recordsToSave:
[record2S!, share], recordIDsToDelete: nil)
modifyOp.savePolicy = .allKeys
modifyOp.modifyRecordsCompletionBlock = { (record, recordID,
error) in
handler(share, CKContainer.default(), error)
}
CKContainer.default().privateCloudDatabase.add(modifyOp)
})
sharingController.availablePermissions = [.allowReadWrite,
.allowPrivate]
sharingController.delegate = self
sharingController.popoverPresentationController?.sourceView = self.view
DispatchQueue.main.async {
self.present(sharingController, animated:true, completion:nil)
}
This presents an activity controller in which you can choose say email and then send a link. You might also want to watch this video, focus on cloudKit JS right at the beginning.
Watch this WWDC video too https://developer.apple.com/videos/play/wwdc2015/710/
It talks about the cloudkit JSON API, using it you can query what has and what hasn't been shared in a terminal window/simple script perhaps. I did the same when using dropbox API a few years back. Hey you can even use the cloudkit JSON API within your code in place of the native calls.
I finally got it to work! I did all of the following:
Deleted my app from ~/Library/Developer/Excode/DerivedData
Made sure I had no other copies of my app archived anywhere on my machine.
Said a prayer.
Rebooted.
Sheesh, that was rough. :)
If your app is a Mac Catalyst app running on any version of macOS Catalina at least up to and including 10.15.4 Beta 1, a UIApplicationDelegate userDidAcceptCloudKitShareWith method will never be invoked.
After some significant debugging, we discovered that the MacCatalyst UIKit doesn’t even have an implementation for userDidAcceptCloudKitShareWithMetadata in its UIApplication delegate. It’s not broken, it’s just not there. So, at least temporarily, our workaround is the following, which seems to work, even if it’s very inelegant:
// Add CloudKit sharing acceptance handling to UINSApplicationDelegate, which is missing it.
#if targetEnvironment(macCatalyst)
extension NSObject {
#objc func application(_ application: NSObject, userDidAcceptCloudKitShareWithMetadata cloudKitShareMetadata: CKShare.Metadata) {
YourClass.acceptCloudKitShare(cloudKitShareMetadata: cloudKitShareMetadata)
}
}
#endif
If you are using a SceneDelegate, implement the delegate callback there, instead of on AppDelegate.
func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) {
// ...
}
You need to create the app delegate for your SwiftUI app using #NSApplicationDelegateAdaptor:
#main
struct Sharing_ServiceApp: App
{
#NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene
{
WindowGroup
{
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
I put that line in and my code instantly started receiving the share requests.

iOS 10 Notification Content Extension not loading

I have a bare-bones app to play with push notifications. I have the Notification Service Extension working. I can send a remote notification with an image URL and have it load.
I can't seem to get Notification Content Extension working. I've gone through multiple tutorials and they all say, just create a Notification Content Extension from the target menu and then inside the Notification Content Extensions Info.plist set the
UNNotificationCategory
to some string. Then when you push the notification, inside the "aps" json-block make sure to have category the same as UNNotificationCategory.
When I receive a notification, I try to swipe it down, left or right and nothing really happens. However, the service extension is working great.
I am using an iPhone 5 with ios 10 and XCode 8.0. I read that at one point only devices with 3d touch could view the content extension but that has since changed since xCode 8 is out of beta.
Any ideas? How can I go about debugging this? I've tried running the app with the Notification Extension selected and printing out stuff inside
didReceive
but am not having any luck.
Make sure to set the Extension's deployment target to the same as your Application target.
Please check if you set the category identifier in your UNMutableNotificationContent() For e.g.
let content = UNMutableNotificationContent()
content.categoryIdentifier = "awesomeNotification"
where "awesomeNotification" is the identifier for your UNNotificationCategory
Such problem. iOS Content Extension work fine with iPhone 5s, SE, iPad2mini, but doesn't work with iPhoine 5, 5c:
UNUserNotificationCenter.current().supportsContentExtensions is false on iPhoine 5, 5c
Despite what I read elsewhere on stackoverflow and online, expanding the push notification did not work on an iPhone 5 and IOS 10. I borrowed an iPhone 6+ and my code worked fine.
For me it was due to changing signing certificates. I was able to resolve it by:
Deleting the app (and all apps in app group)
Restarting phone
Quitting Xcode
Cleaning project
Running again

Check a web page periodically in background

I need to check periodically a web page.
My idea is to set a local notification periodically, for example every 20 minutes. When notification leaves, device should load the web page, check a condition and if the condition is true, device should rang, otherwise nothing.
(NOTIFICATION) -> (LOAD WEB PAGE) -> [VERIFY CONDITION]-|if true|-> (RING)
Is this technically possible to do? How can I load a web page while app isn't running?
My sketch of code was like this:
func check () {
pageCode = // find a way to load the page
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_MSEC * 100))
dispatch_after(delayTime, dispatch_get_main_queue()){
let readCode = self.pageCode.stringByEvaluatingJavaScriptFromString("document.getElementsByTagName('body')[0].outerHTML")
if letturaCodice?.containsString("Some text") == true {
ringPhone()
}
}
}
Not possible using UILocalNotification, you could do it with a remote notification though.
Apple has a guide here: See - "Using Push Notifications to Initiate a Download"
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
A remote notification platform I've used before is called OneSignal, it's completely free and allows you to schedule notifications. https://onesignal.com
Edit:
Doesn't answer question about ringing, not sure about that bit sorry!
Option 1:
You could build the app to use background app refresh function that you could cause an alert if lets say you do not get an http status code of 200.
If you use this option you could build in the function to have a custom tone to play that you build into the app.
Option 2:
Use a server side script todo the checking and have it fire off a push notification. This method would depend on phone settings as to how the notification would function.
You can try to use Grand Central Dispatch to run a background process and inside it add notification observer.
UPD: Like this:
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
() -> Void in
// catch notifications here
}

Local Notification to be shown as Alert Type

I am using local notifications in my application. I want to show local notifications as Alert Type on iphone devices while it is displaying as Banner Type. I have also set the alert type of local notification that is not contains the null value. Please Suggest.
You can't change the way a Notification is presented by code, iOS handles the displaying the notifications.
Only the user can set the way a notification is presented from the settings app.