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, *)
    func webView(webView: WKWebView, didCommitNavigation navigation: WKNavigation!){
        if delegate != nil{
            delegate?.webViewDidStartLoad(self)
        }
    }
    
    
    func webViewDidFinishLoad(webView: UIWebView){
        if delegate != nil{
            delegate?.webViewDidFinishLoad(self)
        }
    }
    @available(iOS 8.0, *)
    func webView(webView: WKWebView, 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, *)
    func webView(webView: WKWebView, didFailNavigation navigation: WKNavigation!, withError error: NSError){
        if delegate != nil{
            delegate?.webView(self, didFailLoadWithError: error)
        }
    }
    @available(iOS 8.0, *)
    func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError){
        if delegate != nil{
            delegate?.webView(self, didFailLoadWithError: error)
        }
    }
    
}

@available(iOS 8.0, *)
extension WKWebView{
    func JavaScriptGet(jscode:String?,callback:((AnyObject?, 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


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值