[英]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
从代码didFinishLaunchingWithOptions
在AppDelegate.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. 这是调试这种情况的方法。
edit scheme
edit scheme
Run
from the left menu. Run
。 Now, Select Info
tab from top menu. Info
选项卡。 Here you will see 2 Radio buttons for Launch
case. 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. 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.
它将在设备上安装您的应用程序,但不会像通常那样每次启动您的应用程序。
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.