简体   繁体   English

通过“推送通知”从“终止”状态打开应用程序时,iOS Web View App崩溃

[英]iOS Web View App crashed when Application is open from kill state through Push Notification

My app is crash when open from kill state through Push Notification . 通过Push Notification从终止状态打开时,我的应用程序崩溃。 It works good if app is launched already but when app is killed then if got any push notification and I tap on it, it crash the app. 如果已启动应用程序,则效果很好,但是当应用程序被终止时,如果收到任何推送通知,而我点击它,它会使应用程序崩溃。 I did not find any error, can any one help me to solve this? 我没有发现任何错误,有人可以帮助我解决此问题吗?

If I comment then UNUserNotificationCenter code from didFinishLaunchingWithOptions in AppDelegate.swift then app not crashing but then view is not loaded against notification. 如果我的评论则UNUserNotificationCenter从代码didFinishLaunchingWithOptionsAppDelegate.swift然后点击App没有崩溃,但随后的观点并没有加载针对通知。 I send the url in push notification and check it not blank then load it as view. 我在推式通知中发送该URL,并检查它是否为空,然后将其加载为视图。

AppDelegate.swift AppDelegate.swift

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?
    var apiUrl = "http://www.example.com/api/";

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        // Device Registration with API
        deviceRegistration(token)
        //print("Token: \(token)")
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {

    }

    // Device Registration with API 
    func deviceRegistration(_ token: String) {
        let parameters = ["UUID": UIDevice.current.identifierForVendor!.uuidString, "Token": token, "DevOption": "Dev", "MID": "0"]
        let url = URL(string: apiUrl + "ios-register")!

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: [])
        request.httpBody = httpBody

        let session = URLSession.shared.dataTask(with: request) { (data, response, error) in
            if let data = data {
                do {
                    let json = try JSONSerialization.jsonObject(with: data, options: [])
                    print(json)
                } catch {
                }
            }
        }
        session.resume()
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .sound])
    }

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

        // Check User Tap the notification
        if let notification = response.notification.request.content.userInfo as? [String: AnyObject] {
            let message = parseRemoteNotification(notification: notification)

            guard let url = message?["url"] as? String else {
                return;
            }
            // If url exists then load the url
            if !(url.isEmpty) {
                loadView(url)
            }
        }
        completionHandler()
    }

    private func parseRemoteNotification(notification:[String:AnyObject]) -> NSDictionary? {
        if let aps = notification["aps"] as? [String:AnyObject] {
            let alert = aps["alert"] as? NSDictionary
            return alert
        }
        return nil
    }

    func loadView(_ url: String) {
        let data: [String: String] = ["url": url]
        NotificationCenter.default.post(name: NSNotification.Name("loadWebView"), object: nil, userInfo: data)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        if let sb = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView {
            sb.backgroundColor = UIColor.init(red: 252/255, green: 153/255, blue: 0/255, alpha: 1)
        }

        // Local Notification
        //if(application.applicationState == .active) {
            UNUserNotificationCenter.current().delegate = self
            UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
                //print("Granted: \(granted)")
            }
        //}

        // Push Notifications
        UIApplication.shared.registerForRemoteNotifications()

        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }


}

ViewControllwer.swift ViewControllwer.swift

import UIKit
import WebKit
import UserNotifications

class ViewController: UIViewController, WKNavigationDelegate {

    @IBOutlet var mWebKit: WKWebView!
    @IBOutlet var indicator: UIActivityIndicatorView!

    public var defaultUrl = "https://www.example.com";
    public var viewUrl = URL(string: "https://www.example.com")!

    override func viewDidLoad() {
        super.viewDidLoad()

        mWebKit.navigationDelegate = self
        self.mWebKit.addObserver(self, forKeyPath: "URL", options: .new, context: nil)
        self.mWebKit.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)

        loadWebView(viewUrl)

        // On Notification Receive
        NotificationCenter.default.addObserver(forName: NSNotification.Name("loadWebView"), object: nil, queue: nil) { (Notification) in
            //print("notification is \(Notification)")
            let url = URL(string: Notification.userInfo?["url"] as? String ?? self.defaultUrl)
            self.loadWebView(url ?? self.viewUrl)
        }

        // Do any additional setup after loading the view, typically from a nib.
    }

    func loadWebView(_ url: URL) {
        var request = URLRequest(url: url)
        request.setValue("com.example.in", forHTTPHeaderField: "X-REQUESTED-WITH")
        self.mWebKit.load(request)
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning();
        // Dispose of any resources that can be recreated
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == #keyPath(WKWebView.url) {
            indicator.startAnimating()            
            loadWebView(self.mWebKit.url!)
        }

        if keyPath == #keyPath(WKWebView.estimatedProgress) {
            if(self.mWebKit.estimatedProgress == 1) {
                indicator.stopAnimating()
            }
        }
    }

}

Here, I am not posting actual solution for your answer, but posting the way in which you can atleast debug your code. 在这里,我并不是在为您的答案发布实际的解决方案,而是在发布您至少可以debug代码的方式。 So, If you are able to keep breakpoints and can able to see the logs(by using print method), then, you can easily find the actual cause behind the scene. 因此,如果您能够保留断点并能够查看日志(使用打印方法),则可以轻松地找到背后的实际原因。

Here is way for debugging such case. 这是调试这种情况的方法。

  1. Go to edit scheme 进入edit scheme

在此处输入图片说明

  1. Now, The screen which get opened, here select Run from the left menu. 现在,打开的屏幕,在这里从左侧菜单中选择Run Now, Select Info tab from top menu. 现在,从顶部菜单中选择“ Info选项卡。 Here you will see 2 Radio buttons for Launch case. 在这里,您将看到2个用于Launch箱的单选按钮。 Automatically will be selected by default. 默认情况下将Automatically选择。 Change it to Wait for executable to be launched . 将其更改为Wait for executable to be launched Then close this screen. 然后关闭此屏幕。

在此处输入图片说明

  1. Now, run your app in your device. 现在,在设备中运行您的应用。 It will install your app on device, but it will not launch your app, as it commonly do everytime. 它将在设备上安装您的应用程序,但不会像通常那样每次启动您的应用程序。

  2. Now, post your push notification, once you will receive the notification, click on it. 现在,发布您的推送通知,一旦您收到通知,请单击它。 As you click on it, your app will get launched, and your debugging session will start, if your app is crashing, then breakpoint will automatically stops there. 当您单击它时,您的应用程序将启动,调试会话将启动,如果您的应用程序崩溃,则断点将自动在此处停止。 Otherwise, if there is any issue with your logic, you can debug the session by putting the breakpoints as well as by adding "print" logs, wherever required. 否则,如果您的逻辑有任何问题,则可以在需要时通过放置断点以及添加“打印”日志来调试会话。

I think by doing above thing, you will be able to debug and once you can debug, you can easily identify the issue and have the solution. 我认为通过上述操作,您将能够进行调试,并且一旦可以调试,就可以轻松地确定问题并找到解决方案。 Once you get the solution, change the above setting back to Automatically to launch your app normally. 获得解决方案后,将以上设置更改回“ Automatically即可正常启动您的应用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过推送通知Objective C iOS从“终止”状态打开时,应用崩溃 - App crash when open from Kill state through Push notification Objective C iOS flutter 通知不会出现在 ios 当应用程序正在杀死 state 但当我们打开应用程序时通知即将到来 - flutter notification is not coming in ios when app is on kill state but when we open the app notification is coming 当应用未处于运行状态iOS时通过通知横幅打开应用 - Open app through notification banner when app is not running state iOS 从推送通知 IOS 打开应用程序时打开特定的 ViewController - Open specific ViewController when open app from push notification IOS 处于“未运行”状态时在iOS应用中推送通知 - Push notification in iOS app when “Not running” state iOS推送通知:当应用程序被终止或迅速终止时如何存储推送通知有效载荷? - iOS push notification: how to store push notification payload when application is kill or terminate in swift? 收到 iOS 推送通知时如何打开通知视图控制器? - How to Open a Notification view controller when a iOS push notification is received? 当用户点击iOS Swift的推送通知时,在特定视图中打开应用程序 - Open app in specific view when user taps on push notification with iOS Swift 当用户点击带有 iOS 13 Swift 5 的推送通知时,在特定视图中打开应用程序 - Open app in specific view when user taps on push notification with iOS 13 Swift 5 应用程序处于终止模式时的声音推送通知 - Audible push notification when app is in kill mode
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM