2008年12月29日

Extjs Django Adobe Air全用上 – SimpleLife开发小记(下)

作者 非鱼

Extjs版的SimpleLife靠一段落,接下来要攻克的就是Adobe Air了。这个东西出来的时间已经很长了,前面看它的开发方式一直云里雾里,下手似乎有些困难,但是唯一的印象就是,通过AIR可以直接把HTML和JS写的网站包装成客户端程序来运行。既然如此,那用Extjs的富客户端方式写的网站岂不是可以直接移植成客户端程序?果然有如此好事?

于是,又是一番疯狂搜索,看了一些AIR的入门文章,写了一个HelloWorld的网页,根据网上的说明,建个目录,写个application.xml的起始文件,下载了AIR SDK,无需安装,解压后直接把bin目录配置到系统环境变量的Path里面去,在命令行窗口里进入网页所在目录,运行adl application.xml,哇,果然很帅啊。

接下来,把SimpleLife里面的index.html(整个网站就这么一个html文件),以及用到的Extjs相关的文件全部拷过来,把js里面读写数据涉及到的URL全部加上域名变成绝对路径,再启动,哇塞,真的可以启动起来啊!

 

但是用AIR做客户端的初衷就是可以让这东西方便的停留在桌面上,随时使用,当然不好像网页似的搞个全屏大的程序了,所以,最理想的布局就是像QQ面板那样折叠。在extjs的Demo里面,有左侧导航栏就是这个样子的,看起来应该也很容易。谁知道,真的想实现这个效果,还真是花了不少功夫。最终的结果是,new一个Ext.ViewPoint,这个东西是自动填充整个body区域并负责内部组件布局的。然后把它的layout属性设成border。border类型的布局就是经典的应用程序布局,把整个body分成东南西北中五大块,除了center,其它都是可选的。所以在ViewPoint的items里new一个Panel,将Panel的region属性设为center,这个Panel就自动充满整个窗口了,然后把这个Panel的layout属性设为accordion,然后把四个Panel放在它的items属性数组里。这样四个Panel就变成QQ面板那样的自动伸缩样式了。

嗯,看起来不错。但是随后就遇到了另一个极其困难的问题,DataView里面根据XTemplate生成的各个操作按钮,都是用的<a href="javascript:;" onclick="ShowEdit()">这样的代码,结果,现在在AIR里所有的onclick都失效了,怎么点都不管用。

随后查阅air的官方文档和开发手册,里面有提到air的安全模型的问题,主程序域里的html代码里是不允许使用onclick这种代码的,因为主程序域的权限极高,可以删除用户的硬盘文件。不过你可以在主页面里用一个iframe加载另一个页面,这个页面会运行在另一个域里面,而它就可以使用onclick或者eval这样的函数,但是,这个域的安全性却决定着它不能操作本地文件和URL,所以读写远程数据的事情它又做不了。

手册里面的解决方案是在主页面里定义一些函数,然后在子页面里可以使用它的父域这个属性来执行父页面里面定义的函数,这样就可以完成两者之间的通信了。但是,这也太麻烦了吧。麻烦还是其次的,当我把页面布局的代码放到iframe里面的页面里时,整个布局就被破坏了,宽高很难掌握。于是还是回到了原来的轨道上,只是得换个思路解决问题。

有趣的是,Panel的标题栏上的两个按钮功能却不受影响,仍然可用。那就是说,用Ext生成的按钮是没有问题的。但是,如何在XTemplate里面生成Ext按钮呢?又花了一个小时,最终证明XTemplate真的是很单薄,无法在里面插入JS函数,也无法把它的模板字符串跟JS函数串联起来。

换一个思路来解决问题,在DataView生成以后,再用Ext来替换其中的内容。尝试在DataView的render事件中处理,发现这个事件被调用的时机有点问题,最后测试在DataView里面的JsonStore的load事件里进行处理,倒是可以用了。但是一个更神奇的问题出现了。在load事件里根据DataView生成的代码里面a的id找到每一个a,给它添加click事件,调用一个匿名函数,在该函数里alert出这条记录的title。结果,所有的a点击弹出的都是第一条的title,怎么看这个循环都没有写错啊。

在这个地方又折腾了一个小时,extjs的demo很不详细,API文档虽然详细却又没有demo和参数的说明,无论如何找不到解决方案。最后,又是使用了一个折衷方案:让a的onclick的函数传递this.id作为参数,这下所有的a点击的时候都能正确的调用函数了。把原来调用显示编辑框的时候需要的三个参数用下划线串起来作为每个a的id,然后被调用的函数再拆分字符串,还原成三个参数去调用原来的函数,嗯,测试一下,没问题了。

按照原来页面的显示编辑窗口的方式,这个窗口仍然是以一个弹出层的形式显示在原来的浏览器窗口里,现在就是显示在AIR的窗口里,而AIR窗口现在是一细条,对话框还显示在这里面就有点不爽了。其实ext的air命令空间里是有个函数可以创建普通的弹出窗口的(就像普通的应用程序的新窗口一样,完全独立于主窗口的),但是在air里面,这个弹出的窗口还需要一个html,这个html还需要一套初始化窗口的js,而如何控制这个窗口的宽高就成了问题。因为这个窗口根据不同的任务类型,大小是不一样的。

通过这种调用方式,主窗口往弹出窗口里传递参数只能通过URL来传递,比如edit.html?id=1&type=2,然后在子窗口的js里取window.location再用字符串解析的方式把所有的参数拆出来。非常的麻烦,倒也是可行的。算了,下次改进的时候再说吧。

测试完成以后,根据参考手册上的说明,生成一个密钥文件,然后将整个目录打包成air文件,发现无法调用这个air文件。原来AIR的SDK只是用来开发,不带运行功能,汗……这一点跟java和.net都不一样。再下载air runtime(发现也需要15M,有点大),安装。然后双击自己生成的air文件,会提示是否要安装,安装界面上显示开发商是未知。想要把这个开发商变成自己的名字,需要像ssl一样购买versign的证书,全球一共就那三四个能卖这种证书的,贵的要1800,便宜的也需要1280一年,靠,当我的钱是天上掉下来的啊?看来我是无福消受了。

把生成的air文件发给朋友,安装测试,完全没有问题。嗯,折腾了一天,总算有点收获。只是不知道这玩意儿跟用.net写个windows客户端程序相比有什么优点?大概就是同一个air程序可以在mac,win,linux上安装并运行(因为js本身兼容性不错)。不过AIR开发的程序丝毫不为开发人员考虑问题,它有着js开发的的同样的缺点,你打包出来的air程序只是个普通的zip文件,而且安装完成后你所有的源代码都在它的安装目录下,丝毫没有加密,别人也完全可以再打包……不知道adobe当初这样设计的初衷是什么?是为了让新手可以得到更多的免费demo吗?

不过既然有了这类似SOA架构的网站核心,用什么方法开发前端软件就是小意思了,甚至可以做成Vista侧边栏组件,Yahoo widget组件,甚至猪八戒桌面程序的组件。但是目前的登录方式只采取了cookie的方式来记录用户,这要求该开发方式能够接收并保存cookie。想达到最大的兼容性,还需要换一种方式,就是登录的时候直接把用户的sessionid返回给客户端,然后客户端每次请求都发送这个sessionid作为辅助参数,这样就可以让任何开发语言都可以使用了。

如果你有兴趣试试这个,可以下载:http://sl.unfish.net/uploads/SimpleLife.air 注意大小写。