前端 WebView 指南之 iOS 调试篇

Web开发过程中离不开调试,WebView 页面开发更是如此。本篇会和大家讲述在 iOS WebView 中一般是如何调试的。其实除去系统差异带来的区别之外,两者调试的原理上其实都差不多。

抓包

抓包即我们查看下 WebView 中的所有网络请求,在很多无法获取到机器的时候非常有用。通常页面行为不正常往往是接口请求的参数不正确,或者是接口返回的数据有异常。甚至于页面行为存在打点,根据打点请求来判断行为是否正常。通过这种“望闻问切”的方式,有些问题能够浮出水面。市面上抓包软件很多,Windows 上大家一般都是用 Fiddler, Mac 上则使用 Charles,还有其它的这里就不一一列举了。不过软件很多原理确实一样,简单的说来则是使用 HTTP 代理将所有的请求转发到软件记录本次 HTTP 请求的相关数据。

首先我们需要保证手机和电脑在同一个局域网中,软件中开启 Proxy 配置,这里以 Charles 为例,如图勾选"Enable transparent HTTP Proxying"即可。然后手机 WiFi 上配置 HTTP 代理 IP 为你的电脑 IP,端口为刚才软件中配置的端口(默认8888)。配置完后如无问题就可以在软件中看到请求流了。我们可以类似于 Chrome 开发者工具中的 Network 一样详细的查看请求的请求报文和响应报文。

Charles Enable Proxy

阅读全文

前端 WebView 指南之调试篇

WebView 是一个客户端浏览器控件,可以实现加载并渲染网页的逻辑。但是这个控件并不能完全同等于浏览器,而且我们页面的一些行为会依赖客户端的交互所以我们需要在 WebView 环境中进行调试。下面我就来说一说简单的 WebView 调试方法。

抓包

抓包即我们查看下 WebView 中的所有网络请求,在很多无法获取到机器的时候非常有用。通常页面行为不正常往往是接口请求的参数不正确,或者是接口返回的数据有异常。甚至于页面行为存在打点,根据打点请求来判断行为是否正常。通过这种“望闻问切”的方式,有些问题能够浮出水面。市面上抓包软件很多,Windows 上大家一般都是用 Fiddler, Mac 上则使用 Charles,还有其它的这里就不一一列举了。不过软件很多原理确实一样,简单的说来则是使用 HTTP 代理将所有的请求转发到软件记录本次 HTTP 请求的相关数据。

首先我们需要保证手机和电脑在同一个局域网中,软件中开启 Proxy 配置,这里以 Charles 为例,如图勾选"Enable transparent HTTP Proxying"即可。然后手机 WiFi 上配置 HTTP 代理 IP 为你的电脑 IP,端口为刚才软件中配置的端口(默认8888)。配置完后如无问题就可以在软件中看到请求流了。我们可以类似于 Chrome 开发者工具中的 Network 一样详细的查看请求的请求报文和响应报文。

Charles Enable Proxy

阅读全文

前端 WebView 指南之 iOS 交互篇

前文我们介绍了 Android 的 WebView 交互方式,iOS 从原理上来说和 Android 还是非常类似的。在 iOS 中 WebView 需要分为UIWebView 和 iOS8 中新增的 WKWebView 两种类型。其中 WKWebView 相较于 UIWebView 优势在于能够直接使用系统 Safari 渲染引擎去渲染页面,支持更多的 HTML5 特性,渲染性能也会更好点。由于对 iOS 开发了解不太多,以下的代码大多是网络整理,没有 swift 的实现,如果有任何错误还请及时联系。

客户端调用 JS

两个 WebView 类型提供了不同的调用方式,但是基本上可以归类成以下两种:

evaluateScript

在 UIWebView 中,iOS7+ 提供了 JavascriptCore 让我们能够直接在 WebView 中获取到 JSContext,也就是当前执行环境的 JS 上下文。在这里我们就可以获取到对应的 JS 方法并执行,是非常高效的执行方式。同时这种方式的好处是能够拿到 JS 执行的结果,并转换成对应的 JS 类型。定义好 jsContext 之后就可以调用 evaluateScript 方法来执行 JS 了。

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //设置JS执行报错捕获
    [self.jsContext setExceptionHandler:^(JSContext *context, JSValue *exception){
        NSLog(@"%@", exception);
    }];

    JSValue *value = [self.jsContext evaluateScript:@"document.title"];
    self.navigationItem.title = value.toString;
}

|Objective-C 数据类型 | 对应 JavaScript 数据类型|
|--------------------|---------------------|
| nil | undefined|
| NSNull | null|
| NSString | string|
| NSNumber | number, boolean|
| NSDictionary | Object object|
| NSArray | Array object|
| NSDate | Date object|
| NSBlock | Function object |
| id | Wrapper object |
| Class | Constructor object |

阅读全文

前端 WebView 指南之 Android 交互篇

WebView 是移动端应用中的一个控件,提供了类似浏览器可以在 App 中加载网页的功能。现在市面上很多应用都会使用这种方式内嵌一些 h5 页面用来实现产品功能。使用这种方式带来的好处就是支持快速迭代更新,并且页面的功能是全网升级。当然目前 RN 和 Codorva 给我们带来的热更新方案也是可以的,只是目前 Apple 的态度很拒绝,这里我们略过不表。在 WebView 中的网页势必存在和客户端进行交互的动作,进行数据的共享。下面我们就来说说 Android WebView 中 JS 和 Native 的交互方式。

客户端调用 JS

loadUrl()

我们明白 WebView 其实就是在加载网页,所以客户端可以直接访问 javascript:console.log('hello') 这样的伪 URL 即可实现在页面注入需要执行的 JS 代码。调用方法如下:

WebView webview = (WebView) findViewById(R.id.webView);

webview.loadUrl("javascript:console.log('hello')");

这样我们就实现了调用 JS 的目的了。loadUrl() 的方案从另外一个角度来看可以算是 hack 方案了,对客户端来说,他们的 JS 交互本质上其实就是一个拼接 JS 字符串的过程。

evaluateJavascript()

刚才我们也说了 loadUrl() 不是 Android 的正经解决方法。好在官方也想到了这点,在 Android 4.4+ 之后,官方给提供了原生的方法支持调用,那就是 evaluateJavascript()。这个方法最大的好处就是能够直接在一次执行的时候获取到 JS 返回的结果。如果是使用 loadUrl() 的方式的话,执行完后对客户端来说这句话就结束了,如果想要拿到返回的结果的话另外需要 JS 调用客户端的方法返回。

阅读全文

我的第一款Drone插件

Drone 是一款基于Docker的CI工具,不仅运行环境是容器化的,甚至于 CI 流中的每一个插件也是 docker 容器。基于容器的 Drone 插件一大特色就是允许我们使用任何语言去开发插件,Python, PHP, Nodejs, bash... 这些都是可以的。每个开发者都可以使用自己熟悉的语言去开发自己想要的插件。Drone 的官方插件市场罗列了很多插件,并且在文档提供了 GolangBash 版本的插件开发文档,并开源了一个插件脚手架

官方插件里有一个 drone-telegram 插件,不过插件目前是不支持自定义 telegrame 请求地址的,对于我这种机器部署在国内需要使用反代的方式访问 telegram 的用户来说不是很方便。搜索到 node-telegram-api 这个模块可以配置,下面我就简单说说基于 Nodejs 写一个 telegram 消息通知的插件。

阅读全文

反代访问 Telegram

最近有使用 Telegram 机器人相关的服务,之前是部署在境外服务器上,运行良好。某天脑子抽风把服务迁移到国内机器了,发现一直 Timeout,后来才反应过来 Telegram 被墙了。由于我使用的是 Telegram bot 相关服务,请求的都是 https://api.telegram.org 这个域名的地址,于是我就想到了能不能借助国外的机器设置反向代理解决这个问题。

中间人劫持

首先我想到的是不修改服务代码,直接将我本地的 api.telegram.org 解析到我的境外服务器,然后在服务器上做反向代理。这个方案是可行的,唯一需要解决的是服务器上 api.telegram.org 证书信任的问题。解决方法也很简单,服务器上自建证书后在本地设置强制信任即可。

这里比较坑的一点在于网上给的教程一般都是说如何在 Linux 上创建自建证书然后在客户端例如 Windows 上信任。很少有教程会说如何在 Linux 上信任的,所以当时搜的资料很少。使用如下命令可为 Linux 添加证书:

sudo mkdir /usr/share/ca-certificates/extra
sudo cp foo.crt /usr/share/ca-certificates/extra/foo.crt
sudo dpkg-reconfigure ca-certificates

阅读全文