小弟在使用RealmSwift搭配Notification Service Extension,碰上了一些問題。
首先,我使用了FCM推播訊息到我的ios設備,我需要儲存我的推播通知到ios設備(使用Realm)
只有兩種情況可以儲存成功
1.app執行中 2.app關閉,點擊橫幅通知
我希望能在app關閉或背景運作中也可以儲存
所以我做了以下這些步驟
1.增加 Notification Service Extension
2.Enable Background fetch/Remote notifications
3.專案與 Notification Service Extension add 到同一個 app groups
並且我更改了Realm的路徑,我在AppDelegates.swift 中增加了以下的code,在NotificationService.swift也加入同樣的code
像這樣
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
當我在每一個要存取Realm的地方都加上這段,問題就出現了!
app關閉後可以成功儲存訊息,但是不穩定,大約10封通知會成功5封,而且原本app執行中與點擊橫幅通知儲存的功能也失效了。
資料表設定
import Foundation
import RealmSwift
class Order: Object {
@objc dynamic var id = UUID().uuidString
@objc dynamic var name = ""
@objc dynamic var amount = ""
@objc dynamic var createDate = Date()
override static func primaryKey() -> String? {
return "id"
}
}
import UIKit
import RealmSwift
class RealmDao: NSObject {
static let shared = RealmDao()
private var realm: Realm!
private override init() {
self.realm = try! Realm()
}
func getRealmObject() -> Realm {
return self.realm
}
}
處理推播訊息的 AppDelegate.swift
let realm = try! Realm()
let order: Order = Order()
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
////share Realm
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
tainerURL(forSecurityApplicationGroupIdentifier: "group.myapp")
FirebaseApp.configure()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
Messaging.messaging().delegate = self // For iOS 10 data message (sent via FCM)
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("ok...")
} else {
print("no...")
}
})
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
let userInfo = notification.request.content.userInfo
print("userInfo: \(userInfo)")
guard
let aps = userInfo[AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let body = alert["body"] as? String,
let title = alert["title"] as? String
else {
// handle any error here
return
}
print("Title: \(title) \nBody:\(body)")
order.name = title
order.amount = body
try! realm.write {
realm.add(order)
}
completionHandler([.badge, .sound, .alert])
}
NotificationService.swift 全部(處理app關閉下的推播通知)
import UserNotifications
import Firebase
import UIKit
import RealmSwift
import Realm
class NotificationService: UNNotificationServiceExtension {
let realm = try! Realm()
let order: Order = Order()
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
let sharedDirectory: URL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myapp")! as URL
let sharedRealmURL = sharedDirectory.appendingPathComponent("db.realm")
Realm.Configuration.defaultConfiguration = Realm.Configuration(fileURL: sharedRealmURL)
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
let message = request.content.userInfo
print("userInfo: \(message)")
guard
let aps = message[AnyHashable("aps")] as? NSDictionary,
let alert = aps["alert"] as? NSDictionary,
let title = alert["body"] as? String,
let body = alert["title"] as? String
else {
// handle any error here
return
}
print("Title: \(title) \nBody:\(body)")
order.name = title
order.amount = body
try! realm.write {
realm.add(order)
}
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.body = "\(bestAttemptContent.body) [fortest]"
contentHandler(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
後來有做一些測試,當我把更改路徑的code刪掉,原本執行中儲存的訊息竟然有被保存下來(不同資料表,一個原始路徑,一個更改過後的路徑)
意思就是,當我更改路徑後,
關閉app的推播訊息有存到新的路徑(當前viewtable顯示新路徑的資料表)
執行中的app推播訊息也有儲存,但是存到舊的路徑(所以在當前的view沒有顯示)
把路徑改回來後(viewtable顯示原本路徑的資料表)剛剛沒有顯示的資料通通都顯示了,所以我誤認他沒有被儲存,小弟不知道為什麼會有這種情況產生,麻煩有經驗的高手告訴小弟該怎麼修改,感激萬分!