iOS – WKWebView application Push Notification failed to navigate (Redirect) to the respective screen using deep linking

I am using WKWebView to load the URL for my hybrid web application. When I receive push notifications, I use deep linking to handle them by invoking the evaluateJavaScript function of WebView.

It should function as follows: when a push notification is tapped, it should take the user to the appropriate page (in the app) using the deep link URL. However, we occasionally notice that it is rerouting to the mobile app’s home page or the page that was already accessed during the prior session or some random page of the app. In the issue case, we have noticed the error.

When I click the push notification it navigation should be to the direct designated screen not Home Screen.

Here I shared the code what I tried.

** // AppDelegate ** here I called the deeplink manager comman class for initial setup and return the url

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
DeepLinkManager.initialSetup(launchOptions: launchOptions) //Here I initialise the deep linking in app delegate when launch the app
window?.backgroundColor = .white
window?.tintColor = assetsAssets.colors.tintColor
return true}
public func application(
_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return DeepLinkManager.handleDeepLink(app: app, open: url, options: options)}}
</code>
<code>public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { DeepLinkManager.initialSetup(launchOptions: launchOptions) //Here I initialise the deep linking in app delegate when launch the app window?.backgroundColor = .white window?.tintColor = assetsAssets.colors.tintColor return true} public func application( _ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { return DeepLinkManager.handleDeepLink(app: app, open: url, options: options)}} </code>
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
DeepLinkManager.initialSetup(launchOptions: launchOptions) //Here I initialise the deep linking in app delegate when launch the app

window?.backgroundColor = .white
window?.tintColor = assetsAssets.colors.tintColor
return true}

public func application(
_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return DeepLinkManager.handleDeepLink(app: app, open: url, options: options)}}

——> ViewController Class—— //This class I used for load the content in web view data and deep linking for redirect when receiving push notification

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class ViewController: UIViewController, WKUIDelegate {
private var deepLinkObserver: Task<Void, Never>? {
willSet {
deepLinkObserver?.cancel()
}}
private var webView: WKWebView!
private let processPool = WKProcessPool()
override func viewDidLoad() {
super.viewDidLoad()
let dataStore = WKWebsiteDataStore.default()
let configuration = WKWebViewConfiguration()
let userController = WKUserContentController()
configuration.allowsInlineMediaPlayback = true
configuration.allowsPictureInPictureMediaPlayback = true
configuration.allowsAirPlayForMediaPlayback = true
configuration.processPool = processPool
configuration.websiteDataStore = dataStore
configuration.userContentController = userController
let webview = WKWebView(frame: .zero, configuration:
configuration)
webview.translatesAutoresizingMaskIntoConstraints = false
webview.allowsBackForwardNavigationGestures = true
webview.allowsLinkPreview = false
#if !PRODUCTION
if #available(iOS 16.4, *) {
webview.isInspectable = true
}
#endif
self.webView = webview
let trampoline = Trampoline(delegate: self)
for `case` in WebAppMessageName.allCases {
let name = `case`.rawValue
Self.logger.debug("subscribed for %@", name)
userController.add(trampoline, name: name)
}
deepLinkObserver = Task {
for await url in DeepLinkManager.shared.deepLinkStream {
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
if components?.queryItems == nil {
components?.queryItems = []
}
let magicNumberQueryItem = URLQueryItem(name: "magicNumber", value: "100")
components?.queryItems?.append(magicNumberQueryItem)
guard let modifiedUrl = components?.url?.absoluteString else { return }
os_log("Attempting to navigate by deep link: %{public}@", log: ViewController.osLogger, type: .debug, modifiedUrl)
do {
let _ = try await webView.evaluateJavaScript("window.mobileNavigateByDeeplink('(modifiedUrl)');true")
os_log("Successfully navigated by deep link: %{public}@", log: ViewController.osLogger, type: .info, modifiedUrl)
} catch {
os_log("Error navigating by deep link: %{public}@, error: %{public}@", log: ViewController.osLogger, type: .error, modifiedUrl, error.localizedDescription)
}
}
}
webView.navigationDelegate = self
webView.uiDelegate = self
webView.scrollView.contentInsetAdjustmentBehavior = .never
webView.scrollView.bounces = false
guard let superview = view else {
return
}
superview.backgroundColor = .white
superview.insertSubview(webview, belowSubview: loadShutter)
superview.addConstraints(
[
webView.topAnchor.constraint(equalTo: superview.topAnchor),
webView.leftAnchor.constraint(equalTo: superview.leftAnchor),
webView.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
webView.rightAnchor.constraint(equalTo: superview.rightAnchor)
]
)}
deinit {
notificationSubscriptions = nil
deepLinkObserver = nil
fallbackTask = nil
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
notificationSubscriptions = [
UIApplication.didBecomeActiveNotification,
Notification.Name.BatchPushUserDidAnswerAuthorizationRequest
].map { name in
Task { [weak self] in
for await _ in NotificationCenter.default.observe(
name: name,
object: nil,
queue: .main
) {
guard let self = self else {
break
}
self.getNotificationsStatus()
}
}
}}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
getNotificationsStatus()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
notificationSubscriptions = nil
}
func load(url: URL, fallbackTimeout: Double) {
webView.load(.init(url: url))
}
}
extension ViewController: WKNavigationDelegate {
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
) {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
return
}
guard navigationAction.navigationType == .linkActivated, !excludedDomains.contains(url.host?.replacingOccurrences(of: "www.", with: "") ?? "") else {
decisionHandler(.allow)
return
}
UIApplication.shared.open(url)
decisionHandler(.cancel)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
Self.logger.debug("didFinish")
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
Self.logger.error("error: %@", String(describing: error))
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
Self.logger.error("provisional navigation error: %@", String(describing: error))
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
self.webView.load(navigationAction.request)
return nil
}}
extension ViewController: WKScriptMessageHandler {
struct Attributes: Codable {
let isOptinEditor, isOptinOpta: Bool?
let userRegion: String?
enum CodingKeys: String, CodingKey {
case isOptinEditor = "is_optin_editor"
case isOptin = "is_optin_"
case userRegion = "user_region"
}}
struct Settings: Codable {
let region: String?
let apiRegion: String?
}
struct AppLink: Codable {
let appURLString: String
let installURLString: String
enum CodingKeys: String, CodingKey {
case appURLString = "app_url"
case installURLString = "install_url"
}
}
typealias TagsPayloadModel = PushNotificationManager.TagsPayloadModel
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
Self.logger.debug("postMessage name: %@, body: %@", message.name, String(describing: message.body))
if message.body as? String == Constants.WebMessage.articleTapped {
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
SKStoreReviewController.requestReview()
}
}
guard let body = message.body as? String else {
return
}
guard let message = WebAppMessageName(rawValue: message.name) else {
return
}
switch message {
case .tags:
guard
let data = body.data(using: .utf8),
let tags = try? JSONDecoder().decode(
[TagsPayloadModel].self,
from: data
)
else {
assertionFailure("Can not handle tags payload: (body)")
break
}
PersonalisationManager.shared.handle(tags)
Task {
do {
PushNotificationManager.handle(
tags,
isHaveTeamWidgets: try await WidgetsManager.checkIfTeamsWidgetInstalled()
)
} catch {
Self.logger.error("check widgets installed error: %@", String(describing: error))
}
}
case .attributes:
if let bodyData = body.data(using: .utf8) {
PushNotificationManager.handle(data: bodyData)
if let attributes = try? JSONDecoder().decode(Attributes.self, from: bodyData) {
PushNotificationManager.set(attributes: attributes)
}
}
case .settings:
if
let bodyData = body.data(using: .utf8),
let settings = try? JSONDecoder().decode(Settings.self, from: bodyData) {
BISVersionManager.shared.set(settings: settings)
}
case .statusBar:
switch body.trimmingCharacters(in: .init([#"""#])) {
case "dark":
self.statusBarStyle = .darkContent
case "light":
self.statusBarStyle = .lightContent
default:
Self.logger.error("unknown status bar style %@", body)
break
}
break
case .events:
switch body {
case "readyToShow":
showContent()
default:
Self.logger.error("unknown event: %@", body)
break
}
case .notificationsPermissions:
Task {
do {
try await PushNotificationManager.toggleNotifications(turnOn: true)
} catch PushNotificationManager.Error.notificationsDenied {
URL(
string:UIApplication.openSettingsURLString
).map {
UIApplication.shared.open($0)
}
}
}
case .appLink:
if
let bodyData = body.data(using: .utf8),
let appLink = try? JSONDecoder().decode(AppLink.self, from: bodyData) {
if let appURL = URL(string: appLink.appURLString), UIApplication.shared.canOpenURL(appURL) {
UIApplication.shared.open(appURL)
} else if let installURL = URL(string: appLink.installURLString) {
UIApplication.shared.open(installURL)
}
}
}
}}
</code>
<code>class ViewController: UIViewController, WKUIDelegate { private var deepLinkObserver: Task<Void, Never>? { willSet { deepLinkObserver?.cancel() }} private var webView: WKWebView! private let processPool = WKProcessPool() override func viewDidLoad() { super.viewDidLoad() let dataStore = WKWebsiteDataStore.default() let configuration = WKWebViewConfiguration() let userController = WKUserContentController() configuration.allowsInlineMediaPlayback = true configuration.allowsPictureInPictureMediaPlayback = true configuration.allowsAirPlayForMediaPlayback = true configuration.processPool = processPool configuration.websiteDataStore = dataStore configuration.userContentController = userController let webview = WKWebView(frame: .zero, configuration: configuration) webview.translatesAutoresizingMaskIntoConstraints = false webview.allowsBackForwardNavigationGestures = true webview.allowsLinkPreview = false #if !PRODUCTION if #available(iOS 16.4, *) { webview.isInspectable = true } #endif self.webView = webview let trampoline = Trampoline(delegate: self) for `case` in WebAppMessageName.allCases { let name = `case`.rawValue Self.logger.debug("subscribed for %@", name) userController.add(trampoline, name: name) } deepLinkObserver = Task { for await url in DeepLinkManager.shared.deepLinkStream { var components = URLComponents(url: url, resolvingAgainstBaseURL: false) if components?.queryItems == nil { components?.queryItems = [] } let magicNumberQueryItem = URLQueryItem(name: "magicNumber", value: "100") components?.queryItems?.append(magicNumberQueryItem) guard let modifiedUrl = components?.url?.absoluteString else { return } os_log("Attempting to navigate by deep link: %{public}@", log: ViewController.osLogger, type: .debug, modifiedUrl) do { let _ = try await webView.evaluateJavaScript("window.mobileNavigateByDeeplink('(modifiedUrl)');true") os_log("Successfully navigated by deep link: %{public}@", log: ViewController.osLogger, type: .info, modifiedUrl) } catch { os_log("Error navigating by deep link: %{public}@, error: %{public}@", log: ViewController.osLogger, type: .error, modifiedUrl, error.localizedDescription) } } } webView.navigationDelegate = self webView.uiDelegate = self webView.scrollView.contentInsetAdjustmentBehavior = .never webView.scrollView.bounces = false guard let superview = view else { return } superview.backgroundColor = .white superview.insertSubview(webview, belowSubview: loadShutter) superview.addConstraints( [ webView.topAnchor.constraint(equalTo: superview.topAnchor), webView.leftAnchor.constraint(equalTo: superview.leftAnchor), webView.bottomAnchor.constraint(equalTo: superview.bottomAnchor), webView.rightAnchor.constraint(equalTo: superview.rightAnchor) ] )} deinit { notificationSubscriptions = nil deepLinkObserver = nil fallbackTask = nil } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) notificationSubscriptions = [ UIApplication.didBecomeActiveNotification, Notification.Name.BatchPushUserDidAnswerAuthorizationRequest ].map { name in Task { [weak self] in for await _ in NotificationCenter.default.observe( name: name, object: nil, queue: .main ) { guard let self = self else { break } self.getNotificationsStatus() } } }} override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) getNotificationsStatus() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) notificationSubscriptions = nil } func load(url: URL, fallbackTimeout: Double) { webView.load(.init(url: url)) } } extension ViewController: WKNavigationDelegate { func webView( _ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void ) { guard let url = navigationAction.request.url else { decisionHandler(.allow) return } guard navigationAction.navigationType == .linkActivated, !excludedDomains.contains(url.host?.replacingOccurrences(of: "www.", with: "") ?? "") else { decisionHandler(.allow) return } UIApplication.shared.open(url) decisionHandler(.cancel) } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { Self.logger.debug("didFinish") } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { Self.logger.error("error: %@", String(describing: error)) } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { Self.logger.error("provisional navigation error: %@", String(describing: error)) } func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { self.webView.load(navigationAction.request) return nil }} extension ViewController: WKScriptMessageHandler { struct Attributes: Codable { let isOptinEditor, isOptinOpta: Bool? let userRegion: String? enum CodingKeys: String, CodingKey { case isOptinEditor = "is_optin_editor" case isOptin = "is_optin_" case userRegion = "user_region" }} struct Settings: Codable { let region: String? let apiRegion: String? } struct AppLink: Codable { let appURLString: String let installURLString: String enum CodingKeys: String, CodingKey { case appURLString = "app_url" case installURLString = "install_url" } } typealias TagsPayloadModel = PushNotificationManager.TagsPayloadModel func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { Self.logger.debug("postMessage name: %@, body: %@", message.name, String(describing: message.body)) if message.body as? String == Constants.WebMessage.articleTapped { DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { SKStoreReviewController.requestReview() } } guard let body = message.body as? String else { return } guard let message = WebAppMessageName(rawValue: message.name) else { return } switch message { case .tags: guard let data = body.data(using: .utf8), let tags = try? JSONDecoder().decode( [TagsPayloadModel].self, from: data ) else { assertionFailure("Can not handle tags payload: (body)") break } PersonalisationManager.shared.handle(tags) Task { do { PushNotificationManager.handle( tags, isHaveTeamWidgets: try await WidgetsManager.checkIfTeamsWidgetInstalled() ) } catch { Self.logger.error("check widgets installed error: %@", String(describing: error)) } } case .attributes: if let bodyData = body.data(using: .utf8) { PushNotificationManager.handle(data: bodyData) if let attributes = try? JSONDecoder().decode(Attributes.self, from: bodyData) { PushNotificationManager.set(attributes: attributes) } } case .settings: if let bodyData = body.data(using: .utf8), let settings = try? JSONDecoder().decode(Settings.self, from: bodyData) { BISVersionManager.shared.set(settings: settings) } case .statusBar: switch body.trimmingCharacters(in: .init([#"""#])) { case "dark": self.statusBarStyle = .darkContent case "light": self.statusBarStyle = .lightContent default: Self.logger.error("unknown status bar style %@", body) break } break case .events: switch body { case "readyToShow": showContent() default: Self.logger.error("unknown event: %@", body) break } case .notificationsPermissions: Task { do { try await PushNotificationManager.toggleNotifications(turnOn: true) } catch PushNotificationManager.Error.notificationsDenied { URL( string:UIApplication.openSettingsURLString ).map { UIApplication.shared.open($0) } } } case .appLink: if let bodyData = body.data(using: .utf8), let appLink = try? JSONDecoder().decode(AppLink.self, from: bodyData) { if let appURL = URL(string: appLink.appURLString), UIApplication.shared.canOpenURL(appURL) { UIApplication.shared.open(appURL) } else if let installURL = URL(string: appLink.installURLString) { UIApplication.shared.open(installURL) } } } }} </code>
class ViewController: UIViewController, WKUIDelegate {

private var deepLinkObserver: Task<Void, Never>? {
willSet {
  deepLinkObserver?.cancel()
}}

private var webView: WKWebView!

private let processPool = WKProcessPool()


override func viewDidLoad() {
 super.viewDidLoad()

  let dataStore = WKWebsiteDataStore.default()
  let configuration = WKWebViewConfiguration()
  let userController = WKUserContentController()

  configuration.allowsInlineMediaPlayback = true
  configuration.allowsPictureInPictureMediaPlayback = true
  configuration.allowsAirPlayForMediaPlayback = true
  configuration.processPool = processPool
  configuration.websiteDataStore = dataStore
  configuration.userContentController = userController

  let webview = WKWebView(frame: .zero, configuration: 
  configuration)
  webview.translatesAutoresizingMaskIntoConstraints = false
  webview.allowsBackForwardNavigationGestures = true
  webview.allowsLinkPreview = false
  #if !PRODUCTION
     if #available(iOS 16.4, *) {
       webview.isInspectable = true
     }
  #endif
     self.webView = webview

     let trampoline = Trampoline(delegate: self)
    for `case` in WebAppMessageName.allCases {
    let name = `case`.rawValue
    Self.logger.debug("subscribed for %@", name)
    userController.add(trampoline, name: name)
    }
  deepLinkObserver = Task {
      for await url in DeepLinkManager.shared.deepLinkStream {
          var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
          if components?.queryItems == nil {
              components?.queryItems = []
          }
          let magicNumberQueryItem = URLQueryItem(name: "magicNumber", value: "100")
          components?.queryItems?.append(magicNumberQueryItem)
          guard let modifiedUrl = components?.url?.absoluteString else { return }
          os_log("Attempting to navigate by deep link: %{public}@", log: ViewController.osLogger, type: .debug, modifiedUrl)
         do {
              let _ = try await webView.evaluateJavaScript("window.mobileNavigateByDeeplink('(modifiedUrl)');true")
              os_log("Successfully navigated by deep link: %{public}@", log: ViewController.osLogger, type: .info, modifiedUrl) 
          } catch {
              os_log("Error navigating by deep link: %{public}@, error: %{public}@", log: ViewController.osLogger, type: .error, modifiedUrl, error.localizedDescription)
          }
      }
  }
webView.navigationDelegate = self
webView.uiDelegate = self
webView.scrollView.contentInsetAdjustmentBehavior = .never
webView.scrollView.bounces = false

guard let superview = view else {
  return
}
superview.backgroundColor = .white
superview.insertSubview(webview, belowSubview: loadShutter)
superview.addConstraints(
  [
    webView.topAnchor.constraint(equalTo: superview.topAnchor),
    webView.leftAnchor.constraint(equalTo: superview.leftAnchor),
    webView.bottomAnchor.constraint(equalTo: superview.bottomAnchor),
    webView.rightAnchor.constraint(equalTo: superview.rightAnchor)
  ]
)}

 deinit {
   notificationSubscriptions = nil
   deepLinkObserver = nil
   fallbackTask = nil
 }

 override func viewWillAppear(_ animated: Bool) {
  super.viewWillAppear(animated)
notificationSubscriptions = [
  UIApplication.didBecomeActiveNotification,
  Notification.Name.BatchPushUserDidAnswerAuthorizationRequest
].map { name in
  Task { [weak self] in
    for await _ in NotificationCenter.default.observe(
      name: name,
      object: nil,
      queue: .main
    ) {
      guard let self = self else {
        break
      }
      self.getNotificationsStatus()
    }
  }
}}

 override func viewDidAppear(_ animated: Bool) {
   super.viewDidAppear(animated)
   getNotificationsStatus()
 }

 override func viewWillDisappear(_ animated: Bool) {
   super.viewWillDisappear(animated)
   notificationSubscriptions = nil
 }

 func load(url: URL, fallbackTimeout: Double) {
   webView.load(.init(url: url))
 }
 }

 extension ViewController: WKNavigationDelegate {

 func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
) {
guard let url = navigationAction.request.url else {
  decisionHandler(.allow)
  return
}
guard navigationAction.navigationType == .linkActivated, !excludedDomains.contains(url.host?.replacingOccurrences(of: "www.", with: "") ?? "") else {
  decisionHandler(.allow)
  return
}
UIApplication.shared.open(url)
decisionHandler(.cancel)
}

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
Self.logger.debug("didFinish")
}

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
Self.logger.error("error: %@", String(describing: error))
}

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
Self.logger.error("provisional navigation error: %@", String(describing: error))
}

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
self.webView.load(navigationAction.request)
return nil
}}

extension ViewController: WKScriptMessageHandler {

struct Attributes: Codable {
let isOptinEditor, isOptinOpta: Bool?
let userRegion: String?

enum CodingKeys: String, CodingKey {
  case isOptinEditor = "is_optin_editor"
  case isOptin = "is_optin_"
  case userRegion = "user_region"
}}

struct Settings: Codable {
let region: String?
let apiRegion: String?
}

struct AppLink: Codable {
let appURLString: String
let installURLString: String
enum CodingKeys: String, CodingKey {
  case appURLString = "app_url"
  case installURLString = "install_url"
}
}

typealias TagsPayloadModel = PushNotificationManager.TagsPayloadModel

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
Self.logger.debug("postMessage name: %@, body: %@", message.name, String(describing: message.body))

if message.body as? String == Constants.WebMessage.articleTapped {
  DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    SKStoreReviewController.requestReview()
  }
}


guard let body = message.body as? String else {
  return
}
guard let message = WebAppMessageName(rawValue: message.name) else {
  return
}

switch message {
case .tags:
  guard
    let data = body.data(using: .utf8),
    let tags = try? JSONDecoder().decode(
      [TagsPayloadModel].self,
      from: data
    )
  else {
    assertionFailure("Can not handle tags payload: (body)")
    break
  }
  
  PersonalisationManager.shared.handle(tags)
  Task {
    do {
      PushNotificationManager.handle(
        tags,
        isHaveTeamWidgets: try await WidgetsManager.checkIfTeamsWidgetInstalled()
      )
    } catch  {
      Self.logger.error("check widgets installed error: %@", String(describing: error))
    }
  }
  
case .attributes:
  if let bodyData = body.data(using: .utf8) {
    PushNotificationManager.handle(data: bodyData)
    if let attributes = try? JSONDecoder().decode(Attributes.self, from: bodyData) {
      PushNotificationManager.set(attributes: attributes)
    }
  }
case .settings:
  if
    let bodyData = body.data(using: .utf8),
    let settings = try? JSONDecoder().decode(Settings.self, from: bodyData) {
    BISVersionManager.shared.set(settings: settings)
  }
  
case .statusBar:
  switch body.trimmingCharacters(in: .init([#"""#])) {
  case "dark":
    self.statusBarStyle = .darkContent
  case "light":
    self.statusBarStyle = .lightContent
  default:
    Self.logger.error("unknown status bar style %@", body)
    break
  }
  break
case .events:
  switch body {
  case "readyToShow":
    showContent()
  default:
    Self.logger.error("unknown event: %@", body)
    break
  }
case .notificationsPermissions:
  Task {
    do {
      try await PushNotificationManager.toggleNotifications(turnOn: true)
    } catch PushNotificationManager.Error.notificationsDenied {
      URL(
        string:UIApplication.openSettingsURLString
      ).map {
        UIApplication.shared.open($0)
      }
    }
  }
case .appLink:
  if
    let bodyData = body.data(using: .utf8),
    let appLink = try? JSONDecoder().decode(AppLink.self, from: bodyData) {
    if let appURL = URL(string: appLink.appURLString), UIApplication.shared.canOpenURL(appURL) {
      UIApplication.shared.open(appURL)
    } else if let installURL = URL(string: appLink.installURLString) {
      UIApplication.shared.open(installURL)
    }
  }
  
}
}}

WKErrorDomain: Error Domain=WKErrorDomain Code=4 “A JavaScript exception occurred” WKJavaScriptExceptionMessage=TypeError: window.mobileNavigateByDeeplink is not a function.

What might be the issue?

New contributor

SaravanaKumar_TEL is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật