我有一个适用于 Android 和 iOS 的网络应用程序,它可以打开一个网页.该应用程序适用于 Android 和大多数 iOS 设备.
I have a web app for Android and iOS that opens a web page. The app works fine for Android and most of the iOS devices.
但出于某种原因,对于某些 iOS 用户,该应用会在用户使用该应用几分钟后随机将用户重定向到初始页面.
But for some reason, for some iOS users, the app randomly redirects users to the initial page after a few minutes using the app.
用户在初始页面上打开应用,点击不同页面的链接,用户正在阅读该页面,然后由于某种原因应用重定向回初始页面.
A user opens the app on the initial page, clicks on a link for a different page, the user is reading the page, then for some reason the app redirects back to the initial page.
应用程序中没有重定向的 JavaScript 代码,有一个服务工作者,但没有重定向.
There's no JavaScript code that does redirect in the application, there's a service worker, but with no redirects.
它不会一直发生,但它确实会发生并惹恼用户.
It does not happen all times, but it does happen and annoys the users.
对可能发生的事情有什么想法吗?
Any ideas on what could be happening?
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)
从您所解释的场景来看,如果在意外场景中调用 internetChanged
方法,则页面可能会重新加载.
From the scenario that you have explained, the page might get reloaded if internetChanged
method is getting called in an unexpected scenario.
如果在显示 viewController 时更改了设备的网络状态,我可以看到这种情况.您在方法 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
中观察到了一个通知.所以当网络状态改变时,internetChanged
方法会被调用.在方法的if
和else
中都有加载webView的逻辑.
I can see that scenario happening if the network status of the device is changed while the viewController is shown. You have observed a notification in method func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
. so when the network status is changed, the internetChanged
method will get called. In both if
and else
of the method, there is logic to load the webView.
我也可以看到,您已观察到通知,但从未删除观察者.所以 ViewController 会有内存泄漏,可能不会从内存中释放.我建议你删除 deinit
Also i can see that, you have observed the notification but never removed the observer. So ViewController will have memory leaks and might not get deallocated from the memory. I would suggest you to remove observer in deinit
还有一点,你可以在 -viewDidLoad
而不是 didFinish
方法中更好地观察通知.现在按照当前逻辑发生的情况是,每当重新加载 webView 时,都会在 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
方法中将新的观察者添加到 ViewController.所以让我们以某种方式调用 internetChanged
方法 3 次,然后添加 3 个观察者.所以下一次当网络改变时,它会使 internetChanged
被调用三次,导致 webPage 被一个接一个地加载 3 次,循环继续.
One more thing is, you can better observe the notification in -viewDidLoad
instead of didFinish
method. Now what happens as per the current logic is, whenever the webView is reloaded a new observer will be added to the ViewController in the method func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
. So let's take somehow internetChanged
method is called 3 times, then 3 observers will be added. So the next time when network is changed, it will make internetChanged
getting called thrice leading to webPage getting loaded 3 times one after the other and the cycle continues.
这篇关于Web 应用程序自动重定向到 iOS 问题的初始页面(不应重定向)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!