swift(ios) webview 的优化

前端之家收集整理的这篇文章主要介绍了swift(ios) webview 的优化前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

最近一直在做手机H5的东西,网页写多了,测试也测出问题来了,打开十几个网页后,app出现无响应,app的webview界面出现黑屏等等奇怪的问题。

我试了几遍,APP内存占用从20M飙升到100M+,到了100M的时候,xcode被断开了,然后问题就一个个冒出来了-_-!

搜索了一下,是uiwebview内存泄漏,然后我就兼容了wkwebview。

wkwebview遇到的问题主要有几个:

1、多个wkwebview数据不同步,localstorage在a页面能用,去到b页面能用,在b页面写入东西,在a页面看不到

2、跳转新增webview,加载很慢

3、receiveMemoryWarning 之后,或者一段时间没用之后,返回之前的页面页面变成空白

解决了这几个问题,并写了一个替代的兼容webview


所以标题也可以叫uiwebview的无痛迁移


//
//  GsWebView.swift
//  iosclient
//
//  Created by Yeshen on 16/8/31.
//  Copyright © 2016年 L. All rights reserved.
//

import Foundation
import UIKit
import WebKit

protocol GsWebViewDelegate{
    func webView(webView: GsWebView,shouldStartLoadWithRequest request: String?) -> Bool
    func webViewDidStartLoad(webView: GsWebView)
    func webViewDidFinishLoad(webView: GsWebView)
    func webView(webView: GsWebView,didFailLoadWithError error: NSError?)
}

class GsWebView :NSObject,UIWebViewDelegate,WKNavigationDelegate,WKUIDelegate{
    var delegate:GsWebViewDelegate?
    var view:UIView?
    
    init(frame:CGRect) {
        super.init()
        if #available(iOS 8.0,*) {
            let config = WKWebViewConfiguration()
            config.processPool = ProcessPool.ins.get()
            config.preferences = ProcessPool.ins.getPreferences()
            let v = WKWebView(frame: frame,configuration: config)
            v.navigationDelegate = self
            v.UIDelegate = self
            v.opaque = false

            self.view = v
        }else{
            let v = UIWebView(frame: frame)
            v.delegate = self
            v.dataDetectorTypes = UIDataDetectorTypes.None
            self.view = v
        }
    }
    
    func loadRequest(url:String){
        if let url = NSURL(string: url.EncodeURL()){
            let request = NSURLRequest(URL: url)
            if #available(iOS 8.0,*) {
                if let wkweb = view as? WKWebView {
                    wkweb.loadRequest(request)
                }
            } else {
                if let uiweb = view as? UIWebView{
                    uiweb.loadRequest(request)
                }
            }
        }
    }
    func setBackgroundColor(color:UIColor){
        view?.backgroundColor = color
    }
    
    func getScrollView() -> UIScrollView?{
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                return wkweb.scrollView
            }
        } else {
            if let uiweb = view as? UIWebView{
                return uiweb.scrollView
            }
        }
        return nil
    }
    
    func runJs(action:String?){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.runJs(action)
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.runJs(action)
            }
        }
    }
    
    func JavaScriptGet(action:String?,callback:((AnyObject?,NSError?) -> Void)){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.JavaScriptGet(action,callback: callback)
                return
            }
        } else {
            if let uiweb = view as? UIWebView{
                let str = uiweb.JavaScriptGet(action)
                callback(str,nil)
                return
            }
        }
        callback(nil,nil)
    }
    
    func getTitle() -> String{
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                return wkweb.getTitle()
            }
        } else {
            if let uiweb = view as? UIWebView{
                return uiweb.getTitle()
            }
        }
        return Strings.empty
    }
    
    func reloadFromOrigin(){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.reloadFromOrigin()
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.reload()
            }
        }
    }
    
    func reload(){
        self.reload(nil)
    }
    
    func reload(optionalUrl:String?){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                if(wkweb.URL == nil && optionalUrl != nil){
                    loadRequest(optionalUrl!)
                    return
                }
                wkweb.reload()
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.reload()
            }
        }
    }
    
    func canGoBack() -> Bool{
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                return wkweb.canGoBack
            }
        } else {
            if let uiweb = view as? UIWebView{
                return uiweb.canGoBack
            }
        }
        return false
    }
    
    func goBack() {
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.goBack()
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.goBack()
            }
        }
    }
    
    //call on viewDidAppear
    //for wkwebview'bug : Blank screen after running app for a while
    var ensure:Int = 0
    func ensurePageValid(){
        if #available(iOS 8.0,*) {
            ensure++
            if(ensure > 1){
                JavaScriptGet("document.body.children.length > 0",callback: {(data,error) -> Void in
                    var isVaild = true
                    if(error == nil && data != nil){
                        if let vaild = data as? Bool{
                            isVaild = vaild
                        }
                    }else if(error != nil){
                        if(error?.domain == WKErrorDomain && error?.code == 1){
                            isVaild = false
                        }
                    }
                    if(!isVaild){
                        NSOperationQueue.mainQueue().addOperationWithBlock({()-> Void in
                            self.reloadFromOrigin()
                        })
                    }
                })
            }
        }else{
            //ignore it
        }
    }

    /////////////
    func webView(webView: UIWebView,shouldStartLoadWithRequest request: NSURLRequest,navigationType: UIWebViewNavigationType) -> Bool{
        if delegate != nil,let url = request.URL?.description.DecodeURL(){
            return delegate!.webView(self,shouldStartLoadWithRequest: url)
        }
        return true
    }
    @available(iOS 8.0,*)
    func webView(webView: WKWebView,decidePolicyForNavigationAction navigationAction: WKNavigationAction,decisionHandler: (WKNavigationActionPolicy) -> Void){
        var policy = WKNavigationActionPolicy.Allow
        if delegate != nil,let url = navigationAction.request.URL?.debugDescription.DecodeURL(){
            if(!delegate!.webView(self,shouldStartLoadWithRequest: url)){
                policy = WKNavigationActionPolicy.Cancel
            }
        }
        decisionHandler(policy)
    }
    
    //////////////
    func webViewDidStartLoad(webView: UIWebView){
        if delegate != nil{
            delegate?.webViewDidStartLoad(self)
        }
    }
    @available(iOS 8.0,didCommitNavigation navigation: WKNavigation!){
        if delegate != nil{
            delegate?.webViewDidStartLoad(self)
        }
    }
    
    ////////////
    func webViewDidFinishLoad(webView: UIWebView){
        if delegate != nil{
            delegate?.webViewDidFinishLoad(self)
        }
    }
    @available(iOS 8.0,didFinishNavigation navigation: WKNavigation!){
        if delegate != nil{
            delegate?.webViewDidFinishLoad(self)
        }
    }
    //////////////
    func webView(webView: UIWebView,didFailLoadWithError error: NSError?){
        if delegate != nil{
            delegate?.webView(self,didFailLoadWithError: error)
        }
    }
    @available(iOS 8.0,didFailNavigation navigation: WKNavigation!,withError error: NSError){
        if delegate != nil{
            delegate?.webView(self,didFailProvisionalNavigation navigation: WKNavigation!,didFailLoadWithError: error)
        }
    }
    
}

@available(iOS 8.0,*)
extension WKWebView{
    func JavaScriptGet(jscode:String?,NSError?) -> Void)?) -> String?{
        if let js = jscode{
            self.evaluateJavaScript("javascript:" + js,completionHandler: callback)
        }
        return nil
    }
    func runJs(jscode:String?){
        if let js = jscode{
            self.evaluateJavaScript("javascript:" + js,completionHandler: {(error,data) -> Void in
            })
        }
    }
    func getTitle() -> String{
        return self.title == nil ? Strings.empty : self.title!
    }
}

extension UIWebView{
    func JavaScriptGet(jscode:String?) -> String?{
        if let js = jscode{
            return self.stringByEvaluatingJavaScriptFromString("javascript:" + js)
        }
        return nil
    }
    func runJs(jscode:String?){
        if let js = jscode{
            self.stringByEvaluatingJavaScriptFromString("javascript:" + js)
        }
    }
    func getTitle() -> String{
        if let title = stringByEvaluatingJavaScriptFromString("document.title"){
            return title
        }
        return Strings.empty
    }
}

//
//  ProcessPool.swift
//  iosclient
//
//  Created by Yeshen on 16/9/2.
//  Copyright © 2016年 L. All rights reserved.
//

import Foundation
import WebKit

@available(iOS 8.0,*)
class LandowProcessPool {
    
    private var pool:WKProcessPool?
    private var preferences:WKPreferences?
    
    class var ins: ProcessPool{
        struct Static {
            static var onceToken:dispatch_once_t = 0
            static var instance:ProcessPool? = nil
        }
        dispatch_once(&Static.onceToken){
            Static.instance = ProcessPool()
        }
        return Static.instance!
    }
    
    func get() -> WKProcessPool{
        if(pool != nil){
            return pool!
        }
        pool = WKProcessPool()
        return pool!
    }
    
    func getPreferences() ->WKPreferences{
        if(preferences != nil){
            return preferences!
        }
        preferences = WKPreferences()
        return preferences!
    }
    
    
}

此外,在Target general 的linked frameworks and libraries中要引入webkit.framework


以上,后面有问题再补充修改

猜你在找的Swift相关文章