笔记整理

前言

好记性不如烂笔头,于是决定把最近了解到的知识点整理,以供后面及时回顾。

总结本篇博客内容:

  1. web首屏优化体验
  2. 移动端网络优化
  3. 崩溃问题分析
  4. 电量优化问题整理
  5. 流量监控

web首屏优化体验

相信现在大部分客户端都存在webview来支撑业务,而其中就会涉及首屏优化的体验,这是最简单的一种跨平台了,既省人力成本又快速,当然性能没有原生好,个人在去年也是写了大半年的vue,感觉前端对新人上手很快。

web端做的工作

  1. 域名尽量保持和APP一样,因为系统层面会缓存DNS解析后的ip
  2. 减少请求量
  3. 适当的使用缓存
  4. css和js优化,注意css和js的顺序

原生做的工作

  1. 1) webview第一次初始化耗时较长,可在APP启动时便进行初始化 2) webview池
  2. 离线包,包括资源缓存,提前加载到内存,减少静态资源的IO,包括图片和静态资源分开处理,包括可以更深的diff机制
  3. 预加载数据,抽出中间层由原生代理,在初始化webview的同时,并行发起比如用户信息的请求,这样当webview发起请求时,询问原生,如果原生请求完,则返回,如果不成功则等待。
  4. 客户端提供web端接口,如网络请求,sqlite,客户端可提供DNS与解析/IP直连/长连接等。

移动端网络优化

正常的网络请求是

  1. DNS解析,请求DNS服务器,获取域名对应的IP地址
  2. 与服务端建立连接,包括 tcp 三次握手,安全协议同步流程。
  3. 发送和接收数据,解码数据。

速度

  1. DNS所遇到的问题:不及时,不可控,缓存,第三方劫持,每次只能解析一个域名
    HTTPDNS 自己控制和处理
  2. 连接 HTTP 2.0 多路复用和 Keep-Alive
  3. 数据压缩 Protobuf,解码速度快体积小

弱网

如何确定弱网
httprtt(http Round-Trip Time)又名TTFB(Time to first byte),指从客户端请求的第一个字节开始发送到接收到http header的第一个字节的时间差。httprtt的时间如果过长,一方面是客户端本身接入网络质量的问题,另一方面是服务的延时比较大。
这里还是推荐看看百度APP分享的博客。还有一篇集合

  1. 提高连接成功率,梯式并发连接,其中一个连接都关闭。提高弱网下的链接成功率,又不会增加服务器的资源消耗
  2. 制定合适的超时时间,及时定位,减少等待时间,加快对超时的判断,尽早重试
  3. 调优TCP参数,适合移动端的业务特性和网络环境,混合慢启动等。

安全

  1. HTTPS
  2. 网络传输过程中数据加解密
  3. 。。。

崩溃问题分析

一般而言有两种崩溃信息,一种是可以通过信号监听收到的,一种是不能通过信号监听收到的。对于前者一般有数组越界,子线程操作UI,kvo,野指针等。
对于后者多存在于,后台被杀,主线程卡顿超时,触发watchdog机制,oom。
在这里我们分析后者信号捕获不到的情况。mach异常到BSD转换成信号,所以可以监听信号
常见的几种信号,访问未知地址,比如没有权限,重复释放同一个内存,非法指令,非法地址等。

后台被杀

我们可以自己起一个后台任务,当然这个后台任务不宜处理大数据或大量读写操作,时间阈值是3min,所以我们可以起个定时器,快到这个时间的时候,如果APP没有挂开始记录当前线程信息或调用栈,作为最接近崩溃的环境。

主线程卡顿

我们这里借助runloop,runloop更为友好的线程调度,runloop主要接受两种不同类型的输入源:1)从另一个线程或另一个应用传来的消息 2)定时器重复间隔的事件。
方案自己启个子线程进行监控,主要是监控两个地方,即将进入休眠之前和唤醒之后,如果这两个点超过了我们设置的3s,而这3s是可以根据watchdog机制来设置。原则上10s也不为过,但是更好的监控到用户感知最明显的卡顿为佳。当触发这个事件后,通过plcrashreporter进行收集堆栈信息,因为直接获取系统的不完整。
(Runloop 的目的,当有事情要处理就保持线程工作,如果没有就让线程休眠,更好的提高用户体验。)

oom定位

可以通过腾讯开源sdk,或者灰度测试内存阈值,然后dump出所有内存信息,对象名称,对象个数,个对象的内存等。

电量优化问题整理

这里不得不吐槽下,某宝真的很费电🙄

背景

假如测试某天说某个页面的耗电严重,之前几个版本却好好的,并且这几个版本也没有改变

基本问题分析

  1. 首先最简单最快捷的就是用排除法,注释掉相应代码进行检测
  2. 如果还有问题,可能就是某个第三方或者其他线程引起的,此时可以获取每个线程的CPU使用率,通过task_threads函数可以获得所有线程信息,thread_basic_info里有记录CPU使用率的字段cpu_usage,此时检测所有线程的使用率,如果如果超过90%的话,就证明有问题,并且dump堆栈信息进行记录。
  3. 尽量避免CPU做大量数据的复杂计算,尽量让服务端去处理,如果必须APP内处理,可通过GCD,专有的QOS模式,NSQualityOfServiceUtility 系统做了专门的电量优化,包括大量的网络请求
  4. 再有就是I/O,模仿SDWebImage使用原生NSCache,减少I/O操作,降低能耗。如果有监听file变动的话使用原生的dispatch_source,而不是轮询去检测。

其他情况

  1. iOS9之后,iPhone增加了低电量模式,APP可监听此通知,减少一些非必须的请求或timer等情况
  2. 优化定位和动作(Motion) 如果你的app只是需要快速确定一下用户的位置,最好用CLLocationManager的requestLocation (iOS9引入)方法。定位完成之后会自动让硬件断电。包括定位精度,及时停止定位等情况。用户摇晃,移动都会触发加速计、陀螺仪等硬件检测,所以不需要时及时取消
  3. 蓝牙在不必要时不要扫描外设,不要轮询检测。

流量监控

一个请求主要包含请求行,请求头,请求体,响应行,响应头,响应体。所以就需要整体监测,看了一些开源的第三方大部分只监控body,和记录body,所以我们还需要记录line 和 header

这里主要是借助众所周知的 NSURLProtocol,主要记录实体的几个字段是,host/path type(请求还是响应) line-length header-lenth body-length 和 总length。
整体监控是一个套路,所以没啥好说的,主要有以下几个注意点。

  1. 需要注意的是请求中cookie,臃肿的cookie也是消耗流量的一部分。
  2. 还有gzip,我们客户端拿到的数据实际上是解压过后的数据,所以直接计算是不准确的,需要模拟gzip压缩再计算大小。