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

Posted

技术标签:

【中文标题】Web 应用程序自动重定向到 iOS 问题的初始页面(不应重定向)【英文标题】:Web app auto-redirecting to the initial page on iOS problem (it should NOT redirect) 【发布时间】:2019-10-07 17:46:36 【问题描述】:

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

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

用户在初始页面打开应用程序,点击不同页面的链接,用户正在阅读该页面,然后由于某种原因应用程序重定向回初始页面。

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

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

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

更新:代码 sn-p

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)

【问题讨论】:

你需要添加一些代码和/或实现细节 如果是网络应用,能否粘贴 URL 以便其他人尝试复制? 可能是服务人员导致了重定向。需要有关该问题的更多信息。哪些设备引发了问题,在哪里?? 我有很多想法,但很少能从问题中继续缩小范围。你有 Xcode 吗?如果是这样,您可以运行 iPhone 模拟器启动 Safari 并从那里运行您的网络应用程序,看看您是否可以重新创建问题。尝试不同的模型和设置。除此之外,尝试整理错误报告,看看是否有共同的主题(相同的型号、相同的 iOS 版本、使用 4g 等)。 谢谢大家。我用一些代码sn-ps更新了这个问题,你能再检查一次吗?如果需要,我很乐意分享任何其他代码。非常感谢您的支持 - 我不知道发生了什么,我自己也无法重现。 【参考方案1】:

从您所解释的情况来看,如果在意外情况下调用 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次,循环往复。

【讨论】:

?谢谢!您的反馈似乎很有希望。我解决了这些更改,这是更改的 sn-p gist.github.com/phstc/d4b8a72304ab942e45bbffd453a6f00d 你可以看看吗? 不知道您的业务逻辑,但我可以看到您正在尝试使用变量离线解决问题。您正在尝试根据用户是否离线的事实重新加载网页。我在答案中看到了另一个问题。 如果您觉得我的回答解决了您的问题,能否将我的回答标记为已接受。这将帮助我提高我对 iOS 的 SO 评分。【参考方案2】:

原因可能是

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

希望对你有帮助。

【讨论】:

嗨@Emre。感谢您的答复。它发生在不同的 iOS 版本上。我无法用我的 iPhone 重现它,也无法用 iOS 模拟器重现。但这肯定会发生在某些用户身上。我附上了一个代码 sn-p 显示我们加载了网络应用程序。我对iOS并不完全熟悉,所以如果需要任何其他代码,我很乐意分享。这不太可能是令牌问题,因为用户登录正常。

以上是关于Web 应用程序自动重定向到 iOS 问题的初始页面(不应重定向)的主要内容,如果未能解决你的问题,请参考以下文章

Django 登录检查-自动重定向到登录页

在 jquery Ajax 调用期间页面重定向到上一页

在 WEB 应用程序中重定向到不同 URL 的正确方法是啥?

Yii2 重定向到上一页

配置spring boot以将404重定向到单页应用程序[重复]

Heroku:Python Flask 应用程序 - 自动从 https 重定向到 http