最新消息:20210917 已从crifan.com换到crifan.org

【已解决】iOS中WebView回调原生页面时崩溃

iOS crifan 3241浏览 0评论

iOS程序,在Web页面点击后返回原生页面时崩溃了:

通过Xcode调试如下:

崩溃日志是:

url:{“url”:”http:/xx.xx.xx.xx//skrDev/src/report/invoice.html?t=1510207894395&drAreaFiltrateCode=SKR02-01-04&drAreaFiltrateName=”,”tabId”:”invoice”;}
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 5713, TID: 782314, Thread name: WebThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 21
Backtrace:
4   SRTDev                              0x0000000103b8f66c _T06SRTDev27ReportDetailsViewControllerCACSS3url_SS5titletcfc + 300
5   SRTDev                              0x0000000103b8e73f _T06SRTDev27ReportDetailsViewControllerCACSS3url_SS5titletcfC + 79
6   SRTDev                              0x00000001038ad239 _T06SRTDev7AppHostC8intentToySSF + 2761
7   SRTDev                              0x00000001038adfba _T06SRTDev7AppHostC8intentToySSFTo + 74
8   CoreFoundation                      0x000000010872432c __invoking___ + 140
9   CoreFoundation                      0x0000000108724200 -[NSInvocation invoke] + 320
10  JavaScriptCore                      0x0000000104b5fe18 
33  WebCore                             0x000000011441bb73 -[WAKWindow sendEventSynchronously:] + 259
34  UIKit                               0x0000000105bb31bc _
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIView init]
PID: 5713, TID: 782314, Thread name: WebThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 21
Backtrace:
4   SRTDev                              0x00000001038b16a3 _T0So9UIWebViewCABycfcTO + 19
5   SRTDev                              0x00000001038aeb6c _T0So9UIWebViewCABycfC + 60
    14  libsystem_pthread.dylib             0x000000010bca2887 _pthread_body + 0
    15  libsystem_pthread.dylib             0x000000010bca208d thread_start + 13
)
StatusBarHeight:20.0,NaviBarHeight:32.0,StatusNaviHeight:52.0
StatusBarHeight:20.0,NaviBarHeight:32.0,StatusNaviHeight:52.0

本来以为是其他逻辑方面的错误呢。

但是又看到了:

This application is modifying the autolayout

之类的错误

-》感觉是:

解决了这个问题,估计就不会崩溃了。

而之前之所以没有崩溃,是因为之前要求不严格,现在新的iOS11+XCode9,要求严格,所以会崩溃。

去找找是哪里的 background线程中修改了UI元素

其实Xcode9中,已经可以帮我们找到是哪里出现这类问题了:

然后点击进去找找

找到了,此处的:

AppHost的intentTo

是H5页面调用iOS 原生的入口

其中intentTo中,调用了VC:ReportDetailsViewController

而ReportDetailsViewController的init中,是有些UI元素的初始化的,比如:UIWebView

所以,要确保H5调用原生的intentTo中的ReportDetailsViewController,是处于Main Thread主线程才行。

而之前的代码:

    func intentTo(_ jsonString: String) {
。。。
        // current use the url inside dict to jump
        if  let url = dict?[“url”]{
。。。
            let ReportDetailsVC = ReportDetailsViewController(url: url as! String,title:titleC)
            controller?.show(ReportDetailsVC, sender: self)
        }else{
。。。
            let ReportDetailsVC = ReportDetailsViewController(url: jsonString,title:titleC)
            controller?.show(ReportDetailsVC, sender: self)
        }
    }
}

没有注意这点。

所以相关代码改为:

            dispatchMain_sync {
                let reportDetailsVC = ReportDetailsViewController(url: url as! String, title:titleC)
                self.controller?.show(reportDetailsVC, sender: self)
            }
            dispatchMain_sync {
                let reportDetailsVC = ReportDetailsViewController(url: jsonString, title:titleC)
                self.controller?.show(reportDetailsVC, sender: self)
            }

即可。

其中dispatchMain_sync是我自己整理的函数:

//
//  CrifanThread.swift
//  Crifan Li
//  Updated: 2017/09/28
//
import UIKit
let MainThread:DispatchQueue = DispatchQueue.main
let UserInteractiveThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInteractive)
let UserInitiatedThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated)
let DefaultThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default)
let UtilityThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.utility)
let BackgroundThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.background)
let UnspecifiedThread:DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.unspecified)
/***************************************************************************
* GCD/Queue/Thread functions
***************************************************************************/
func delayDispatch(_ delayTimeInSec:Double, inThread:DispatchQueue, thingsTodo:@escaping ()->()) {
    let dispatchDelayTime = DispatchTime.now() + Double(Int64(delayTimeInSec * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
    
    inThread.asyncAfter(deadline: dispatchDelayTime, execute: thingsTodo)
}
func delayDispatchInMainThread(_ delayTimeInSec:Double, thingsTodo:@escaping ()->()) {
    delayDispatch(delayTimeInSec, inThread: MainThread, thingsTodo: thingsTodo)
}
func dispatchMain_sync(_ delayTimeInSec:Double = 0.0, thingsTodo:@escaping ()->()) {
    delayDispatchInMainThread(delayTimeInSec, thingsTodo: thingsTodo)
}
func delayDispatchInBackgroundThread(_ delayTimeInSec:Double, thingsTodo:@escaping ()->()) {
    delayDispatch(delayTimeInSec, inThread: BackgroundThread, thingsTodo: thingsTodo)
}
func dispatchBackground_async(_ thingsTodo:@escaping ()->()) {
    BackgroundThread.async(execute: thingsTodo)
}
func dispatchUserInitiated_async(_ thingsTodo:@escaping ()->()) {
    UserInitiatedThread.async(execute: thingsTodo)
}
func dispatchMain_async(_ thingsTodo:@escaping ()->()) {
    MainThread.async(execute: thingsTodo)
}

更多代码详见:

https://github.com/crifan/crifanLib/blob/master/swift/Thread/CrifanThread.swift

【总结】

此处H5页面调用iOS原生导致页面崩溃,其实不是互调的问题,而是:

老生常谈的,在后台非UI线程操作UI元素而导致崩溃的。

-》如果你发现之前同样代码为何没有奔溃,那么是因为iOS11(Xcode9)之前要求不严格

-》iOS11(Xcode9)之后要求严格,所以就报错了。且Xcode9可以监测出运行时的这类问题:

在Running AppName on iPhone x 的后面,有个 淡紫色背景的数字,比如3

表示有几个这类问题,点击查看,即可找到对应代码,从而定位错误原因,解决问题了。

转载请注明:在路上 » 【已解决】iOS中WebView回调原生页面时崩溃

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
93 queries in 0.185 seconds, using 23.36MB memory