How to show Arabic text in notification? [closed] - swift

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I am getting FCM push notification in both languages English/Arabic but I want to show it only in Arabic, How to show this?
My Code-
#available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
if let jsonResult = userInfo as? Dictionary<String, AnyObject> {
if let notifyType = jsonResult["type"] as? String {
if notifyType == "8" || notifyType == "18" {
self.pushRedirection(userInfo: userInfo)
}else{
if let league_id = jsonResult["league_id"] as? String {
if let contestUnique_id = jsonResult["contest_unique_id"] as? String {
}
}
}
}
}
completionHandler([.alert,.sound])
}
I am getting this notification in English(Match Reminder). How to set this in Arabic
My notification data is -
[AnyHashable("gcm.notification.type"): 5, AnyHashable("league_id"): 3, AnyHashable("en_msg"): Match Reminder, AnyHashable("gcm.notification.ar_msg"): القوانين, AnyHashable("gcm.notification.en_msg"): Match Reminder, AnyHashable("gcm.notification.league_id"): 3, AnyHashable("contest_unique_id"): KBm8oVuTR, AnyHashable("gcm.message_id"): 0:1528974245362555%6c5fd9d06c5fd9d0, AnyHashable("gcm.notification.contest_unique_id"): KBm8oVuTR, AnyHashable("ar_msg"): القوانين, AnyHashable("google.c.a.e"): 1, AnyHashable("type"): 5, AnyHashable("aps"): {
alert = "Match Reminder";
}, AnyHashable("body"): Match Reminder]

You need to write a notification service extension. That will allow you to modify the notification's payload prior to display.
As the docs say:
A UNNotificationServiceExtension object ... lets you customize the content of a remote notification before it is delivered to the user.
And that is exactly what you are wishing to do.

Related

How do I set a value on NSUserActivity from my Complication to open the correct view in my Watch app

In my ComplicationController, I'm creating my descriptor with an NSUserActivity object:
class ComplicationController: NSObject, CLKComplicationDataSource {
// MARK: - Complication Configuration
let data = MyData.shared
var dataDict: Dictionary<AnyHashable, Any> = ["character": "nil"]
func getComplicationDescriptors(handler: #escaping ([CLKComplicationDescriptor]) -> Void) {
let userActivity = NSUserActivity(activityType: "com.myapp")
userActivity.userInfo = dataDict
let descriptors = [
CLKComplicationDescriptor(
identifier: "myapp.extralarge",
displayName: "MyApp",
supportedFamilies: [CLKComplicationFamily.extraLarge],
userActivity: userActivity)
]
// Call the handler with the currently supported complication descriptors
handler(descriptors)
}
In my ExtensionDelegate, I can detect that the complication has been tapped and use Notification Center to send a message to my Watch App as follows:
func handle(_ userActivity: NSUserActivity) {
if let date = userActivity.userInfo?[CLKLaunchedTimelineEntryDateKey] as? Date {
// Handoff from complication
NotificationCenter.default.post(
name: Notification.Name.complicationTapped,
object: date
)
}
I can detect the timeline entry date using the CLKLaunchedTimelineEntryDateKey. How do I detect what data was being presented by the complication? I can't find where to set a key on the NSUserActivity object.

Badge variable is missing in my FCM notification in Swift

I am receiving notifications in my app using FCM but i am unable to show badge count on my app icon since there seems to be missing variables in my notification. how can i add this?
Below is the error i am getting
[AnyHashable("icon"): logo.png, AnyHashable("user_id"): 3, AnyHashable("google.c.sender.id"): 938224596608, AnyHashable("aps"): {
alert = {
body = "You have new message! Check in the app.";
title = Tutil;
};
sound = default;
}, AnyHashable("google.c.a.e"): 1, AnyHashable("body"): You have new message! Check in the app., AnyHashable("user_photo"): images/3.png, AnyHashable("type"): message, AnyHashable("gcm.message_id"): 1604897386664267, AnyHashable("title"): Tutil, AnyHashable("user_name"): Mali, AnyHashable("lessons"): []]
Below is my code
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
print("%#", userInfo)
// Print message ID.
let content = notification.request.content
let badgeCount = content.badge as! Int //<<i am getting my error here as variables may not be available
incrementBadgeNumberBy(badgeNumberIncrement: badgeCount)
completionHandler([.alert,.badge,.sound])
}
You can get badge like this
if let aps = userInfo["aps"] as? Dictionary<String, Any>, let badge = aps["badge"] as? Int {
print(badge)
}

Trying to customize notifications in macOS with Swift

I am using macOS 10.5.6 and I am trying to display a custom notification. I am using UNNotificationAction to set up a drop down menu for the notification and UNNotificationCategory to save it. I can get the notification correctly. The title and body are displayed but the popup menu for the notification is displayed under a button labeled "Actions".
What I would like to happen is have the label "Actions" changed to a two button format the way that the Reminders app does. I have spent a couple of days searching this web site and several others trying to find the answer but all I have found is the method I am currently using to set up the notification with out the button format that I would like to display. I know that it can be done I just do not know which key words to use to get the answer I would appreciate any help I can get.
enter image description here
Sample notifications
A notification with an attachment:
A notification with an attachment, mouse is hovering over to make the action buttons visible (they're visible right away if there's no attachment).
Sample project
Delegate
AppDelegate is going to handle notifications in the following sample project. We have to make it conform to the UNUserNotificationCenterDelegate protocol.
import UserNotifications
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate {
...
}
We have to set the UNUserNotificationCenter.delegate to our AppDelegate in order to receive notifications. It must be done in the applicationDidFinishLaunching: method.
func applicationDidFinishLaunching(_ aNotification: Notification) {
setupNotificationCategories() // See below
UNUserNotificationCenter.current().delegate = self
// Other stuff
}
Authorization, capabilities, ... omitted for simplicity.
Constants
An example how to avoid hardcoded constant.
enum Note {
enum Action: String {
case acceptInvitation = "ACCEPT_INVITATION"
case declineInvitation = "DECLINE_INVITATION"
var title: String {
switch self {
case .acceptInvitation:
return "Accept"
case .declineInvitation:
return "Decline"
}
}
}
enum Category: String, CaseIterable {
case meetingInvitation = "MEETING_INVITATION"
var availableActions: [Action] {
switch self {
case .meetingInvitation:
return [.acceptInvitation, .declineInvitation]
}
}
}
enum UserInfo: String {
case meetingId = "MEETING_ID"
case userId = "USER_ID"
}
}
Setup categories
Make the notification center aware of our custom categories and actions. Call this function in the applicationDidFinishLaunching:.
func setupNotificationCategories() {
let categories: [UNNotificationCategory] = Note.Category.allCases
.map {
let actions = $0.availableActions
.map { UNNotificationAction(identifier: $0.rawValue, title: $0.title, options: [.foreground]) }
return UNNotificationCategory(identifier: $0.rawValue,
actions: actions,
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: "",
options: .customDismissAction)
}
UNUserNotificationCenter.current().setNotificationCategories(Set(categories))
}
Create a notification content
Sample notification content with an attachment. If we fail to create an
attachment we will continue without it.
func sampleNotificationContent() -> UNNotificationContent {
let content = UNMutableNotificationContent()
content.title = "Hey Jim! Weekly Staff Meeting"
content.body = "Every Tuesday at 2pm"
content.userInfo = [
Note.UserInfo.meetingId.rawValue: "123",
Note.UserInfo.userId.rawValue: "456"
]
content.categoryIdentifier = Note.Category.meetingInvitation.rawValue
// https://developer.apple.com/documentation/usernotifications/unnotificationattachment/1649987-init
//
// The URL of the file you want to attach to the notification. The URL must be a file
// URL and the file must be readable by the current process. This parameter must not be nil.
//
// IOW We can't use image from the assets catalog. You have to add an image to your project
// as a resource outside of assets catalog.
if let url = Bundle.main.url(forResource: "jim#2x", withExtension: "png"),
let attachment = try? UNNotificationAttachment(identifier: "", url: url, options: nil) {
content.attachments = [attachment]
}
return content
}
Important: you can't use an image from the assets catalog, because you need an URL pointing to a file readable by the current process.
Trigger helper
Helper to create a trigger which will fire a notification in seconds seconds.
func triggerIn(seconds: Int) -> UNNotificationTrigger {
let currentSecond = Calendar.current.component(.second, from: Date())
var dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
dateComponents.second = (currentSecond + seconds) % 60
return UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
}
Notification request
let content = sampleNotificationContent()
let trigger = triggerIn(seconds: 5)
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
if error != nil {
print("Failed to add a notification request: \(String(describing: error))")
}
}
Handle notifications
Following functions are implemented in the sample project AppDelegate.
Background
This is called when your application is in the background (or even if your application is running, see Foreground below).
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler:
#escaping () -> Void) {
guard let action = Note.Action(rawValue: response.actionIdentifier) else {
print("Unknown response action: \(response.actionIdentifier)")
completionHandler()
return
}
let userInfo = response.notification.request.content.userInfo
guard let meetingId = userInfo[Note.UserInfo.meetingId.rawValue] as? String,
let userId = userInfo[Note.UserInfo.userId.rawValue] as? String else {
print("Missing or malformed user info: \(userInfo)")
completionHandler()
return
}
print("Notification response: \(action) meetingId: \(meetingId) userId: \(userId)")
completionHandler()
}
Foreground
This is called when the application is in the foreground. You can handle the notification silently or you can just show it (this is what the code below does).
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
#escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
iOS customization
There's another way how to customize the appearance of notifications, but this is not available on the macOS. You have to use attachments.

watchOS, not receiving remote notifications

I am developing app on WatchOS 6 but I cannot receive remote notification
Here is my registration code for push notifications in ExtensionDelegate I am getting valid device token.
extension ExtensionDelegate {
func setupRemoteNotifications() {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
print("[WATCH PUSH NOTIFICATIONS] Permission granted: \(granted)")
guard granted else {
DispatchQueue.main.async {
self.showNotificationsNotGrantedAlert()
return
}
return
}
self.getNotificationSettings()
}
}
private func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
print("[WATCH PUSH NOTIFICATIONS] Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
WKExtension.shared().registerForRemoteNotifications()
self.onRemoteNotificationRegistration()
}
}
}
private func onRemoteNotificationRegistration() { }
func didRegisterForRemoteNotifications(withDeviceToken deviceToken: Data) {
// Convert token to string
let deviceTokenString = deviceToken.map { data in String(format: "%02.2hhx", data) }.joined()
print("[WATCH PUSH NOTIFICACTIONS] Device Token: \(deviceTokenString)")
UserSettings.shared.deviceToken = deviceTokenString
}
func didFailToRegisterForRemoteNotificationsWithError(_ error: Error) {
print("[WATCH PUSH NOTIFICATIONS] Failed to register device: \(error)")
UserSettings.shared.deviceToken = nil
}
func didReceiveRemoteNotification(_ userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (WKBackgroundFetchResult) -> Void) {
print("[WATCH PUSH NOTIFICATIONS] Push notification received: \(userInfo)")
let aps = userInfo["aps"] as! [String: AnyObject]
completionHandler(.noData)
}
}
extension ExtensionDelegate: UNUserNotificationCenterDelegate {
// show notification also when in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("[WATCH PUSH NOTIFICATION] Will present notification...")
let categoryIdentifier = notification.request.content.categoryIdentifier
let category = NotificationCategory(rawValue: categoryIdentifier)
if category == NotificationCategory.NotificationCategory {
} else if category == NotificationCategory.ActivityCategory {
}
completionHandler([.alert, .badge, .sound])
}
// called when tapped onto notification banner
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("[WATCH PUSH NOTIFICATION] Did receive notification response")
let userInfo = response.notification.request.content.userInfo as! [String: AnyObject]
let aps = userInfo["aps"] as! [String: AnyObject]
let categoryIdentifier = response.notification.request.content.categoryIdentifier
let category = NotificationCategory(rawValue: categoryIdentifier)
if category == NotificationCategory.NotificationCategory {
} else if category == NotificationCategory.ActivityCategory {
}
handleNotificationAction(response.actionIdentifier)
openNotification(userInfo: userInfo)
completionHandler()
}
}
extension ExtensionDelegate {
private func handleNotificationAction(_ actionIdentifier: String) {
let action = NotificationAction(rawValue: actionIdentifier)
if action == NotificationAction.Call {
print("Action: Call handled!")
} else if action == NotificationAction.Email {
print("Action: Email handled!")
} else if action == NotificationAction.Message {
print("Action: Message handled!")
}
}
private func openNotification(userInfo: [String: AnyObject]) {
// let something = userInfo["something"] ...
}
}
extension ExtensionDelegate {
private func showNotificationsNotGrantedAlert() {
let settingsActionTitle = NSLocalizedString("Settings", comment: "")
let cancelActionTitle = NSLocalizedString("Cancel", comment: "")
let message = NSLocalizedString("You need to grant a permission from notification settings.", comment: "")
let title = NSLocalizedString("Push Notifications Off", comment: "")
let settingsAction = WKAlertAction(title: settingsActionTitle, style: .default) {
print("[WATCH PUSH NOTIFICATIONS] Go to Notification Settings")
}
let cancelAction = WKAlertAction(title: cancelActionTitle, style: .cancel) {
print("[WATCH PUSH NOTIFICATIONS] Cancel to go to Notification Settings")
}
WKExtension.shared().rootInterfaceController?.presentAlert(withTitle: title, message: message, preferredStyle: .alert, actions: [settingsAction, cancelAction])
}
}
I've added Push notification Entitlement in WatchExtensions
I am sending notification from Push Notification Tester app using valid TeamId, P8 cert, P8 key, bundle Id -> where I am getting success.
I am sending default test notification nothing special
{
"aps": {
"alert": {
"title": "Silver Salmon Creek",
"body": "You are within 5 miles of Silver Salmon Creek."
},
"category": "Notification"
}
}
I have similar code for iOS and there notification are delivered correctly on iPhone.
UPDATE
I've tested a little bit more
And I have application added to my iPhone app
but iPhone app is for iOS 13
and Watch app is for WatchOS 6
So as I understand this WatchOS app can be install as standalone application.
I have checked "Support running without iOS App installation"
So as I understand my server should send this notification to both
Watch device Token and iOS device token. And there APNS/iOS/watchOS take the decision if there is duplicated notification where to deliver this notification i.e. to iPhone / watchOS.
If there is only watchOS app I think it will be delivered to watch Device token
If there is both watch/iOS app then it will send to iOS and then device whether user is using iPhone/Watch in given moment and deliver it to currently used device.
So now if I send notification to iPhone device token with iOS bundle identifier, and have locked iPhone and watch on wrist I am getting notification on my WatchOS and even can look at long notifications with dynamic content.
But when I've uninstall iOS version of application, and send notification with iPhone or watch device token and appropriate bundle id iOS/watchOS then for standalone app I am not getting this notification delivered again.
I encountered a similar issue, be sure your p8 Bundle ID is using the explicit WatchkitApp ID and not the Extension's ID.
Once I dropped the .watchkitextension and uninstalled (the app), reinstalled, reregistered the device, it worked.
I found the issue. It was related with the way Push Notification is send from the server using node-apns. I also have old Push Notification Tester app. 3.0 version of node-apns is required. there is additonal Header field send to APNS server
apns-push-type

UNNotificationContent userInfo is empty when handling response but correct when request is made

I am building a Desktop Cocoa App. When the user clicks a button, if a resource is successfully downloaded, the application sends a local notification to the user. When the user click's the notification, I want to open the URL to the source of the downloaded resource. I am attempting to store the URL in the userInfo dictionary in UNMutableNotificationContent with an integer key.
I can see that the content is there before the notification request is added: [AnyHashable(0): "https://stackoverflow.com/questions/ask"], but it is empty in the delegate's handler: [:]
// helper method to create the notification
func notify(userInfo: [AnyHashable : Any] = [:]) {
let uid = UUID().uuidString
let content = UNMutableNotificationContent()
content.title = self.title
content.userInfo = userInfo
content.sound = UNNotificationSound.default
print("add notification userInfo \(content.userInfo)")
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: uid, content: content, trigger: trigger)
center.add(request) { (error) in
print("add notification error \(error)")
}
}
// notification click handler
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("recieved notification userInfo: \(response.notification.request.content.userInfo)")
}
This is the only place notifications are being created, and I've verified that the request identifiers match.
notify() caller example
if let url = URL(string: "https://stackoverflow.com/questions/ask") {
notificationDelegate.notify(userInfo: [0: url.absoluteString])
}
The documentation for UNNotificationContent's userInfo property notes that the keys must be property list types. This means that they have to be one of a short list of types that are directly storable in a property list. Scalar-like types in this list include NSNumber, NSString, and NSDate.
The literal Swift Int 0 that you're using as a key should, as far as I know, be automatically bridged to NSNumber and therefore be legal as a key. It seems that is not happening.
You will have to use one of those plist types directly. If you want a number as a key, 0 as NSNumber ought to work (hopefully?), or NSNumber(value: 0). More commonly, I think, the key would be a string.
I think this is worth filing a radar about, especially since a Swift String apparently is bridged correctly and automatically (to an NSString). (An exception from the ObjC side to let us know that the dictionary can't be encoded, rather than silent disappearance, would also be nice...)