浅析支付宝钱包插件

来源:互联网 发布:手机淘宝打不开淘口令 编辑:程序博客网 时间:2024/04/28 13:38

参考:http://imallen.com/blog/2013/06/26/inside-alipay-plugin.html

昨天看到唐巧分析了支付宝钱包插件的实现原理,今天也趁热打铁研究了一下支付宝插件的结构和代码,很多时候逆向思考也可以为自己积累很多有用的经验(即便实际实现方式和自己所想有出入)。

承接唐巧的上文,本文同样以彩票插件为例,如果你没有下载该插件的压缩包,用如下命令下载。

wget http://download.alipay.com/mobilecsprod/alipay.mobile/20130601021432806/xlarge/10000011.amr

并改为 zip 后缀,解压。

根目录根目录

  • CERT:内容为各文件的特征值,特征值可以是重复 hash 和 salt 多次后 base64 的结果,解压插件后支付宝理应检查文件特征值以确定来源可靠
  • Manifest.xml:插件的描述文件,都有注释,易懂,其中定义了业务包 ID、名称、介绍、版本等信息,也定义了版本兼容性、能力集、依赖关系、入口文件等

resres

  • res:资源文件,仅有图标,奇怪的是代表 Android 尺寸的目录下没有文件,可能因为唐巧抓的包是 iOS 的?

wwwwww

  • www:前端代码,目录结构跟一般 Web 开发相似,其中 demo 下是 HTML 代码

demodemo

  • demo:HTML 代码,子目录都是拼音缩写,比如 ssq 代表双色球,根据 Manifest.xml 描述,index-alipay-native.html 为插件入口页面

cpcp

唐巧打开 index-alipay-native.html 给大家看过了,你会发现 Cells 都是不能点的,因为页面尚未初始化,代码中可以看到形似 <a rel="ssq/ssqbet.html"> 的代码。显然这代表双色球的子页面,我简单猜测一下用 rel 的原因:

首先,点击 Cell 在客户端触发的必然是 Native 的 pushViewController:,用 href 同样可以通过webView:shouldStartLoadWithRequest:navigationType: 触发,但这样会在某些意外情况下造成点击后页面直接跳转。此外如果最终是用形如 push://10000011/ssq/ssqbet.html 的协议来实现 Native 跳转,用 rel 再注入 JS 处理可以防止客户端逻辑的显式暴露(如长按、拷贝,曾经的新浪微博客户端长按评论可以看到类似 comment:// 的协议,不见得有多大危害,但是值得避免)

页面底部有如下代码:

1234567891011
    //配置时间戳,解决浏览器或者webview cache问题    seajs.config({        map: [            [ /^(.*\.(?:css|js))(.*)$/i, '$1?000021']        ]    });  function onDeviceReady(){      seajs.use('../js/appnav/nav',function(Nav){          Nav.initialize();      });  }

略懂前端开发的话,果断猜测 onDeviceReady() 是在页面加载完毕后,由设备调用的初始化方法,于是尝试在 Console 中输入onDeviceReady() 执行,点击 Cell,报错如下:

onDeviceReadyonDeviceReady

跟到 nav.js 里可以看到是在 pushWindow 中报错的,错误为 alipay 未定义,粗略判断 alipay 为客户端注入的变量,这里看到的调用形如 alipay.navigation.pushWindow(obj.attr('rel')) 用到了上述 rel 属性,最终应该会触发客户端类似 [self pushWebControllerWithURL:url] 的代码来推入下一个 VC,这位我们最终尝试实现能跑这个插件的 Demo 提供了一些思路。

用 onDeviceReady 可以完成大部分页面的初始化工作,如 ssq/ssqbet.html,在浏览器里也能响应下拉机选操作,你会发现,这些插件的屏幕尺寸兼容性和浏览器兼容性极佳:

ssqbetssqbet

再如 jczq/jczqmatch.html,甚至可以读到场次数据并完成数据初始化了

jczqjczq

在这里我们又发现了两个有意思的信息,它们被写在 meta 信息里,根据字面,很容易理解,它们分别定义了 navigationBar 的title 和 rightBarButtonItem,以及点击 rightBarButtonItem 触发的 JS 函数。此时你如果比对着使用客户端就知道这个筛选对应着怎样的表现和交互,这些都为我们写 Demo 提供了线索。

尝试在 Console 输入 rightBar(不带括号)查看其定义,又能得到很多有用的线索,比如点击 rightBarButtonItem 触发的是推入filterpage,这个 filterpage 则是在 js/jczq/jczqmatch.js 中定义的。

jczqjczq

此外,结合 jczqfilter.html 的内容和 rightBar 函数,可以看到主页面利用 HTML5 的 localStorage 为 filter 页面提供了数据(这为纠结于 UIWebView 如何给 push 进来的下一个 View 提供数据的我,提供了很好的思路,值得借鉴)

1
    localStorage.setItem('__tbcp__filter', JSON.stringify(obj))

不知不觉写了 2 个多小时了,发现通过文字表达出来要比分析本身还费时。不过,至此,支付宝插件的大体框架已经比较清晰了,和 Native Code 的交互方式、数据传递方式也有了一定的思路。

接下来的几天我会尝试写一个 Demo 让这样一个插件基本能跑起来(除了核心的下单、支付环节,这显然不是我力所能及的)。跟着我的分析,相信读者对 WebView + Native Code 的混合编程模式应该也有了一些新的认识。

希望我有足够的动力和时间写 Demo,因为这个 Demo 可以帮助大家更清楚地理解支付宝插件中用到的 WebView + Native Code 的 Hybrid 开发方式。


原创粉丝点击