Web 应用程序在 iOS 问题上自动重定向到初始页面(不应重定向)

Web app auto-redirecting to the initial page on iOS problem (it should NOT redirect)

我有一个用于 Android 和 iOS 的网络应用程序,可以打开一个网页。该应用程序适用于 Android 和大多数 iOS 设备。

但出于某种原因,对于某些 iOS 用户,该应用会在使用该应用几分钟后随机将用户重定向到初始页面。

用户在初始页面上打开应用程序,点击 link 进入另一个页面,用户正在阅读该页面,然后由于某种原因应用程序重定向回初始页面。

应用程序中没有 JavaScript 重定向代码,有一个服务工作者,但没有重定向。

它不会一直发生,但它确实会发生并惹恼用户。

对可能发生的事情有什么想法吗?

更新:代码片段

ViewController.swift

import UIKit
import WebKit
import Firebase
import UserNotifications
class ViewController: UIViewController , WKNavigationDelegate, WKUIDelegate{

    @IBOutlet weak var loading: UIActivityIndicatorView!
    @IBOutlet weak var screenSplash: UIImageView!
    @IBOutlet weak var webView: WKWebView!
    let reachability = Reachability()!

    var request = URLRequest(url: URL(string: "https://app.com/webview")!)

    var screen = CGRect.zero

    var flag = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        screen = UIScreen.main.bounds
        webView.frame.origin.x = 0
        webView.frame.origin.y = 0
        webView.frame.size.height = screen.height
        webView.frame.size.width = screen.width

        webView?.navigationDelegate = self

        webView.scrollView.bounces = false
        webView.isOpaque = false
        webView.backgroundColor = UIColor.clear
        webView?.load(request)
        self.view.addSubview(webView)

        screen = UIScreen.main.bounds
        webView.frame.origin.x = 0
        webView.frame.origin.y = 0
        webView.frame.size.height = screen.height
        webView.frame.size.width = screen.width


        webView.navigationDelegate = self
        self.webView?.uiDelegate = self
        view.addSubview(webView!)
    }


    @objc func internetChanged(note: Notification){
        let reachability = note.object as! Reachability
        if reachability.connection != .none{
            print("Volvio la conexion")
            webView?.load(request)
            viewDidLoad()

        }else{
            //let alert = UIAlertController(title: "", message: "Es necesario tener una conexión activa a internet", preferredStyle: .alert)
            //alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            //self.present(alert, animated: true, completion: nil)
            print("Es necesario tener una conexión activa a internet")

            let htmlPath = Bundle.main.path(forResource: "error", ofType: "html")
            let folderPath = Bundle.main.bundlePath
            let baseUrl = URL(fileURLWithPath: folderPath, isDirectory: true)
            do{

                let htmlString = try NSString(contentsOfFile:htmlPath!, encoding:String.Encoding.utf8.rawValue)
                self.webView.loadHTMLString(htmlString as String,baseURL:  baseUrl)
            }catch{

            }
        }
    }


    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
    {

    }
    func webView(webView: WKWebView!, createWebViewWithConfiguration configuration: WKWebViewConfiguration!, forNavigationAction navigationAction: WKNavigationAction!, windowFeatures: WKWindowFeatures!) -> WKWebView! {
        if navigationAction.targetFrame == nil {
            webView.load(navigationAction.request)
        }
        return nil
    }


    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
    {

        let fmcToken=InstanceID.instanceID().token() as! String
       print(fmcToken)
        webView.evaluateJavaScript("(function() { if(typeof sendDeviceToken === 'function'){  return sendDeviceToken('ios','\(fmcToken)');  }else{ return false; }  })()", completionHandler: { (data, error) in
            if let err = error {
                print(err)
                print(err.localizedDescription)
            } else {
                guard let dataValue = data else {return}
                print("res sendDeviceToken")
                print(dataValue)
            }
        })

        screenSplash.isHidden = true
        loading.isHidden = true
        webView.evaluateJavaScript("document.getElementsByTagName('meta')['viewport'].content='initial-scale=1.0, user-scalable=no';"){
            (result,error) in if error != nil  {
                print(result ?? "")
            }
        }

        if(flag==0){
            NotificationCenter.default.addObserver(self, selector: #selector(internetChanged), name: Notification.Name.reachabilityChanged, object: reachability)
            do{
                try reachability.startNotifier()

            }catch{
                print("No se pudo iniciar la notificacion")
            }
            flag=flag+1
        }
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if navigationAction.navigationType == .linkActivated  {
            if let url = navigationAction.request.url,
                let host = url.host, !host.hasPrefix("app.com")  || url.absoluteString.contains("/share/"),
                UIApplication.shared.canOpenURL(url) {
                UIApplication.shared.open(url)
                print(url)
                print("Redirected to browser. No need to open it locally")
                decisionHandler(.cancel)
            } else {
                // print("Open it locally")
                decisionHandler(.allow)
            }
        } else {
            // print("not a user click")
            decisionHandler(.allow)
        }
    }


    //fix the alert
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {

        let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)

        alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            completionHandler()
        }))

        self.present(alertController, animated: true, completion: nil)
    }
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {

        let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)

        alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            completionHandler(true)
        }))

        alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
            completionHandler(false)
        }))

        self.present(alertController, animated: true, completion: nil)
    }

    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {

        let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .actionSheet)

        alertController.addTextField { (textField) in
            textField.text = defaultText
        }

        alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
            if let text = alertController.textFields?.first?.text {
                completionHandler(text)
            } else {
                completionHandler(defaultText)
            }

        }))

        alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in

            completionHandler(nil)

        }))

        self.present(alertController, animated: true, completion: nil)
    }
    //end fix the alert

    func clickActionOpen(action: String) {
        request = URLRequest(url: URL(string: "https://app.com/webview?click_action="+action)!)

       var requestClick = URLRequest(url: URL(string: "https://app.com/webview?click_action="+action)!)
        webView.load(requestClick)
    }
}
服务人员
// Incrementing CACHE_VERSION will kick off the install event and force previously cached
// resources to be cached again.
// https://github.com/GoogleChrome/samples/blob/gh-pages/service-worker/custom-offline-page/service-worker.js
var CACHE_VERSION = 'v4'
var CACHE_NAME = CACHE_VERSION + ':sw-cache-'

function onInstall(event) {
  console.log('[Serviceworker]', 'Installing!', event)
  event.waitUntil(
    caches.open(CACHE_NAME).then(function prefill(cache) {
      return cache.addAll([
        '<%= asset_path "admin.js" %>',
        '<%= asset_path "admin.css" %>',
        '<%= asset_path "site/homepage-logo.png" %>'
      ])
    })
  )
}

function onActivate(event) {
  console.log('[Serviceworker]', 'Activating!', event)
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames
          .filter(function(cacheName) {
            // Return true if you want to remove this cache,
            // but remember that caches are shared across
            // the whole origin
            return cacheName.indexOf(CACHE_VERSION) !== 0
          })
          .map(function(cacheName) {
            return caches.delete(cacheName)
          })
      )
    })
  )
}

// Borrowed from https://github.com/TalAter/UpUp
// then from https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/onfetch
function onFetch(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      if (response) {
        // console.log('Found response in cache:', response)

        return response
      }
      // console.log('No response found in cache. About to fetch from network...')

      return fetch(event.request).then(function(response) {
        // console.log('Response from network is:', response)

        return response
      }).catch(function(error) {
        // console.error('Fetching failed:', error)

        throw error
      })
    })
  )
}

self.addEventListener('install', onInstall)
self.addEventListener('activate', onActivate)
self.addEventListener('fetch', onFetch)

原因可能是

  • ISP(互联网服务提供商)
  • 对于 ruby-on-rails,身份验证并使用他们的 authentication_token 来验证用户对您的 API 的网络请求。否则,应用程序将终止。

希望对您有所帮助。

根据您所解释的情况,如果在意外情况下调用 internetChanged 方法,页面可能会重新加载。

如果在显示 viewController 时设备的网络状态发生变化,我可以看到这种情况会发生。您已在方法 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 中观察到通知。所以当网络状态改变时,internetChanged 方法将被调用。在方法的ifelse中,都有加载webView的逻辑。

我还看到,您已经观察到通知但从未移除观察者。所以 ViewController 会有内存泄漏,可能不会从内存中释放。我建议您删除 deinit

中的观察者

另一件事是,您可以更好地观察 -viewDidLoad 中的通知,而不是 didFinish 方法。现在按照当前逻辑发生的事情是,每当重新加载 webView 时,一个新的观察者将被添加到方法 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) 中的 ViewController。所以让我们以某种方式调用 internetChanged 方法 3 次,然后将添加 3 个观察者。因此,下次网络更改时,它会使 internetChanged 被调用三次,导致 webPage 依次加载 3 次,并继续循环。