用户端智能的应用实践

2019-3-25 评论(0) 分类:技术文章

去年团队在用户端上进行了一些简单的智能应用探索实践,这里记录梳理下。

现在很多“智能”,是普通推荐算法借深度mg游戏平台官方网站的风包装的,核心也就是决策树/随机森林/SVM这些90年代已经提出的算法,我们这里的实践也是这样。在用户端上,智能应用最广泛的目前两个点:个性化和多媒体识别,我们主要实践是在个性化上,从原来所有用户都用同一套或几套规则,换成根据推荐算法给每个用户制定符合他个性化特征的不同规则。

实际上简单的个性化推荐也可以认为是规则,只是这个规则很复杂,里面的if/else/权重/概率计算不是人工写的,而是算法算出来的,大多采用监督mg游戏平台官方网站的方式,这种需求大体实现步骤是:

  1. 建模,把问题转化为三个点:输入/输出/算法。也就是挑选特征集X,确定输出目标值标签Y,挑选算法尝试找出Y=f(X)。
  2. 取数,选择一坨线上数据,清洗出需要的特征和对应的目标值。
  3. 训练,不断调整算法/参数/数据,找出用户特征->目标值的一个靠谱转化方式,输出一个模型。
  4. 应用,部署线上应用,实时预测,分析效果输入特征。

按这个套路,寻找了一些应用场景,做了一些尝试。

金额推荐

金额推荐概念很简单,我们作为理财业务,有很多场景是需要用户填入金额的,例如工资理财(每月自动把钱存到理财),小星愿(许愿存入钱),基金定投,各种理财产品的购买等。目前这些填金额的地方不是空着,就是有一个固定的默认值,金额推荐想根据每个用户的情况给推荐不同的金额,可以预填进输入框或出提示供用户选择,提升体验,甚至做出一些引导提升客单价。接下来套在上述步骤里来看下大致实施过程。

  1. 建模:
    • 输入特征基本上先拍脑袋尽量多的选取可能有关的特征,比如年龄,城市,过去交易金额等,后期训练迭代过程中会根据计算出的每个特征的重要性再进行几轮筛选。
    • 输出标签目标值是金额,但金额推荐这个需求不需要把每个用户的金额预测精确到个位数,从用户数据观察多数金额集中在有限的一些整数上(比如100/500/1000/2000等),所以这里只需要把金额分成一些档位,目标值是金额档位。
    • 算法,目标值是金额档位,是一个分类问题,分类算法中选用了随机森林这种集成算法,简单应用广,过程中也试过其他算法,效果差不多。
  2. 取数:
    • 进行一些数据预处理,例如把非数值类型的特征转为数值,合并特征和标签等。
    • 把最近一次交易金额转为对应金额档次分类作为目标值标签。
  3. 训练:使用第二步的部分数据进行训练,拟合出一个模型,再使用另一部分数据评估模型的预测效果。过程中通过各种调参/分析/数据处理,优化模型评估效果,例如:
    • 提升数据质量,筛选出过去购买金额有一定规律的人群数据,比如多次购买的方差不超过某个数值。
    • 参考随机森林特征重要性中的 entrophy gini 指数,去除重要性较低的特征。
    • 减少标签金额档次的个数,只保留多数用户会命中的几个档次。
  4. 应用:部署模型,不同的交易产品有不同的用法,可以把预测值直接预填进输入框,也可以在旁边出输入提示显示推荐的金额。然后就是一系列ABTest、性能优化、监控、数据效果分析的工作。

不同交易产品(工资理财/小星愿)对特征和标签的选取有一些小的不同,但大致处理流程一致。实践中工资理财把固定的1000元引导改成推荐的金额,订单平均金额提升60%32%用户直接使用了推荐的金额。小星愿把金额推荐作为提示供用户选择,相比直接放一个该用户历史交易金额作为提示,点击率高十几倍,用户对推荐金额的接受程度较高。

智能push

智能push想做的是在合适的时间给人推push,提高点击率。基于一个假想:每个用户都有不同时间段的活跃时间点,如果push不是统一固定时间下发,而是选择每个用户对应活跃的时间点下发,可以提高点击率。这里的push是促活类的,例如资讯的push。这里的问题可以转化为:怎样根据一个用户已有信息预测出他的活跃时间点。

  1. 建模
    • 输入,选取可能跟用户作息有关的年龄/收入/城市等基础信息,再加上用户过去7天的push点击数据作为特征值。
    • 输出,用户的活跃时间点,精确到小时,用户一天可能在多个时间点活跃,需要输出多个时间点。因为需求原因,push时间点限制在8-21点。
    • 算法,8-21点共14个小时,14小时->14个分类,多个时间点活跃->属于多个分类,是个多标签分类问题,我们用多个二分类的方式实现,同样用随机森林的算法,14个时间点每个点都单独做一次二分类,每个二分类的计算结果都是0-1之间的数,可以当成这个用户在这个时间点的活跃概率,最后合起来,得到每个时间点的概率。再根据指定阈值确定是否活跃时间点,例如:
      20190324164008
  2. 取数:
    • 对过去的push数据进行处理,根据8-21点每个时间是否有点击push,合成多条特征数据,取过去8天的数据,1-7天的数据作为特征,第8天的数据作为目标值标签。
    • 清洗用户基础特征,数据转换,拼接push特征。
  3. 训练:根据第二步的数据分14个二分类(14个时间点)训练,得到14个模型,每个时间点一个模型,最后合成一个。
  4. 应用:经过算法模型可以得到用户每个时间点的活跃概率,有多种使用策略,可以通过阈值得到几个活跃时间点,也可以直接选用概率最高的时间点,还可以在业务发送push时,往后选取概率最大的时间点发送,例如业务12点发送push,选12-21点之间概率最大的时间点,把push进队列延迟到该时间点发送。

同样是经过了多轮的数据分析、模型调整、特征优化、AB实验、Android分链路优化等,最终同一条push内容,使用智能push链路和普通链路直接推送相比,点击率稳定在提升25%左右。

本地处理

push的优化上当时我们想做更多,除了活跃时间段,实际上影响用户点击push的还有他当前手机的实时状态,例如是否在看视频/玩游戏/放在口袋里等状态,在这些情况下用户点击push概率一定很小,如果在收到push后显示前能实时检测到这些状态,就可以推迟到更合适的时间显示。为此我们在iOS上做了一些尝试:

  1. 需要在用户收到push后执行代码逻辑,再决定是否显示push,经调研 Notification Extension 没有取消展示push的能力,VoIP 需要特殊权限,只能用普通的静默push去做。
  2. 每条push都改成静默push,收到后唤起执行代码,经过各种判断后创建Local Notification,在指定时间展示push
  3. iOS 无法直接判断用户正在运行的程序和手机状态,只能通过一些侧面属性判断,包括横竖屏状态、耳机插入、内存情况、cpu情况、锁屏情况、网络状态这些信息,模糊猜测用户当前所处环境,给出一条运算公式计算用户当前是否适合展示push,公式可以动态下发,根据效果调整。
  4. 用户本地保存上面跑出来的每个时间点活跃概率数据,把push延迟到下一个较活跃的时间点显示。

Android 也实现了差不多的方案,不过iOSAndroid的方案都有缺陷,iOS方面用户手动kill掉的APP情况会收不到静默push,会影响push的到达率,Android方面没有可靠的延迟展示push手段,若延迟的时间点APP处于非活跃状态,会无法展示,同样也是会影响 push 到达率,这些缺陷导致最后本地处理的方案实现后没有很好地应用上。

其他

除了金额推荐、智能push,还做了一些其他智能的尝试,包括

  1. 智能异常检测:客户端的一些异常很多时候无法通过代码准确地检测到,例如图形引擎在一些安卓机器上的花屏,没有报错的白屏/黑屏,期望是有统一的手段检测到这些显示的异常。做法是在端上内置机器mg游戏平台官方网站框架,云端训练模型,输入是截屏图片,输出是异常分类,我们挑了三种情况作为异常截屏样本:白屏/黑屏/花屏,做一个简单的图形分类模型,典型的深度mg游戏平台官方网站cnn入门级项目,压缩模型下发到客户端运行,用户运行过程中根据一定的规则抽样进行截屏检测,有异常可能即上报。
  2. 股票OCR导入:自选股票从不同APP迁移时,需要逐个股票进行输入->搜索->添加自选,这里要做的是在应用A自选列表截屏,在应用B导入截屏,OCR识别出截屏上的股票代码。OCR是比较通用的识别能力,直接用现成模型,配合一些逻辑处理就能实现了。

还有像智能预加载/智能分页/交互预测/交易流失归因分析这些实践,但还没有做完整,就不描述了。

感想

  1. 当智能基础能力的基建(训练平台,模型部署,数据打标等)做好了,要把智能能力应用到业务上时,需要的更多是业务理解和数据分析能力,多数精力会耗费在清洗数据、模型调优上,这个能力跟工程能力有很大不同。
  2. 简单的“智能”需求,不需要理解具体算法实现也能做出来,只是理解了算法可能对优化有帮助。
  3. 机器mg游戏平台官方网站算法繁多,与过往计算机通用经验复用度不高,要达到创造/改进算法的程度门槛太高。
  4. 用户端体验上的智能应用在多媒体、IoT、系统级优化上比较有空间,其他的并没有找到特别大的应用场景。
  5. 即使做了几个智能的应用,也没法说已经入门了这个领域,只是接触到一点皮毛,而且当时去补的各种知识点在一段时间没有接触使用后,也很容易就遗忘了。

闲聊 Flutter

2018-8-27 评论(5) 分类:技术文章

移动端开发从08年开始就有个大家前赴后继不断追求的目标:跨平台,15年时 nwind 有篇雄文,详细调研了跨平台各流派,其中最后的 Dart 栏可以看到现在 Flutter 的雏形。可以看出来,Flutter 是从精简浏览器的思路演化过来的,实际上 web Flutter 从底层看是一致的,web 是提供了一层平台无关的独立引擎,可以看成平台只提供了画布,所有的UI组件、框架、事件处理都是 web 引擎封装处理。其实这种虚拟机方式是跨平台的正道,在 GUI 跨平台的道路上,JAVA FLASH 都是这种方式,在 PC 时代都取得过成功,只不过移动端时代只有 web 这种开放标准能平衡各大公司利益,延续下来了。

原本 web 作为跨平台的解决方案很完美,FB最初也信心满满用 web 技术做主 APP,但到最后还是搞不定性能问题,被迫回归原生。为什么web性能不行,上面雄文也说了,历史代码兼容,CSS复杂,DOM接口粒度大等问题,自然有牛人们继续不断去尝试解决这些问题,面对历史包袱满满的 web 引擎,首先尝试的当然是不断删代码删功能,做个精简版的 web 引擎,完全抛弃兼容性,只保留最主要的功能,据 Eric Seidel 说删完后快了 20 倍,于是朝这个方向经过几年的努力逐渐演化出 Flutter。(国外大厂可以花三四年时间做一个引擎且还在Beta,怕不怕?)

Flutter 的推出为略为沉闷的移动端技术注入了一些活力,底子强,包装好,只要接入引擎就能获得跨平台+高性能的特性。不过 Flutter 还是有不少缺陷:

  1. 动态化,国外对跨平台有偏执,国内对动态化的偏执更高,高速发展高压环境,随时发版修改是基础能力,Flutter Release AOT 无法动态化,理论上可以用 JIT 模式做动态化,但目前 Release 上没有 JIT 模式,不确定是否有性能上的问题,国内大厂接入使用少了一个很重要的理由。
  2. 体积,编译后iOS双架构15M+Android单架构约7M,不算太大,对小APP可以接受,但在大厂大APP普遍严格控制体积的情况下,使用又多一个大障碍。
  3. 语言,从 web 演化过来的框架,为什么不使用 JS 而是使用 Dart?可能出于性能考虑,Dart AOT 模式,但使用 Dart 绝对是 Flutter 推广的一大劣势,学多一门新语言就多一层障碍,Java Android 开发的推动,JS nodeJS 的推动,换个语言就不一样了。
  4. 生态,Flutter 刚推出不久,组件功能的完善度和丰富程度自然不能跟发展了十几年的iOS/Android原生以及web相比,虽说生态都是慢慢建立,但这一个从语言到工具到组件都是几乎从零开始积累,无法借用强大的前端生态或其他生态,难度会高很多,堪忧。

不管怎样,Flutter是一个宝库,一个完整的比 webkit 简单得多的引擎,源码很值得挖掘mg游戏平台官方网站,现阶段国内关注 Flutter 也是mg游戏平台官方网站居多,直接使用 Flutter 目前吸引力还不够大,但国内可能有另一个利用 Flutter 的途径:小程序。Flutter web 引擎简化中来,使用的也是 CSS flexbox 布局,但抛弃历史包袱重定规则,不兼容 web 也不是 dom 那套玩意,需要上层业务根据新规则限制写法,而小程序就是这样的限制框架,可以参考 Flutter 构建小程序渲染引擎,相对于 web 渲染性能好,相对 RN 渲染,同渲染引擎坑少,无需维护两个平台框架。可行性待研究,算是一个有趣的课题。

移动 APP 网络优化概述

2018-1-9 评论(25) 分类:技术文章

一般开发一个 APP,会直接调用系统提供的网络请求接口去服务端请求数据,再针对返回的数据进行一些处理,或者使用AFNetworking/OKHttp这样的网络库,管理好请求线程和队列,再自动做一些数据解析,就结束了。

但对于一些大型 APP,还会想针对网络的一些问题进行进一步优化,包括:

  1. 速度:网络请求的速度怎样能进一步提升?
  2. 弱网:移动端网络环境随时变化,经常出现网络连接很不稳定可用性差的情况,怎样在这种情况下最大限度最快地成功请求?
  3. 安全:怎样防止被第三方窃听/篡改或冒充,防止运营商劫持,同时又不影响性能?

对基于浏览器的前端开发来说,网络这块能做的事情很少,但对于客户端 APP 来说,整个网络请求过程是自由控制的,可以做很多事情,很多大型 APP 都针对这三个问题做了很多网络层的优化,一些新的网络层协议像 HTTP2 / QUIC 也是在这些方面进行了不少优化,在这里边mg游戏平台官方网站边整理,大致列举一下常见的做法。

速度

正常一条网络请求需要经过的流程是这样:

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

这里有明显的三个优化点:

  1. 直接使用 IP 地址,去除 DNS 解析步骤。
  2. 不要每次请求都重新建立连接,复用连接或一直使用同一条连接(长连接)。
  3. 压缩数据,减小传输的数据大小。

逐条来看能做什么。

1.DNS

DNS 完整的解析流程很长,会先从本地系统缓存取,若没有就到最近的 DNS 服务器取,若没有再到主域名服务器取,每一层都有缓存,但为了域名解析的实时性,每一层缓存都有过期时间,这种 DNS 解析机制有几个缺点:

  1. 缓存时间设置得长,域名更新不及时,设置得短,大量 DNS 解析请求影响请求速度。
  2. 域名劫持,容易被中间人攻击,或被运营商劫持,把域名解析到第三方 IP 地址,据统计劫持率会达到7%。
  3. DNS 解析过程不受控制,无法保证解析到最快的IP
  4. 一次请求只能解析一个域名。

为了解决这些问题,就有了 HTTPDNS,原理很简单,就是自己做域名解析的工作,通过 HTTP 请求后台去拿到域名对应的 IP 地址,直接解决上述所有问题:

  1. 域名解析与请求分离,所有请求都直接用IP地址,无需 DNS 解析,APP 定时请求 HTTPDNS 服务器更新IP地址即可。
  2. 通过签名等方式,保证 HTTPDNS 请求的安全,避免被劫持。
  3. DNS 解析由自己控制,可以确保根据用户所在地返回就近的 IP 地址,或根据客户端测速结果使用速度最快的 IP。
  4. 一次请求可以解析多个域名。

其余细节就不多说了,HTTPDNS 优点这么多,几乎成为中大型 APP 的标配。至此解决了第一个问题 — DNS 解析耗时的问题,顺便把一部分安全问题 — DNS 劫持也解决了。

2.连接

第二个问题,连接建立耗时的问题,这里主要的优化思路是复用连接,不用每次请求都重新建立连接,如何更有效率地复用连接,可以说是网络请求速度优化里最主要的点了,并且这里的优化仍在演进过程中,值得了解下。

keep-alive

HTTP 协议里有个 keep-alive,HTTP1.1默认开启,一定程度上缓解了每次请求都要进行TCP三次握手建立连接的耗时。原理是请求完成后不立即释放连接,而是放入连接池中,若这时有另一个请求要发出,请求的域名和端口是一样的,就直接拿出连接池中的连接进行发送和接收数据,少了建立连接的耗时。

实际上现在无论是客户端还是浏览器都默认开启了keep-alive,对同个域名不会再有每发一个请求就进行一次建连的情况,纯短连接已经不存在了。但有个问题,就是这个 keep-alive 的连接一次只能发送接收一个请求,在上一个请求处理完成之前,无法接受新的请求。若同时发起多个请求,就有两种情况:

  1. 若串行发送请求,可以一直复用一个连接,但速度很慢,每个请求都要等待上个请求完成再进行发送。
  2. 若并行发送这些请求,那么首次每个请求都要进行tcp三次握手建立新的连接,虽然第二次可以复用连接池里这堆连接,但若连接池里保持的连接过多,对服务端资源产生较大浪费,若限制了保持的连接数,并行请求里超出的连接仍每次要建连。

对这个问题,新一代协议 HTTP2 提出了多路复用去解决。

多路复用

HTTP2 的多路复用机制一样是复用连接,但它复用的这条连接支持同时处理多条请求,所有请求都可以并发在这条连接上进行,也就解决了上面说的并发请求需要建立多条连接带来的问题,网络上有张图可以较形象地表现这个过程:

duolufuyong

HTTP1.1的协议里,在一个连接里传送数据都是串行顺序传送的,必须等上一个请求全部处理完后,下一个请求才能进行处理,导致这些请求期间这条连接并不是满带宽传输的,即使是HTTP1.1的pipelining可以同时发送多个request,但response仍是按请求的顺序串行返回,只要其中一个请求的response稍微大一点或发生错误,就会阻塞住后面的请求。

HTTP2 这里的多路复用协议解决了这些问题,它把在连接里传输的数据都封装成一个个stream,每个stream都有标识,stream的发送和接收可以是乱序的,不依赖顺序,也就不会有阻塞的问题,接收端可以根据stream的标识去区分属于哪个请求,再进行数据拼接,得到最终数据。

解释下多路复用这个词,多路可以认为是多个连接,多个操作,复用就是字面上的意思,复用一条连接或一个线程。HTTP2这里是连接的多路复用,网络相关的还有一个I/O的多路复用(select/epoll),指通过事件驱动的方式让多个网络请求返回的数据在同一条线程里完成读写。

客户端来说,iOS9 以上 NSURLSession 原生支持 HTTP2,只要服务端也支持就可以直接使用,Android 的 okhttp3 以上也支持了 HTTP2,国内一些大型 APP 会自建网络层,支持 HTTP2 的多路复用,避免系统的限制以及根据自身业务需要增加一些特性,例如微信的开源网络库 mars,做到一条长连接处理微信上的大部分请求,多路复用的特性上基本跟 HTTP2 一致。

TCP队头阻塞

HTTP2 的多路复用看起来是完美的解决方案,但还有个问题,就是队头阻塞,这是受限于 TCP 协议,TCP 协议为了保证数据的可靠性,若传输过程中一个 TCP 包丢失,会等待这个包重传后,才会处理后续的包。HTTP2的多路复用让所有请求都在同一条连接进行,中间有一个包丢失,就会阻塞等待重传,所有请求也就被阻塞了。

对于这个问题不改变 TCP 协议就无法优化,但 TCP 协议依赖操作系统实现以及部分硬件的定制,改进缓慢,于是 GOOGLE 提出 QUIC 协议,相当于在 UDP 协议之上再定义一套可靠传输协议,解决 TCP 的一些缺陷,包括队头阻塞。具体解决原理网上资料较多,可以看看。

QUIC 处于起步阶段,少有客户端接入,QUIC 协议相对于 HTTP2 最大的优势是对TCP队头阻塞的解决,其他的像安全握手 0RTT / 证书压缩等优化 TLS1.3 已跟进,可以用于 HTTP2,并不是独有特性。TCP 队头阻塞在 HTTP2 上对性能的影响有多大,在速度上 QUIC 能带来多大提升待研究。

3.数据

第三个问题,传输数据大小的问题。数据对请求速度的影响分两方面,一是压缩率,二是解压序列化反序列化的速度。目前最流行的两种数据格式是 json 和 protobuf,json 是字符串,protobuf 是二进制,即使用各种压缩算法压缩后,protobuf 仍会比 json 小,数据量上 protobuf 有优势,序列化速度 protobuf 也有一些优势,这两者的对比就不细说了。

压缩算法多种多样,也在不断演进,最新出的 Brotli 和Z-standard实现了更高的压缩率,Z-standard 可以根据业务数据样本训练出适合的字典,进一步提高压缩率,目前压缩率表现最好的算法。

除了传输的 body 数据,每个请求 HTTP 协议头的数据也是不可忽视,HTTP2 里对 HTTP 协议头也进行了压缩,HTTP 头大多是重复数据,固定的字段如 method 可以用静态字典,不固定但多个请求重复的字段例如 cookie 用动态字典,可以达到非常高的压缩率,这里有详细介绍。

通过 HTTPDNS,连接多路复用,更好的数据压缩算法,可以把网络请求的速度优化到较不错的程度了,接下来再看看弱网和安全上可以做的事情。

弱网

手机无线网络环境不稳定,针对弱网的优化,微信有较多实践和分享,包括:

    1. 提升连接成功率
      复合连接,建立连接时,阶梯式并发连接,其中一条连通后其他连接都关闭。这个方案结合串行和并发的优势,提高弱网下的连接成功率,同时又不会增加服务器资源消耗:
      20180109120421
    2. 制定最合适的超时时间
      对总读写超时(从请求到响应的超时)、首包超时、包包超时(两个数据段之间的超时)时间制定不同的计算方案,加快对超时的判断,减少等待时间,尽早重试。这里的超时时间还可以根据网络状态动态设定。
    3. 调优TCP参数,使用TCP优化算法。
      对服务端的TCP协议参数进行调优,以及开启各种优化算法,使得适合业务特性和移动端网络环境,包括RTO初始值,混合慢启动,TLP,F-RTO等。

针对弱网的这些细致优化未成为标准,系统网络库没有内置,不过前两个客户端优化微信的开源网络库 mars 有实现,若有需要可以使用。

安全

标准协议 TLS 保证了网络传输的安全,前身是 SSL,不断在演进,目前最新是 TLS1.3。常见的 http 就是 HTTP 协议加上 TLS 安全协议。

安全协议概括性地说解决两个问题:1.保证安全 2. 降低加密成本

在保证安全上:

  1. 使用加密算法组合对传输数据加密,避免被窃听和篡改。
  2. 认证对方身份,避免被第三方冒充。
  3. 加密算法保持灵活可更新,防止定死算法被破解后无法更换,禁用已被破解的算法。

降低加密成本上:

  1. 用对称加密算法加密传输数据,解决非对称加密算法的性能低以及长度限制问题。
  2. 缓存安全协议握手后的密钥等数据,加快第二次建连的速度。
  3. 加快握手过程:2RTT-> 0RTT。加快握手的思路,就是原本客户端和服务端需要协商使用什么算法后才能加密发送数据,变成通过内置的公钥和默认的算法,在握手的同时就把数据发出去,也就是不需要等待握手就开始发送数据,达到0RTT。

这些点涉及的细节非常多,对 TLS 的介绍有一篇雄文,说得很详细,在此推荐。

目前基本主流都支持 TLS1.2,iOS 网络库默认使用 TLS1.2,Android4.4 以上支持 1.2。TLS1.3 iOS 还处于测试阶段,Android 未查到消息。对于普通 APP,只要正确配置证书,TLS1.2 已经能保证传输安全,只是在建连速度上会有所损耗,有一些大型 APP 像微信就自行实现了 TLS1.3 的部分协议,早一步全平台支持。

最后

网络优化这个话题非常庞大,本文只是在mg游戏平台官方网站过程中从优化思路上列举了目前业界常见的优化点,还有很多细节很多更深入的优化没涉及到,网络层实践开发经验不足,若有错误欢迎指出。

小程序技术方案探讨

2017-9-19 评论(3) 分类:技术文章

微信小程序上线大半年,大部分技术原理也有文章介绍了,本文尝试从需求出发探讨微信小程序技术方案的来源,以及最近公测的支付宝小程序技术方案的考量。

微信小程序

微信小程序的需求是让第三方开发者可以接入,可以使用微信的提供的接口去开发应用嵌入在微信里。对于这个需求,最简单的实现方案是:让外部开发者开发纯H5应用,在微信的 H5 容器里打开,容器提供微信 native 接口,就行了。在有小程序之前,已经有很多这样的业务接入,像京东购物,钱包里的各种友商大众点评/滴滴出行等,都可以认为是一个“小程序”,内嵌在微信里,能调用微信 native 接口,是不是沿着这种模式下去,把相应的接口开放给第三方,再提供个入口就行了?

实际上这种简单的方案不能满足需求,在产品上微信小程序有另外两个很重要的需求:

  1. 管控。作为一个平台必须对接入的应用有管控能力,必须能尽量精确控制应用的内容和类型,毕竟若出现非法应用平台是要承担责任的,H5 的方式太过自由,开发者可以随时改变整个应用的内容,平台难以检测到这些改变,无法管控。另外H5开发质量参差不齐,平台也无法管控,这对于一向有洁癖的微信来说无法接受。
  2. 体验。作为一个“小程序”需要让体验接近原生,而上述像京东购物这些普通 H5 页面的体验不太行,包括启动速度/页面切换流畅度都有问题,跟原生体验没法比。

所有小程序的技术方案都是为了这两个需求服务。

(更多…)

移动 H5 首屏秒开优化方案探讨

2017-8-14 评论(16) 分类:技术文章 Tags:

随着移动设备性能不断增强,web 页面的性能体验逐渐变得可以接受,又因为 web 开发模式的诸多好处(跨平台,动态更新,减体积,无限扩展),APP 客户端里出现越来越多内嵌 web 页面(为了配上当前流行的说法,以下把所有网页都称为 H5 页面,虽然可能跟 H5 没关系),很多 APP 把一些功能模块改成用 H5 实现。

虽然说 H5 页面性能变好了,但如果没针对性地做一些优化,体验还是很糟糕的,主要两部分体验:

  1. 页面启动白屏时间:打开一个 H5 页面需要做一系列处理,会有一段白屏时间,体验糟糕。
  2. 响应流畅度:由于 webkit 的渲染机制,单线程,历史包袱等原因,页面刷新/交互的性能体验不如原生。

本文先不讨论第二点,只讨论第一点,怎样减少白屏时间。对 APP 里的一些使用 H5 实现的功能模块,怎样加快它们的启动速度,让它们启动的体验接近原生。

(更多…)

React Native 源码导读(零) – 创建/运行/调试

2017-7-31 评论(10) 分类:技术文章 Tags:

最近工作需要,重新看 React Native (以下简称RN) 源码,了解机制,寻找优化空间,过程中看能不能整理出一些东西。

RN 这个项目已经是庞然大物,打开 github 项目主页,根目录下文件和文件夹就多达五六十个,看起来一脸懵逼,不知道哪些是源码,在看源码之前先理理 RN 最终用到哪些代码,项目是怎样创建,怎样跑起来的。以下皆以 iOS 端为例。

流程

先看看标准 RN 项目创建和运行过程:

  1. RN 根据教程装完环境后,会有一个全局命令 react-native,执行 react-native init AwesomeProject 可以创建一个新 RN 项目。
  2. XCode 打开自动生成的项目,编译到模拟器或真机,一个 RN hello world 程序成功运行了。
  3. 在模拟器运行同时会在 chrome 打开一个页面,在页面里使用 developer tools 可以直接断点调试 RN 页面上的 JS 源码。

疑问

上述流程跑下来整个过程是个黑盒,对黑盒里的处理有一些疑问点:

  1. react-native init AwesomeProject 这个命令做了什么,是怎样创建 RN 模板项目的?
  2. 项目 JS 源码在哪里,如何跑起来的?
  3. 怎样做到可以在 chrome 调试 JS 源码?

接下来一条条看。
(更多…)

晋升评审的套路

2017-6-26 评论(5) 分类:技术文章

很多中大型互联网公司都会有晋升评审,也就是对技术/产品等职位划分成若干个等级,每个员工都有一个等级,若要晋升到下一级,需要由几个评委面试决定是否合格。这跟传统公司的考职称差不多,只不过传统公司是通过考试,互联网公司是通过面试。

为什么会有这种晋级评审?等级是公司内部对员工的一种评价和定位,等级的参照物是公司内的所有员工,假如一个公司比较小,老板每天跟所有员工一起工作,在老板识人能力又没有问题的前提下,老板就很清楚每个人的能力,直接对他们排等级,不需要什么评审,得出来的结果其实是更公正准确的,因为这是根据平时工作过程中获取的大量信息综合考虑得出的结果。但在中大型公司做不到,老板认识不了那么多人,没在一起工作,没法对每个人给出公正的评价。若把评判权都交给一起工作的组长总监又不妥,因为职级的参照系是全公司,而不是组内或部门内,很容易出现偏颇/标准不一的情况。

于是出现一个评审系统,由公司里一些有经验的人士去判断某个人能不能晋升到下一个等级,而这些人平时很可能没有跟他们一起工作,仅仅是通过大概一个小时的陈述和沟通去评判,这导致了这一个小时里陈述的方式和沟通的技巧变得很重要,同样一个人同样的工作,不同的 PPT 不同的陈述方式,结果会完全不一样。这里大致说下我所了解到的套路,套路并不是贬义词,只是能帮助更好地表现自己的能力,让评委得出更公正的评价。

要点

先列一下在准备晋级评审 PPT 时我认为重要的几个要点:目标,重点,思路,数据。

目标

在准备晋级 PPT 时,得先搞清楚目标,这种 PPT 目标很简单只有一个,就是告诉评委我很NB我完全可以晋升到下个等级。时刻问自己 PPT 表现出这个目标了没有。

重点

只有一个小时时间,不可能面面俱到表现出所有,讲的内容多了评委也不会记得,必须突出一两个重点和亮点,用2/3以上篇幅去深入讲,并且要让人听得懂。有人误解了以为晋升评审是述职,罗列过去一年做的工作,这个其实很为难评委,评委需要帮你在你罗列的众多工作中寻找能体现你技术水平的点,整体印象也大打折扣。

另外需要有一些亮点,如果你陈述的都是业界常规做法,其他人也是这样做的,评委会觉得没什么特别,是个人都会这么做,若有自己独特的创新点和亮点,就算是小的点,让评委眼前一亮也是很好的加分项。其实这是这个评审制度本身的缺陷和局限,因为评委每次评审的人数太多,如果大家能力都没有太突出,那决定谁更好的方式就是谁更特别留下更多的印象,这也就是亮点的意义。

思路

讲思路不要讲细节,特别是代码细节,除非是非常有技术含量的,作为亮点的细节。着重表现自己在解决问题过程中的思路,表达出自己在项目/问题涉及到的方方面面都有考虑到(全局观),有深入思考的能力,面对一个问题有能力抽象出关键点,有能力分解问题,若最终能总结出类似问题的统一解决思路(方法论)更好。

数据

要有数据证明做出的成绩,经过你NB的工作后,是性能提升百分之多少,还是工作效率提高多少,还是投诉率降低多少,还是有多少个产品都在用你的东西,业务的核心数据是怎样,都要有证据证明自己不是在吹牛,尽量使用量化的指标。

结构

这里列个常用的结构供参考:

我是谁:工作经历
我做出了什么成绩:在本公司做的事情,负责的业务,做出的成绩。
1-3个重点:

  • 碰到什么问题,业界是怎么解决的,我在这基础上做了些什么,相对业界的做法有什么优点,在这过程中碰到什么困难,怎么解决,最终达到什么效果(数据)。
  • 碰到什么需求,业务特点是什么,有哪些技术挑战(安全/架构/协作/性能/稳定性/历史包袱/响应能力/兼容性/开发效率/自动化等等),我是怎样设计的(方案完整性),有什么优点和创新点,最终达到什么效果(数据)。
  • 碰到什么问题,我按什么样的思路尝试过哪些方法,深入钻研到什么程度,虽然最终做法跟业界一样,但经过我深入研究证明了这已经是最佳做法。
  • 碰到什么问题,有哪些开源项目解决了这些问题,它们有什么缺陷,我重新造的轮子比他们NB在哪里,做到这么NB的难点是什么,我怎么做到的,怎么证明真的NB不是我在吹。

未来计划
谢谢

当然并不是说都要按这个结构写,若个人能有创新发挥用更适合自己的方式陈述自然更好。

交流

交流环节里,一般评委都是会根据 PPT 内容问问题。

最容易被挑战的就是数据,若 PPT 上列的数据不是很常规就会被问为什么,对所有数据都必须准备好被质疑。

评委对某个点感兴趣会追问细节,一些重要的技术细节可以以附录的形式附在PPT后面,问到时方便讲解。

PPT 上提到的点最好对相关技术都了解清楚,例如提到客户端网络层优化,最好把网络层底层相关知识都准备好,评委可能会追问下去以考察技术深度。

有些评委喜欢问一些固定问题,例如你觉得为什么你应该晋级,你觉得有哪些不足,你后续的技术规划是什么等等。

公司一般会有每个职级对应的能力表,有些评委喜欢对着能力表问相关问题。

评审也是个双向mg游戏平台官方网站的过程,如果你能让评委觉得学到东西了效果会很好。

很多评委喜欢问他擅长的专业领域内的问题。显然这个环节有一定运气成分存在,遇到匹配度高的评委通过几率直线上升。

最后

这种一小时判断一个人的晋级评审肯定做不到非常公正,有一些运气成分,甚至有一些关系成分,但已经是相对较好的一种形式,而且评审的准备过程中还能让自己梳理总结一下过去做的事情,虽然准备过程会很痛苦,但也会很有收获。晋升的前提当然是要有足够的技术能力/影响力和视野,这里一些套路只供参考,希望能帮助有需要的人更好地表现自己的实力。

iOS App 签名的原理

2017-3-13 评论(40) 分类:技术文章

iOS 签名机制挺复杂,各种证书,Provisioning Profile,entitlements,CertificateSigningRequest,p12,AppID,概念一堆,也很容易出错,本文尝试从原理出发,一步步推出为什么会有这么多概念,希望能有助于理解 iOS App 签名的原理和流程。

目的

先来看看mg游戏网站的签名机制是为了做什么。在 iOS 出来之前,在主流操作系统(Mac/Windows/Linux)上开发和运行软件是不需要签名的,软件随便从哪里下载都能运行,导致平台对第三方软件难以控制,盗版流行。mg游戏网站希望解决这样的问题,在 iOS 平台对第三方 APP 有绝对的控制权,一定要保证每一个安装到 iOS 上的 APP 都是经过mg游戏网站官方允许的,怎样保证呢?就是通过签名机制。

非对称加密

通常我们说的签名就是数字签名,它是基于非对称加密算法实现的。对称加密是通过同一份密钥加密和解密数据,而非对称加密则有两份密钥,分别是公钥和私钥,用公钥加密的数据,要用私钥才能解密,用私钥加密的数据,要用公钥才能解密。

简单说一下常用的非对称加密算法 RSA 的数学原理,理解简单的数学原理,就可以理解非对称加密是怎么做到的,为什么会是安全的:

  1. 选两个质数 p 和 q,相乘得出一个大整数n,例如 p = 61,q = 53,n = pq = 3233
  2. 选 1-n 间的随便一个质数e,例如 e = 17
  3. 经过一系列数学公式,算出一个数字 d,满足:
    a.通过 n 和 e 这两个数据一组数据进行数学运算后,可以通过 n 和 d 去反解运算,反过来也可以。
    b.如果只知道 n 和 e,要推导出 d,需要知道 p 和 q,也就是要需要把 n 因数分解。

上述的 (n,e) 这两个数据在一起就是公钥,(n,d) 这两个数据就是私钥,满足用私钥加密,公钥解密,或反过来公钥加密,私钥解密,也满足在只暴露公钥 (只知道 n 和 e)的情况下,要推导出私钥 (n,d),需要把大整数 n 因数分解。目前因数分解只能靠暴力穷举,而 n 数字越大,越难以用穷举计算出因数 p 和 q,也就越安全,当 n 大到二进制 1024 位或 2048 位时,以目前技术要破解几乎不可能,所以非常安全。

若对数字 d 是怎样计算出来的感兴趣,可以详读这两篇文章:RSA 算法原理(一)(二)

数字签名

现在知道了有非对称加密这东西,那数字签名是怎么回事呢?

数字签名的作用是我对某一份数据打个标记,表示我认可了这份数据(签了个名),然后我发送给其他人,其他人可以知道这份数据是经过我认证的,数据没有被篡改过。

有了上述非对称加密算法,就可以实现这个需求:

(更多…)

iOS 开发技术栈与进阶

2017-2-28 评论(18) 分类:技术文章

最近有一些开发朋友问我应该怎样提升自己的能力,回想起来做了这么久 iOS 开发,我也有过那种“让我做一个功能实现个需求我会做,但接下来怎样提高我不知道。”的时期,这里尝试列一下 iOS 开发的相关技术,再说说在mg游戏平台官方网站进阶上我的一些想法。

iOS 技术栈

这里按我的理解给 iOS 相关技术分个类,以工程实现的角度,分成了基础、需求、效率、质量四个类别。基础指程序开发和 iOS 开发的基础知识和技能,需求就是产品的需求,有了基础技能,实现了产品需求后,剩下的事情就都是为了提高项目质量和提升开发效率。

大致的思维导图

iOS技术栈 (更多…)

如何动态创建 block – JPBlock 扩展原理详解

2017-1-23 评论(12) 分类:技术文章

简介

JSPatch 最近新增了扩展 JPBlock,解决之前 block 使用上的一些限制:

  1. block 参数个数最多支持6个。
  2. block 参数类型不能是 double / struct / union 类型。
  3. 不支持 JS 封装的 block 传到 OC 再传回 JS 去调用。

接入 JPBlock 后,就可以:

  1. block 参数支持任意多个。
  2. block 参数类型可以是除 struct / union 以外的任意类型,包括 double。
  3. 支持 JS 封装的 block 传到 OC 再传回 JS 去调用。

这篇文章说说这里的实现原理。

(更多…)

Baidu
sogou