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 【问题描述】:我有一个适用于 android 和 ios 的网络应用程序,它可以打开一个网页。该应用程序适用于 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
方法将被调用。在方法的if
和else
中都有加载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 问题的初始页面(不应重定向)的主要内容,如果未能解决你的问题,请参考以下文章
在 WEB 应用程序中重定向到不同 URL 的正确方法是啥?