当应用程序未运行并点击推送通知时如何调试远程推送通知?

问题描述 投票:0回答:4

当应用程序运行并收到推送通知时,会调用 didReceive 。

func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    )

因此,当调用上述委托时,我会使用收到的有效负载呈现一个屏幕。这里没有问题。

当应用程序未运行并且用户点击通知时,它应该显示与上面相同的屏幕。它不起作用,因为我没有在 didFinishLaunchingWithOptions 中添加代码。

所以,然后我添加了以下代码-

func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
         ......        
    
            
        if let userInfo = launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] {
         ......
        }
        
        return true
    }

但这不起作用,我无法调试,因为在调试模式下,我必须从后台终止应用程序并点击通知,但在这种情况下,调试器将无法工作。我尝试了替代方法,即显示警报,但警报也不起作用

let aps = remoteNotif["aps"] as? [AnyHashable: Any]
            let string = "\n Custom: \(String(describing: aps))"
            let string1 = "\n Custom: \(String(describing: remoteNotif))"

            DispatchQueue.main.asyncAfter(deadline: .now() + 5) { [weak self] in
                if var topController = application.windows.first?.rootViewController {
                    while let presentedViewController = topController.presentedViewController {
                        topController = presentedViewController
                    }

                    let ac = UIAlertController(title: string1, message: string, preferredStyle: .alert)
                    ac.addAction(UIAlertAction(title: "OK", style: .default))
                    topController.present(ac, animated: true)
                }
            }

我该如何解决这个问题?

ios swift push-notification appdelegate
4个回答
5
投票

“但在这种情况下调试器将无法工作”不是真的!即使 Xcode 没有启动它,您也可以在启动时附加调试器。

编辑方案,然后在“运行”操作中的“信息”下,显示“启动”,单击第二个单选按钮:“等待可执行文件启动。”运行应用程序;它没有启动。现在通过推送通知启动应用程序。调试器可以工作。


3
投票

我已经通过实现 sceneDelegate

willConnectTo
方法解决了这个问题。 didFinishLaunchingWithOptions 中无需处理

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
//Remote notification response
   if let response = connectionOptions.notificationResponse{
        print(response.notification.request.content.userInfo)
   }

   ....
} 

这就够了


0
投票

您必须创建一个NotificationServiceExtension并在那里处理有效负载

在 XCode 中,

  1. 选择您的项目
  2. 从左下角选择添加目标
  3. 添加通知服务扩展

然后尝试做这样的事情。以下代码适用于 FCM,但您可以根据自己的负载进行修改。

例如-

import UserNotifications
import UIKit

class NotificationService: UNNotificationServiceExtension {
    
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            // Modify the notification content here...
            bestAttemptContent.title = "\(bestAttemptContent.title)"
            
            guard let fcmOptions = bestAttemptContent.userInfo["fcm_options"] as? [String: Any] else {
                contentHandler(bestAttemptContent)
                return
            }
            
            guard let imageURLString = fcmOptions["image"] as? String else {
                contentHandler(bestAttemptContent)
                return
            }
            
            getMediaAttachment(for: imageURLString) { [weak self] (image, error) in
                guard let self = self,
                      let image = image,
                      let fileURL = self.saveImageAttachment(image: image, forIdentifier: "attachment.png")
                else {
//                    bestAttemptContent.body = "Error - \(String(describing: error))"
                    contentHandler(bestAttemptContent)
                    return
                }
                
                let imageAttachment = try? UNNotificationAttachment(
                    identifier: "image",
                    url: fileURL,
                    options: nil)
                
                if let imageAttachment = imageAttachment {
                    bestAttemptContent.attachments = [imageAttachment]
                }
                
                contentHandler(bestAttemptContent)
            }
        }
        
    }
    
    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
    
    private func saveImageAttachment(image: UIImage, forIdentifier identifier: String) -> URL? {
        let tempDirectory = URL(fileURLWithPath: NSTemporaryDirectory())
        
        let directoryPath = tempDirectory.appendingPathComponent(
            ProcessInfo.processInfo.globallyUniqueString,
            isDirectory: true)
        
        do {
            try FileManager.default.createDirectory(
                at: directoryPath,
                withIntermediateDirectories: true,
                attributes: nil)
            
            let fileURL = directoryPath.appendingPathComponent(identifier)
            
            guard let imageData = image.pngData() else {
                return nil
            }
            
            try imageData.write(to: fileURL)
            return fileURL
        } catch {
            return nil
        }
    }
    
    private func getMediaAttachment(for urlString: String, completion: @escaping (UIImage?, Error?) -> Void) {
        guard let url = URL(string: urlString) else {
            completion(nil, NotificationError.cannotParseURL)
            return
        }
        
        ImageDownloader.shared.downloadImage(forURL: url) { (result) in
            switch result {
            case .success(let image):
                completion(image, nil)
            case .failure(let error):
                completion(nil, error)
            }
        }
    }
    
}


enum NotificationError: Error {
    case cannotParseURL
}

0
投票

将您的启动从自动更改为等待可执行文件启动,您应该能够在应用程序未运行时调试通知。

© www.soinside.com 2019 - 2024. All rights reserved.