Mobile Web 调试指南(2)–– 远程调试

第一篇中讲解了如何让手机来请求我们开发电脑上的源码,做到了这步后,我们可以改完代码立即看到效果,但是对于调试还是远远不够的。这篇文章我们继续讲目前常用的几种 Developer tools。

PC 端的经验

在使用桌面浏览器开发时,几乎每种浏览器都有自己的开发者工具,比如大家常用的 firebug , chrome develper tools , safari developer tools . 哪怕是 IE 甚至 IE6,也有自己的开发者工具。我们利用这些工具来检查调试样式、javascript,查看修改 cookie , 查看网络请求 等等。这些大家都非常熟悉了。

移动端的方案

手机端的浏览器或者 webview 不可能在手机上集成一个 developer tools ,因为屏幕太小。好在各大厂商还是很关注开发者的便利性的,现在有多种远程调试的方案。也就是在手机上加载页面,在电脑上来展示调试工具。下面我们看看目前主流的一些工具。

iOS 平台

Safari Mobile

safari 支持远程调试,需要做如下的几步:

  • 在手机里找到 设置 -> safari -> 高级 -> Web 检查器 ,打开此功能。
  • 用数据线连接到你的 Mac(没有 Mac ? 找老板要去!)。
  • 打开 Mac 下的 safari , 到偏好设置里,高级一栏最下部,勾选在菜单栏中显示“开发”菜单
  • 用手机 safari 访问一个网页,在Mac上的 safari 开发菜单里找到你的手机,二级菜单里找到这个网页

做完这些,我们就进入了熟悉的 safari developer tools ,调试 css , js 网络请求等。

iOS webview

iOS APP 里的 webview 同样支持远程调试,不过限制更多一点。这个 APP 必须是自己编译安装进手机的,也就是你必须要有 iOS 开发者账号。对于做 Hybrid APP 开发的来说,这不是什么难事,团队肯定有开发者账号。你需要做的是了解一点 iOS 开发基础,起码能自助把代码编译安装到你的手机。

对于自己编译进去的 APP ,只需要在 APP 里载入你要调试的页面,其他步骤和 safari 的远程调试一样。

Android 平台

Chrome Mobile

Chrome for android 32 以及之后的版本具有远程调试的功能,你需要做的是:

  • 开启 Android 的 USB 调试功能。
  • 用 USB 先连接到你的电脑(windows 用户需要安装 Android 驱动)。
  • 在 Chrome for android 上打开你要调试的网页。
  • 在电脑上打开 chrome (同样最低需要 32 版本),进入 菜单 -> 工具 -> 检查设备 页面,确保 Discover USB devices 被勾选

如果设置正确的话,现在就可以看到你手机上打开的页面了,点击 inspect 进入我们熟悉的 Chrome develper tools 。

由于 Android 手机各种各样,如果遇到麻烦,请仔细阅读 官方文档

Android Webview

Android 4.4 开始,默认的浏览器已经是 chrome 了,所以 webview 也是 chrome 了,这就给了 webview 远程调试的能力。我们需要在 Android 里针对 Webview 做以下设置:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WebView.setWebContentsDebuggingEnabled(true);
}

然后在你的 App 里打开要调试的页面,其余步骤和使用 Chrome for Android 一样,进行远程调试。

使用 Android 模拟器

鉴于目前 Android 4.4 的手机还比较少,你可以选择使用模拟器来进行调试。官方的模拟器太慢,推荐大家使用 genymotion , X86 架构的模拟器,速度和真机没什么两样了。对于只做 webview 调试的前端来说,只需要使用个人免费版就可以了。

其他方式

如果你的调试条件不能满足上面讲的任何一种,还可以使用 weinre 。只需要在页面里插入一段脚本,就可以进行远程调试,基本没其他限制。但是使用这个也是有明显的缺点的:

  • 不能给 javascript 打断点,基本只能用 console 来调试
  • 不支持查看元素的样式是写在 css 第几行,也不支持显示在哪个文件
  • 由于是通过网络来连接的,所以在调试移动网络的情况时,不好操作(需要服务端运行在一个移动网络可以访问到的机器上)

总之,weinre 仅仅适用于你没办法使用 Safari 或者 Chrome 进行远程调试的情况下,聊胜于无,调试 Android hybrid APP 时,经常会遇到这个情况。

总结

综上所述,可以根据下图来选择最优的调试方案:

Mobile debug

由于我目前只接触了 iOS 和 Android 平台的开发调试,其他的移动平台不了解,所以本文没涉及到 windows phone 等平台。欢迎大家留言或者 email 交流各种远程调试方案。

Mobile Web 调试指南(1)–– 把静态资源指向到本地

Mobile 越来越重要,Hybrid App 越来越流行,在手机上进行网页的调试却并不像电脑上那么容易。大约半年前,我开始转向 Mobile Web 的开发,在调试方面做了不少的尝试,近期慢慢分享给大家。

开发过程离不开调试,特别是做前端开发,几乎是一边调试一边开发。

做调试的第一步:让浏览器/webview直接请求你本地的源码

PC 端的经验

如何实现目标?相信大家在做 PC Web 开发时,有接触过以下一些解决方案:

  • 编辑本地的 hosts 文件,把静态资源的域名指向到本地,在本地搭建静态资源 HTTP 服务器,使浏览器直接载入本地的源码。
  • 在本地搭建一个代理服务器,设置浏览器的代理到这个代理服务器,在代理服务器中根据规则直接读取本地的源码返回给浏览器。例如有 nproxy 可以满足此类需求。
  • 使用 Fiddler 的 AutoResponder 的功能。这个方法实际上和上一个是同样的,Fiddler 是一个非常强大并且免费的 GUI 工具,很容易上手。
  • 使用模块加载器提供的 debug 功能来做线上资源到本地资源的映射,例如 seajs-debug

这些方式要完成的任务都是:让浏览器直接请求你本地的源码

只要做到了这一点,我们就可以在编辑器里改完代码,刷新浏览器立即看到改动后的效果,避免了部署代码的繁琐操作。

移动端的方案

在移动端,应该怎么做呢?

无非要实现同样的目标:让手机浏览器/webview 直接载入我们工作电脑上的源码 。我们先看看 PC 上的这几种常用方式在手机上是否还适用。

编辑 hosts 的方案

在 PC 上编辑 hosts 文件的时候,大家应该注意过,在 WIN7/8 系统上,需要管理员权限,在 Mac/Linux 下,需要 root 权限。这确实是一个很安全敏感的文件。所以在手机上,要想编辑这些文件同样需要 root 权限。这就意味着 iOS 需要越狱,Android 需要 root 。我认为这个方案在手机上不可取,在手机上编辑 hosts 困难重重,你还不能保证你的每台开发机都有 root 权限,调试兼容性的时候,遇到无法 root 的机器怎么办?

使用代理的方案(包括自建 proxy server 和 使用 fiddler)

在 iOS 上配置系统的 HTTP 代理服务器是非常容易的,大部分 Android 机也可以配置,只是不同机型配置菜单的位置不一样。剩下要做的,就是和在 PC 上一样了,配置规则来把某些文件代理到本地。

使用这个方案可能会遇到的问题是:自建的 proxy server 一般对 HTTPS 的兼容不够好,对于 Hybrid App ,可能 native 部分有些请求是 HTTPS 的,webview 里的页面是 HTTP 的。设置了 HTTP Proxy 后,所有的请求都要经过这个代理服务器,如果对 HTTPS 的支持不够好,可能出现无法登录等情况发生。这点要赞 Fiddler 一下,处理的非常好。

另外 Mac 用户可能没有太好的 Fiddler 的替代品,Charles 是收费的,而且没 Fiddler 好用。

使用模块加载器提供的 debug 功能

一般需要在页面上输入一些东西来完成资源映射。在手机上输入文字太麻烦了,而且屏幕太小,不太好展示这些内容,所以这个方案也不好。

综上所述,使用代理服务器的方案是可以从 PC 端沿用到移动端的。

但是上面我们也讲了,使用代理服务器也有一些缺点,那能不能在手机上无痛的实现绑定 hosts 的效果呢?答案是可以的。我们绑定 hosts 只是改变了域名的解析结果,正常情况下,域名是由谁来解析的呢?DNS !

自定义 DNS 的方案

我们只需要在开发电脑上运行一个特殊的 DNS 服务器,然后把手机网络配置里的 DNS 改成开发电脑的 IP 。我们在 DNS 服务器里做一些手脚,把静态资源的域名解析到开发电脑上,就可以实现和编辑 hosts 文件一模一样的效果了。

而在手机上修改 DNS 服务器地址,是非常容易的,比修改代理服务器还要通用。

为了实现这些,我写了一个非常方便配置的 DNS Server : xdns , 兼容 hosts 文件的语法,同时提供了比 hosts 文件更高级的语法。

比如,xdns 支持域名使用通配符的模式。支持 IP 地址用网卡接口名来作为占位符,运行时可以自动替换成该网卡接口上的 IPv4 地址,这样当你的开发电脑 IP 变了后就不需要修改配置文件。

安装和启动都非常方便,使用 Node.js 开发,Node 对于前端来说应该很熟悉。npm 安装后,一个命令就可以启动。具体请看文档:xdns

第一篇就到这里,如果你有其他方案能方便实现让浏览器/webview直接请求你本地的源码文件,欢迎留言探讨。

Macbook pro 更新镁光 M4 固件

11年上半年买的镁光 M4 SSD,最近两天老是无缘无故的死机,尤其是编辑完代码,保存的时候,猜测是硬盘出了问题。记得当时看到 M4 的固件是有缺陷的,工作时间超过一定时间后,在 windows 就会蓝屏。只是由于懒,一直没更新固件,今天被迫更新完固件,就不再死机了。

如果你的情况和我差不多,请继续往下看升级固件的过程。

1, 在 http://www.crucial.com/support/firmware.aspx 这里找到你用的型号,如果和我一样,就选择 Crucial m4 2.5-inch SSD 。

2, 下载 Manual Boot File for Windows and Mac® ,解压得到一个 ISO ,顺便可以看看官方的 instruction guide, 有中文文档。

3,如果你的 Macbook 有光驱,身边有刻录盘(CD 或者 DVD 都可以),用 Mac 自带的磁盘工具刻录此 ISO 镜像。

4,光盘放入光驱,关机。接着开机,同时按住 option 键。如果你的电脑能在选着启动盘的位置直接看到光盘,那就直接启动。如果不能看到,选择 recovery HD,从恢复盘启动成功后,点左上角的启动磁盘,可以看到下图:

选择启动磁盘

如果看到左边的有 windows 图标的光盘,那恭喜你,快成功了,选择它,启动磁盘。

5,升级固件工具会自动寻找符合条件的硬盘,中途需要手工输入一个 “yes” 进行确认,然后等待它自动升级,直到看到升级成功的提示。

6,退出光盘,按住电源键强制关掉电脑,重启,完成。

如果你的电脑支持从 USB 启动,也可以用官方文档里给的创建 USB 启动盘的方式来创建启动盘(需要一台 windows 机器),不过我使用此方法没成功,机器不能从此 U盘启动。

Javascript API alfred workflow

Alfred 2.0 是 Mac 下的一个提升效率的软件,可以搜索应用,搜索文件,使用的是 spotlight 的索引,所以非常快。还可以直接使用 google 搜索,自定义搜索,还有很多其他功能,你不妨点开上面的地址去看看。这里要说的是它的 workflow 功能,可以自己写代码去处理输入的 keywords ,然后指定打开某个 URL ,或者执行某个命令,打开某个文件等等等等。

http://www.alfredworkflow.com/ 这个地方有很多 Alfred workflow ,这个社区还不够成熟,找东西还不是那么方便,有耐心的话,你不妨去这里淘淘。想开发的话,暂时还找不到官方开发文档,还好这东西比较简单,看看例子和别人写的,应该很容易上手。

前两天晚上,我一边摸索,一边写,做了一个查找 Javascript API 的 workflow 。看下面的截图:

截图

用过 workflow 的人一看就懂。

当然现在做的还不够好,还不能直接显示每个 API 的简单使用方法,这个等我有空再优化优化。

下载地址在这里:http://api.allenm.me/jsapiworkflow/jsapi-workflow.alfredworkflow

源码托管在 Github: https://github.com/allenm/jsapi-workflow 欢迎 fork , 欢迎 pull request .

Alfred 绝对是在 Mac 下提升工作效率的利器,用 Mac 的同学快快试试吧。对了,workflow 是需要付费后才可以使用的功能。既然能够帮助你提升效率,付点钱也值得。

The new beginning

2012年12月21日过去了,大家都安然无恙,世界末日并没有来,所有人都重生了。我个人的工作也迎来了全新的开始。12月24号,我正式开始到支付宝上班了。

毕业两年半以来,一直在阿里B2B工作,在这里收获了很多,无论是在技术上还是其他方面都成长了不少。但是今年越来越感觉自己成长变慢了。是的,不论是谁,都不可能一直快速的成长,总会慢慢变缓。但是我还是觉得我应该去换个环境挑战一下,去尝试新的东西,或许可以唤醒差不多沉睡的激情。恰好这个时候有个机会去支付宝,那就去试试吧。

现在已经在新工作岗位一周了,很多东西对我来说都是新的。虽然还是干前端,前端的知识没有怎么变,但是各种工作环境、开发环境都是大不一样的。虽然都属于阿里集团,还是有很多东西不一样。很久没有过这种感觉了,很久没有过这种什么都要问,什么都不清楚的感觉了。我不知道是害怕,还是兴奋,或许这两种感觉都有吧。

总觉得不能让自己太舒适,在太舒适的环境下,很容易就失去战斗力,我不知道如果我在一家公司呆上十年,还能不能去换工作,能不能去适应其他公司。我觉得自己还是年轻的,所以有机会,就要换换环境,多看看不同的世界,增加自己的人生阅历。人活在这个世界上,不就去体验各种不同的事情吗?总干一种事情有啥意思,很快就是失去激情。

在B2B的这么多时间,从身边的同事身上学到了不少,在这里也感谢他们,在这里就不一一列举了,在这里列举姓名也不太好。这中间有前端、有后端开发、有设计师,有产品经理。最让我感动的,是 21 号这天,同事给我准备的礼物。同事很用心的准备了一个留言册,让熟知我的人都给我留言,还贴上我的照片。看到大家送我的话,倍感亲切,这些都是这两年多来,和我在一起共事的兄弟姐们们。我想当我不开心的时候,就拿出来翻翻,有你们的鼓励,我会走的更好。另外这个同事还准备了一个很特别的大号淘公仔,这个淘公仔是一个牛B的设计师根据我的样貌特意绘出来的。这两个礼物实在是太棒了,我已经无法用语言来表达我的感激之情。总之,感谢这位为我准备礼物的同事,为我绘淘公仔的设计师,以及在留言册上给我写祝福的同事们,你们这些朋友是我这两年来最大的收获,我会永远记住你们。

临走B2B的时候,还发生了一些不开心的事情,这里就说下吧,以后就不再提了。在运营产品的思路上,我和运营和产品人员发生了一些争执,我坚决不同意采用一些不那么阳光的手段去运营,我坚定相信,不使用这些手段也照样能把产品做起来。但是他们并不同意我,他们就开始举例微信啊、早期的淘宝啊,等等。或许是我有点理想主义吧,我一直的看法都是,并不能因为别人这样做,我们就要这样做,哪怕明知这个事情不那么阳光,违反价值观、违反道德。也并不是别人那样做成功了,我们不那样做就成功不了。不过争执归争执,我还是衷心祝福这个产品能做起来,能发展的好,这个是我最近半年来一直在为之付出的产品,多少含有我的心血,希望它好。

这应该是 2012 年的最后一篇博客了,2013 年的第一篇博客,应该是对 2012 年的总结吧,这一年我变化了很多,我收获了很多,也失去了很多,等过段时间在慢慢写吧。

未来怎么样?换个环境后,我会怎么样?我都不清楚,我只知道我会努力去把事情做好,去继续提高自己的能力。这一切不是才刚刚开始吗?

通过网络共享 hosts 配置的工具

Web dev 们经常需要绑定 hosts 来切换到开发环境吧。如果你是一名前端开发,还需要去调试不同浏览器下的表现吧,经常还要开几个虚拟机。一个项目组的成员也经常需要共享一套 hosts 。那么如何方便在多台电脑之间共享和管理 hosts 呢?

自从我发现 @oldj 写的一个 hosts 管理工具 SwitchHosts 支持从 URL 获取 hosts 后,我就想为这个功能写个小工具。这几天空余时间比较多,现在这个工具的第一版已经上线了: hosts.allenm.me

屏幕快照 2012-12-20 下午3.55.39

在这里输入的每组 hosts 都会给一个供 SwitchHosts 这个本地软件访问的 URL ,在这个软件中填入url即可:

屏幕快照 2012-12-20 下午3.57.28

如果 web 端的 hosts 有更新,在 SwitchHosts 这个软件上点下更新按钮即可。

是不是该抛弃不停的复制粘贴 hosts 的方式了?

PS ,SwitchHosts 支持 Windows, Mac, Linux , 需要跨平台的同学也不必担心

PS2 ,不要用低版本的 IE 访问 http://hosts.allenm.me , 从没测试过 IE 。

欢迎反馈意见和建议,说说你工作中遇到的 hosts 的相关需求,如果现在的工具满足不了你,说不定你说出来接下来就满足你了。

使用 SourceMap 来进行前端代码调试

今天在方凳会上做了一次 SourceMap 的分享。现在在博客上分享出来。

简介

什么是 SourceMap 呢?

在这个年代,对于前端开发来说,很少有用户浏览器执行的代码和我们写的 code 完全相同的情况。因为我们的代码一般要经过压缩、合并。另外现在还有 sass, less, stylus, coffscript, typescript 等等预编译语言。那么在这些情况下我们如何调试呢?SourceMap 就是为了解决这个问题而生的,虽然它还不够成熟,支持它的工具还不够多,但是我们能从它身上看到未来。

欲了解详情,请观看下面的 slide 吧。(有疑问或者建议可以在下面评论交流,或者微博 @allenm 进行交流)

sourcemap.001

sourcemap.003

sourcemap.004

sourcemap.005

Continue reading

BASE64 VLQ 编码规则

首先我们先来了解下 VLQ 是什么,VLQ 是 Variable-length quantity 的缩写,是一种通用的,使用任意位数的二进制来表示一个任意大的数字的一种编码方式。这个编码方式是在 MIDI 文件格式中定义的,用来节省空间。在其他地方也有很多类似这样的编码格式,比如在 Google’s protocol buffers 中,还有我们马上要讨论到的 BASE64 VLQ 中。想了解的更多,请参考wikipedia

我们先来看看 MIDI 中的 VLQ 编码是如何编码 137 这个数字的吧:(摘抄自 wikipedia)

  • 先把 137 转换成二进制:10001001
  • 7 bit 一组,把二进制分开,不足的补 0 ,变成 0000001 0001001
  • 把最低的7位拿出来,在最高位补0表示最后一位,变成 0000 1001,这个作为最低位,放在最后边。
  • 在其他组的最高位补 1 ,表示没有结束,后面跟着还有数据。在这里就是 1000 0001
  • 拼在一起,就变成了 1000 0001 0000 1001 .

这就是 VLQ 的变化过程。

那么什么是 Base64 VLQ 呢?和上面的变换过程有什么区别呢?

我们可以先来参考我博客的另外一篇文章,先来回顾下 Base64 编码:BASE64 编码规则

我们可以看到 Base64 是一种可以把二进制数据编码成用 ASCII 表示的一种编码规则,但是受限于 Base64 采用的字符集,一个 Base64 字符只能表示 6bit 的数据。所以上面的 VLQ 中 7 bit 一组的分组方式,在这里就要变成 5 bit 一组的分组了。

另外,Base64 VLQ 需要能够表示负数,于是规定了需要先把数字变成无符号数,用最后一位来作为符号标志位。我们直接来做一个变换吧,这样理解的最快。在例子中可以看到和上面的 VLQ 编码还是有一定差别的。

不妨还拿 137 来做示例吧。

  • 先把 137 转换成二进制:10001001
  • 由于 137 是正数,所以在最低位补0 变成 100010010
  • 按照 5bit 一组的方式分组,变成 01000 10010
  • 按照从低位到高位的顺序,以 5bit 一组为单位,依次拿出数据做转换。
  • 先拿出第一组 10010 , 因为后面还有数据,所以需要在高位补 1,变成 110010 ,编码成 Base64: y
  • 再拿出第二组,也是我们这里的最后一组,01000 , 由于是最后一组,所以在高位补 0 变成 001000,编码成 Base64: I
  • 按照从低位到高位的顺序把这些 ASCII 字符拼接起来,变成 yI

可以看到在 VLQ 中,编码顺序是从高位到低位,在 Base64 VLQ 中,编码顺序是从低位到高位。

那么如何解码呢?相信了解了编码过程后,解码过程就不必再讲解了。平时也基本不会去手工去算这些东西。这里推荐一个在线编码解码的网站:http://murzwin.com/base64vlq.html , 同时如果你想在代码中使用,Mozilla 的一个开源库里有相关实现:https://github.com/mozilla/source-map/blob/master/lib/source-map/base64-vlq.js,这个是 javascript 的实现,其他语言的实现,如果你需要,请自己找找,或者根据编码规则自己写一个。

说了这么多,好像还没讲 Base64 VLQ 运用在什么地方,这次我不打算说了,准备下一篇博客再来解释这个问题。

如果你想在 python 项目中使用 stylus

Stylus 是用 node.js 写的,所以在 nodejs 项目中集成 Stylus 是一件很方便的事情,特别是 expressjs 这样的 web framework 直接配置下就可以用了。在 expressjs 中一旦你修改了 .styl 文件,立马就会被转换成同名的 .css 文件。

如果你想在 Python 项目中获得这样的特性,不妨来试试我写的一个 python package 吧: live-stylus

由于这个 package 依赖 python stylus ,python stylus 最终是要依赖 nodejs 和 stylus node package 的,所以你还是需要安装 nodejs 和 stylus node package 的。

如果你没有使用过 nodejs ,请在 nodejs 官网查看安装方法,然后:

npm install -g stylus

即可完成 stylus node package 的安装。然后:

pip install live-stylus

即可安装 live-stylus 。使用方法非常简单,比如在一个 Flask 项目中:

from flask import Flask
from live_stylus import ConvStylus

app = Flask(__name__)

from views import *

if __name__ == "__main__":
    app.debug = True
    ConvStylus()
    app.run()

这样就可以监控你项目中的所有 .styl 文件的变化,从而实时的转换成 .css 文件了。更多的说明和使用方式请参考此项目的github 主页