本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/579efa7083355a9a57a1ac5b

Dev Club 是一个交流移动开发技术,结交朋友,扩展人脉的社群,成员都是经过审核的移动开发工程师。每周都会举行嘉宾分享,话题讨论等活动。

本期,我们邀请了腾讯WXG iOS开发工程师——bang 陈振焯,为大家分享《JSPatch成长之路》

如何加入 Dev Club?

移动端开发经验 >= 2 年,微信扫描下方群管理微信二维码,备注姓名-公司(或产品) 申请加入。


分享内容简介:
JSPatch 是 iOS 上的动态更新框架,只需要引入小小的引擎文件,就可以用 JS 调用和替换任意 OC 方法。目前被普遍用于实时修复 bug,已有超过2500个 APP 接入,本次分享介绍 JSPatch 发展过程中遇到的问题和解决思路。
(此内容已在 GMTC 线下分享过,本次重新整理为线上分享)

内容大体框架:

  1. 起步:介绍 JSPatch 的诞生和当时碰到的难题
  2. 发展:介绍 JSPatch 如何补全周边功能变得更好用
  3. 下一步:介绍 JSPatch 下一步的计划

分享人介绍:

bang 陈振焯 广州研发部 目前负责开发微信读书iOS端,博客 http://blog.cnbang.net


下面是本期分享内容整理


大家好,我是 bang,目前在广州研发部做微信读书 iOS 端,今天分享的主题是《JSPatch 成长之路》。

我在去年5月发布了 JSPatch (https://github.com/bang590/JSPatch) 这个开源库,现在广泛应用于 iOS 的热修复,今天分享一下 JSPatch 过去一年以来的成长。

分享共分为三个部分:

  1. 起步 —— 介绍JSPatch的诞生和当时碰到的难题
  2. 发展 —— 介绍JSPatch如何补全周边功能变得越来越好用
  3. 下一步 —— 介绍JSPatch下一步的计划

一、起步

先说下起步阶段。当时碰到的一个问题是:APP 线上 bug 修复周期长,成本高,版本发布出去后,发现一个 bug,要修复这个 bug 就必须得另外发一个版本,也就是要经历:测试——打包——发布——审核——用户下载,这一系列过程,成本非常高,最后还很难让所有用户都升级上来。

当时业界已有一个解决方案,叫 waxPatch,它是在APP里嵌入 lua 引擎,然后通过 OC 的 runtime 接口在 lua 里调用和替换 OC 方法,这样就可以下发 lua 脚本替换原生代码,动态修复 bug。

waxPatch: https://github.com/mmin18/WaxPatch

这是个不错的方案,但当时的 waxPatch 存在很多缺陷:

首先是 wax 已经多年不维护了,导致不支持一些 block/64 位等新特性,此外当时 wax 还有文档不足,测试不足,线程不安全,难以调试等坑。

于是开始探求更好的解决方案。很容易想到如果用 JavaScript 做这个事情的话,相对 lua 原生就有一些优势:

  1. iOS 里已内置 JavascriptCore 引擎,无需再另外嵌入。
  2. JS 在终端应用广泛,很多混合开发内嵌 H5 页面就是用 JS。
  3. 符合苹果审核规则,苹果在文档里说明不可以下载可执行的代码,由 JavascriptCore 执行的除外

那么有没有人试过这样做呢?用 Javascript 调用和替换 OC 方法,当然是有的。

  • 在当时有一个开源库 JavascriptBridge (https://github.com/kishikawakatsumi/JavaScriptBridge), 它可以用 JS 调用 OC 接口。
不过它用的是 JavascriptCore 原生的接口做的,需要事先在 OC 里定义好要调用的接口,没有事先定义的不能调,这导致它的实现很臃肿,因为要在 OC 定义大量的方法。此外它也不能替换 OC 方法,实用性很低。

  • 当时国外还有一个热补丁服务叫 rollout (http://rollout.io)。 它是一个服务平台,底层也是用 JS 调用和替换 OC 方法去实时修复 bug,不过它不是开源的,只能在这个平台上用,另外它的 JS 写法是比较复杂的,看看这个例子就知道,这导致它不得不在平台上做一些便捷的功能,把一些常用的操作封装起来,减少使用者写代码。

总的来说,当时并没有一个更好的方案,于是想自己造个。

当时期望做到的效果是这样的:

我在 JS 写 UIView.allOC(), 然后传给 JavascriptCore 执行,JavascriptCore 把我要调用的信息,这里类名是 UIView,类方法名是 alloc 传递给 OC,OC runtime 就可以找到这个类和方法进行调用。这是最基本的一个语句调用。

实际上当时实现这个最基本的调用就遇到一个槛,在 JS 里这条语句根本无法执行:

要让这条语句在 JS 环境中可以执行,在 JS 的语言规则下,UIView 必须是一个对象,alloc 必须这个对象的一个方法。

也就是说要像这样定义后才可以执行:

UIView 必须是一个对象这点没问题,在调用前定义就可以,但 UIView 的方法必须在调用前定义就很糟糕,这意味着如果你想调用任意 UIView 的方法,你就需要提前把所有 UIView 的方法都找出来,每一个方法都要预先定义好。

也就是说在使用UIView之前,需要先去 OC 把UIView所有方法找出来,然后构建UIView对象,每个方法都在这个对象里生成对应的函数,然后你才可以调用UIView的任意方法。

JSPatch 在开发时就尝试过这种方案,后来发现这些对象的方法太多了,仅 NSObject 基类的实例方法就有830个,类方法有118个,这导致在JS生成的对应的对象占用内存极高,NSObject就占了1.3M,UIView占2M。这根本不可用。

对此我还进行了一些优化尝试,例如去除掉里面的下划线开头的私有方法,在 JS 构造继承链共用基类方法。但这些优化都没多少效果,占用内存依旧很高。当时就觉得不太可能实现。

实际上当时我陷入了一个思维定势,做终端久了,思维停留在 iOS 的 OC 世界,写代码必须遵守语言的规则,上述的困难也是在遵守 JS 语言规则这个前提下碰到的。

如果有方法不遵守语言规则呢?实际上在 JS 界,有个很常用的伎俩,就是预编译:

也就是我们写的脚本不直接拿给 JS 引擎执行,而是进行一些转换后才执行,在现代框架这个用法很常见, react/vue 都用了,甚至还有像 coffieScript 这样把 JS 完全换成另一种语言的做法。

想到这一点,刚才的问题就很好解决了。

只需要把所有函数调用在执行前都替换一遍,变成去调用一个固定的 __c 函数, 这个 __c 函数模拟了 ruby/lua 等语言的元方法机制,对方法调用进行转发。

还是以调用 UIViewalloc 方法为例,这个语句在执行之前会被替换为调 UIView 的 __c 方法,把 “alloc” 作为字符串参数穿进去,在 __c 方法里判断调用者 UIView 是不是 OC 对象。如果是,就把类名和传进来的方法名传到 OC 层进行调用,如果不是,就调用回 JS 这个对象的方法。

这样做简洁高效地解决了前面的问题,不需要去 OC 遍历每个类的方法,不需要存储这些方法,就可以调用任意 OC 方法,只需要给 JS 基类定义一个 __c 方法就可以了。正则替换后无论调用 OC 的什么方法,都不会有语法错误,因为都变成调用这个 __c 方法,在这个 __c 方法里做处理去 OC 层调用相应的方法就行了。

使用这种方案后内存的占用下降了 99%,甚至更多,也使 JSPatch 的使用成为可能,这是 JSPatch 最核心的一点。

解决这个核心问题后,后面就是细化功能了,JSPatch 发布以后一直在完善,包括最基本的调用和替换OC方法,还有支持64位,支持 block,支持包括 c指针/Class/结构体等类型,支持 c函数的调用等,这里面的细节原理我觉得看文章会比较清晰,相关文章都可以在 github wiki (https://github.com/bang590/JSPatch/wiki) 上找到,这里就不多说了。

二、发展

接下来说说 JSPatch 是怎样进行进一步发展的。

在完善 JSPatch 的同时,我也在想,如何把 hotfix 做得更好。

主要有两个思路:

  1. 降低使用门槛
  2. 提高使用效率

我们一个点一个点来看对这两个问题是怎么做的。

首先 JSPatch 在易用性上一直坚持着一个理念,就是 keep it simple and tiny,用中文说就是保持精巧,保持好用。JSPatch 从开源到现在一年多,增加和完善了很多功能,但它的使用方式和接口都没有变过,一直以来都是只有三个文件,拖入项目直接可以使用,也会很谨慎地新增接口,不会影响到旧接口的使用,不会出现同一份代码在旧版本能用,在新版本不能用的情况,在易用性上降低使用门槛。

另一个问题是安全问题

JSPatch 可以调用和替换任意 OC 方法,权限很大,如果在传输过程中被第三方攻击,替换了下发的代码去执行,会对用户和 APP 本身造成很大伤害。如果每个接入 JSPatch 的人都要考虑这个安全问题,接入门槛就会很高,也可能会因为考虑不周全导致 APP 处于危险状态。

对此当时详细考虑了安全策略。对这种情况:

  • 最简单的方案是直接对脚本加密,后台使用固定密钥加密脚本后下发,客户端使用同样的密钥解密。这种方案的优点是简单,缺点是这个密钥必须存在客户端,黑客很容易破解拿到这个密钥,然后通过传输过程第三方攻击,下发同样用这个密钥加密的恶意代码,就没有安全可言了。

  • 第二个方案是让脚本通过 https 传输,这个方案的优点是安全性高,只要客户端对证书进行过足够的验证,就能很好地保证安全性。缺点是这个方案门槛高,部署繁琐,需要购买证书,对一些中小 APP 来说可能难以接受,并且如果用户手机信任了一些恶意证书,也还是存在被攻击的危险。

  • 第三个方案是使用RSA签名验证。
    整个流程是这样:

第一步服务端计算脚本文件的MD5值,用存在服务端的私钥对这个MD5值进行加密,然后把这个MD5值和脚本一起打包下发给客户端。客户端拿到脚本和加密后的MD5值,用存在客户端的公钥进行解密,拿到服务端计算的MD5值,本地再计算一遍脚本文件的MD5值,对比这两个值是否一致,若一致则表示传输过程中没有被篡改。

如果第三方要截获请求下发恶意脚本,第三方必须用私钥加密这个恶意脚本的MD5值一起下发,才能通过验证执行,只要服务端不被攻破,第三方就没有私钥,也就无法进行篡改。

可以看到这第三个方案门槛低,通用性高,部署简单,安全性也高,对服务端和客户端都没有什么特殊要求。

我把这一套安全方案做成一个组件,叫 JPLoader,也开源在 JSPatch 项目上(https://github.com/bang590/JSPatch/tree/master/Loader), 需要部署 JSPatch 的同学可以直接使用这套组件,解决安全性问题,客户端的工作就完成了,只剩下后端的工作。

前面把安全性问题解决了,只剩下后端的工作,但搭建后台对使用者来说也是挺麻烦的事,特别是作为 iOS 开发者,在中小公司自己搭后台麻烦,在大公司要后台帮你搭也不容易,这又会导致使用 JSPatch 的门槛还是很高。

于是在想这部分工作能不能也帮使用者省了呢?

对此我搭建了 JSPatch 平台 (http://JSPatch.com), 让使用 JSPatch 的人不需要搭建后台,直接通过平台下发补丁代码。

这个平台几个月前已经开放注册,现在所有人都可以使用。

在搭建这个平台时,碰到一个问题值得分享一下,就是如何支持高并发?

由于 JSPatch 的补丁特性,补丁需要及时推送给用户,也就是说至少需要在每次启动时向服务端请求询问 APP 是否有新的补丁,有的话下发执行。这里询问的请求量是很高的,单个 APP 可以控制,但平台要面对多个 APP,累计起来的请求数量会非常多,并发会很高,怎样支撑这样的高并发?

正常来说这样一个系统整体设计大致是这样的:

平台用户把脚本放到平台服务端,服务端的数据库保存着脚本的各种信息和内容,APP 客户端向平台发起请求询问是否有新脚本,平台服务端接收到请求后通过 CGI 处理请求参数,根据 APPkey 等参数从数据库拿出这个 APP的信息,然后组装数据告诉APP客户端有没有新脚本。

这里的询问请求至少时 APP 每次启动都要发一次请求,才能保证脚本的更新能尽快下发。请求量大时,这里从数据库取出数据很容易成为整个系统的瓶颈,CGI 处理请求参数和组装数据也要耗不少资源。

对此我改用了另一种方式:

平台用户上传脚本到平台服务器时,服务端除了把 APP 信息存在 DB 外,同时会另外上传一份 JSON 静态文件到静态云服务器,JSON 里保存了当前补丁的版本,而这个静态资源的文件名是由 APPkey/APP 版本号组成的。

例如这里脚本补丁版本号是10,这个JSON静态文件的内容就是 {v:10}。可以想象静态文件的访问路径就是:

 http://JSPatch.com/{APPkey}/{APP_version}.json

然后 APP 客户端不再向平台服务端发请求,而是向这个静态资源服务器发请求,根据 APPKey 和 APP 版本直接请求到这个 JSON 文件,里面带的版本号信息就可以告诉 APP 脚本是否有更新。

整个流程就变成了:

APP 向静态服务器询问是否有新补丁,静态服务器直接返回预先设置好的 JSON,就结束了。

这样 APP 永远不会跟平台服务器打交道,只需跟静态资源服务器打交道,静态资源的高并发处理起来就简单得多,成本也低很多,现在有很多静态资源云存储,直接接入就可以了,以这些云存储的能力,支持多高的并发都没有问题,用户量多大的 APP 接入都可以支撑到。就是这样 JSPatch 平台解决了高并发问题,可以投入使用。

接下来在开发效率上,有一个问题是转换代码效率低。

我们用 JSPatch 修复 bug 时时以方法为单位进行替换的,若原方法有上百行,你的需求只是修改其中一两行代码,你也要把这上百行代码人工翻译成 JS 才行。对此我开发了JSPatch Convertor 这个工具,可以自动把 OC 代码转为 JSPatch 代码,提升开发效率。

这个工具也开源在 github 上(https://github.com/bang590/JSPatchConvertor), 支持了大部分语法特性,但目前还做不到支持所有特性,像私有变量/静态变量/宏这些还不支持,所以转换后需要人工修改,但还是很大地提高了使用 JSPatch 的效率。

总结下来,在降低使用门槛上,JSPatch 保证了易用性,封装了安全方案,提供了 JSPatch 平台让使用者可以直接接入,另外还有完善的文档和解析文章保证使用无障碍。提高使用效率上,做了 JSPatch Convertor 自动转换代码,也内置了一些扩展方便直接调用一些常用的 C函数。

经过不断发展,JSPatch 可以说是 iOS hotfix 的最佳解决方案。

目前大部分应用都已经接入使用,据不完全统计至少有 2500 个 APP 接入,经过了的大用户量的考验。

三、下一步

接下来说说下一步的计划,JSPatch 在 hotfix 上已经做得不错,目前下一步打算推动使用 JSPatch 开发功能模块。

JSPatch 做这个事情跟 React Nativeweex 这类方案比起来,会有一些优势:

  • 首先 React Native 和 weex 都是从前端出发扩展到终端,是前端方案的延伸,他们的体系对于前端来说更熟悉,对于终端来说,意味着要重新学习前端的一套知识,学习成本较高,而 JSPatch 是从终端出发,编码体系也差不多是直译 OC,学习成本较低。

  • 第二点是 ReactNative 和 Weex 是比较大型的框架,环境配置都很复杂,也会增大不少安装包的大小,如果说只想扩展实现一两个小功能,接入这么大型的框架不合适。而 JSPatch 前面也说了,属于微型框架,只有三个文件,也无需环境配置。

  • 第三点是 ReactNative 和 Weex 的组件都是要一个个封装好,难以复用现有的 OC 组件,并且他们都是大型框架,在未成熟阶段框架本身实现上的坑会很多,而 JSPatch 可以直接复用所有 OC 现有组件,并且只是薄薄的转接层,坑会较少。

但 JSPatch 要用于开发功能,有两个问题:

  1. 开发效率较低
  2. 运行效率较低。

在开发效率上,我做了两件事去提高,第一个是 JSPatchX 代码补全插件 (https://github.com/bang590/JSPatchX)。

写 JSPatch 代码时并不像 OC 那样有代码补全,在调用 OC 长长的方法时效率会很低,而且用 JSPatch 写功能时,不像 hotfix 那样有对应的 OC 代码,也无法使用前面说的 JSPatchConvertor 进行转换。于是做了 JSPatchX 去弥补这个缺陷,可以在 XCode 自动提示补全 JSPatch 代码。

另一个是 Playground 即时刷新范例 (https://github.com/bang590/JSPatch/tree/master/Demo/iOSPlayground)

可以实时预览 JSPatch 脚本执行的结果,无需像原生代码那样每一次修改都要 build 重启才能看到效果,这也是脚本语言的优势。使用者可以仿照这个 playground 的实现,在开发功能时在自己的页面实现这样的即时刷新,这样一定程度上提高了开发效率。

接下来看看运行效率。

JSPatch 写功能时运行效率低,于是着手进行优化,第一步是确定瓶颈,发现运行速度最慢的在于在 JS 调用 JS 上定义的新方法。

例如这里新定义了一个dribbbleView类,里面有个新方法renderItem,在 JS 里调用这个新方法时,速度很慢。

分析下这个调用过程:

主要问题在于这个新定义的方法与 OC 挂钩,这一次普通的调用,需要在 JS 和 OC 之间不断来回通信,不断进行参数转换,经过这9个步骤后才能成功调用。

对此我通过一些手段做了优化,把这样的方法直接放在 JS 环境上,在 JS 调用这个方法时无需再与 OC 通信,整个调用流程就变成了只有两步:

经过这个优化后,这样的方法调用性能最高提高 700 倍,这才使 JSPatch 写功能变成一件靠谱的事。

除此之外还做了一些其他优化,包括提升新增 property 性能,提供跟定义 OC 类一样的纯 JS 类定义接口,自动转换参数类型等,具体优化细节可以在这篇文章(http://blog.cnbang.net/tech/3123/) 上看到。

我用 JSPatch 写了个 Dribbble 客户端 demo (https://github.com/bang590/JSPatch/tree/master/Demo/DribbbleDemo) 在 iPhone5C 上测试过,滑动性能没有问题。

最后,可以从这个脑图看出 JSPatch 的现状,周边设施仍在继续建设中。

我今天的分享就到这里,谢谢。

问答环节:

Q1: JSPatch 的底层原理跟 ReactNative 是不是差不多呢?有受到其启发么?

JSPatch 的原理跟 ReactNative 是完全不一样的,JSPatch 是 OC 方法调用和替换的一层转接,ReactNative 并不会去调用和替换 OC 方法,它有自己的一套通信规则。

Q2: 本身基于OC runtime 对 Swift 的项目如何支持?

Swift 相关问题在 wiki 里有提到:


  1. 只支持调用继承自 NSObject 的 Swift 类
  2. 继承自 NSObject 的 Swift 类,其继承自父类的方法和属性可以在 JS 调用,其他自定义方法和属性同样需要加 dynamic 关键字才行。
  3. 若方法的参数/属性类型为 Swift 特有(如 Character / Tuple),则此方法和属性无法通过 JS 调用。
  4. Swift 项目在 JSPatch 新增类与 OC 无异,可以正常使用。

Swift 的原生类目前没找到替换的方法,动态调用倒是可以实现。

Q3: JSPatch 运行一次就会把JS转换为 OC 缓存起来?那我们可以利用它去做一些重复调用的事情?甚至用来开发?它的效率和原生相近吧?

会缓存一些 methodSignature,但还是得通过反射 (className->class->imp) 去找到要调用的方法,效率会比原生低。但一般程序的瓶颈不会在语言这里。

Q4: 对于 JSPatch 资源更新服务平台还是表示一些担忧,如果被别人攻破了,岂不是很多 APP 都受牵连了?

JSPatch 平台就算平台被人黑了,也无法对平台上的 APP 下发恶意代码。只要使用者用了自定义的 RSA 密钥就可以了,只有使用者有私钥,每次发布脚本都要使用这个私钥,平台不会保存它,详情可见:http://JSPatch.com/DOCs/rsa

Q5: 现在 iOS 加快了审核速度,好像现在是24小时内审核上线。那现在 JSPatch 前景还会好么?

审核只是一个环节,测试/打包/发布/用户下载,这些其他环节还是不可少,并且最大的问题还是是用户下载更新不可控。

Q6: Swift 属于静态编译类型,是不是可以利用类似 c函数替换的方法呢?像 fishhook 这样的工具

fishhook 需要编译时确定要替换的函数指针,并不能在运行时替换任意 c函数

Q7: 我看网上的一些介绍说 JSPatch 对小的 bug 修复好点,大的还是提交新的版本,但是我看您介绍使用静态资源服务器管理.应该不存在数据量大,并发的问题.这个您怎么看?

他指的大的 bug 应该是要写很多代码才能修复的 bug 吧?这点应该跟 JSPatch 开发效率问题有关,对于大量的代码他不想原生 OC 写一套修复,再用 JSPatch 写一套,跟数据量和并发应该没什么关系。

Q8: 为何 JSPatch 上面,QQmail 没有接入?有什么顾虑吗?

因为QQ邮箱在 JSPatch 出现之前已接入 lua,刚出现时 JSPatch 还不是很成熟,团队当时想同时使用两种方案作对比,时间久了也没有再切换过来了。

Q9: 有没有可能进一步提升 JSPatch convertor 的能力。最终发到直接打开 Xcode 项目,寻找依赖,通过语法语义分析等,将 OC 转换为 JS

可以做到的,不过这事要投入很大精力,之前有搞过一个 demo,直接用 OC 写 Patch,然后在执行前转换成 JSPatch 代码,有一个开源库 JSTalk (https://github.com/ccgus/JStalk) 有基本的 OC->JS 的转换,但要做到好用还有很多工作。

Q10: 请问如果我的 APP 引入了 JSPatch, 但是产生 crash 的代码并不是通过 JS 写的, 而是原生的 OC 代码, 那么 JSPatch 可以通过下发 JS 脚本修复这种 crash 吗, 如果可以的话, 原理是怎样的?

可以,原理就是把导致 crash 出现的方法替换掉,OC 调用那个方法时转成调用 JSPatch 里写的替换的方法,就不会 crash 了

Q11: 有没有意识到 JSPatch 的性能瓶颈最终都取决于 JavascriptCore 的性能?所以低端机永远是低性能,有没有想过借鉴 JSX 做点事情呢?

JavascriptCore 的性能并没有问题,性能瓶颈不是 JavascriptCore,目前来看瓶颈会是 OC 与 JS 通信时大对象的参数转换,但这是可以避免的

Q12: JSPatch 效率怎么样啊

效率可以试试上文说的 dribbbleDemo

Q13: 调试 JSPatch 时能不能打断点,如何定位到 JS 的 crash 堆栈

可以断点,文档有写:https://github.com/bang590/JSPatch/wiki/JS-%E6%96%AD%E7%82%B9%E8%B0%83%E8%AF%95

如果大家对本次分享还有问题,请按以下格式在DEV社区(dev.qq.com)发问答帖

发帖格式:【bang@DEV Club 你问我答】 “问题”

最后,欢迎大家关注 JSPatch 公众号:JSPatchDev,会即时推送 JSPatch 最新信息以及相关技术文章:

更多精彩内容欢迎关注bugly的微信公众账号:

腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!

【腾讯Bugly干货分享】JSPatch 成长之路的更多相关文章

  1. 【腾讯Bugly干货分享】职场中脱颖而出的成长秘诀

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/uQKpVg7HMLfogGzzMyc9iQ 导语 时光 ...

  2. 【腾讯Bugly干货分享】React Native项目实战总结

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/577e16a7640ad7b4682c64a7 “8小时内拼工作,8小时外拼成长 ...

  3. 【腾讯Bugly干货分享】让 CodeReview 这股清流再飞一会儿

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/ToYeT4Y4pzx0ii9Z92fo-Q 作者:刘 ...

  4. 【腾讯Bugly干货分享】打造“微信小程序”组件化开发框架

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/2nQzsuqq7Avgs8wsRizUhw 作者:Gc ...

  5. 【腾讯Bugly干货分享】iOS黑客技术大揭秘

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5791da152168f2690e72daa4 “8小时内拼工作,8小时外拼成长 ...

  6. 【腾讯Bugly干货分享】微信读书iOS性能优化

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/578c93ca9644bd524bfcabe8 “8小时内拼工作,8小时外拼成长 ...

  7. 【腾讯Bugly干货分享】深入源码探索 ReactNative 通信机制

    Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 本文从源码角度剖析 RNA 中 J ...

  8. 【腾讯Bugly干货分享】Android性能优化典范——第6季

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/580d91208d80e49771f0a07c 导语 这里是Android性能优 ...

  9. 【腾讯Bugly干货分享】基于RxJava的一种MVP实现

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57bfef673c1174283d60bac0 Dev Club 是一个交流移动 ...

随机推荐

  1. Microservice架构模式简介

    在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...

  2. Sublime Text 3中文乱码解决方法以及安装包管理器方法

    一般出现乱码是因为文本采用了GBK编码格式,Sublime Text默认不支持GBK编码. 安装包管理器 简单安装 使用Ctrl+`快捷键或者通过View->Show Console菜单打开命令 ...

  3. ExtJS 4.2 组件介绍

    目录 1. 介绍 1.1 说明 1.2 组件分类 1.3 组件名称 1.4 组件结构 2. 组件的创建方式 2.1 Ext.create()创建 2.2 xtype创建 1. 介绍 1.1 说明 Ex ...

  4. 协议森林17 我和你的悄悄话 (SSL/TLS协议)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 转载请先与我联系. TLS名为传输层安全协议(Transport Layer Protocol),这个协议是一套加密的 ...

  5. SignalR SelfHost实时消息,集成到web中,实现服务器消息推送

    先前用过两次SignalR,但是中途有段时间没弄了,今天重新弄,发现已经忘得差不多了,做个笔记! 首先创建一个控制台项目Nuget添加引用联机搜索:Microsoft.AspNet.SignalR.S ...

  6. 关于.NET参数传递方式的思考

    年关将近,整个人已经没有了工作和写作的激情,估计这个时候很多人跟我差不多,该相亲的相亲,该聚会喝酒的聚会喝酒,总之就是没有了干活的心思(我有很多想法,但就是叫不动我的手脚,所以我只能看着别人在做我想做 ...

  7. js学习之函数的参数传递

    我们都知道在 ECMAScript 中,数据类型分为原始类型(又称值类型/基本类型)和引用类型(又称对象类型):这里我将按照这两种类型分别对函数进行传参,看一下到底发生了什么. 参数的理解 首先,我们 ...

  8. 利用注册表在右键添加VS15的快捷方式打开文件夹

    1.简介 最近安装VS15 Preview 5,本版本可以打开"文件夹" 是否可以向Visual Studio Code一样在文件夹或文件右键菜单添加"Open with ...

  9. 微信小程序开发日记——高仿知乎日报(中)

    本人对知乎日报是情有独钟,看我的博客和github就知道了,写了几个不同技术类型的知乎日报APP要做微信小程序首先要对html,css,js有一定的基础,还有对微信小程序的API也要非常熟悉 我将该教 ...

  10. 打破陈规抓痛点,H3 BPM10.0挑战不可能

    高效益意味着相似的运营活动比竞争对手做得更好,而战略定位则意味着企业在运营活动中有区别于竞争对手的实施方式,即差异化竞争.在新经济体下,面对社会的变革.市场的竞争环境.不断攀升的成本压力,几乎没有企业 ...