html5test是一个测试浏览器对HTML5支持情况的一个web应用。在github上可以看到作者公布的一些测试结果。Adobe AIR2对HTML5, CSS3都提供了增强,我记得用html5test对AIR1.5的测试结果在20分左右,今天再用它测试一个AIR2。demo代码如下:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="init()">
<fx:Script>
<![CDATA[
import spark.components.Group;
import spark.core.SpriteVisualElement;
protected var htmlLoader:HTMLLoader;
protected var htmlUI:SpriteVisualElement;
private function init():void{
htmlLoader=new HTMLLoader();
htmlLoader.width=800;
htmlLoader.height=this.height;
htmlLoader.load(new URLRequest('http://html5test.com'));
htmlUI=new SpriteVisualElement();
htmlUI.addChild(htmlLoader);
this.addElement(htmlUI);
}
]]>
</fx:Script>
</s:WindowedApplication>
运行后发现得分依然是很低——46分,跟Android 1.6的得分42分差不多,不过跟iPhone, iPod touch的120多的得分来比真是差的很远。Adobe官方有一篇文章讲到了AIR2对HTML, CSS, JavasScript的支持情况以及不支持的个中缘由。
AIR2的正式版总算是出来了,前些天SDK也放出来了,于是就鼓捣一下它的一些新特性,其中一个特性就是录制Microphone,本地录制,本地存储,不需要FMS的协助。
为了完成这个录制Microphone的功能,我们需要先做如下事情:
- 下载AIR2 SDK并覆盖到Flash Builder的SDK中。
- 下载adobe官方用于保存WAV音频的开源库WAVWriter。
接下来,新建一个AIR2工程,为了力求简单,本例中只用一个按钮,用于开始录制和停止录制。UI代码大致如下:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="init()">
<fx:Script>
<![CDATA[
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout paddingTop="10" horizontalAlign="center"/>
</s:layout>
<s:Button id='controlBtn' label="{controlBtnLabel}" click="clickHandler()"/>
</s:WindowedApplication>
下面开始编写逻辑代码,程序启动后,初始化Microphone, 设置音频文件保存路径。
import com.adobe.audio.format.WAVWriter;
import mx.controls.Alert;
protected var targetFile:File;
protected var microphone:Microphone;
protected var recordedData:ByteArray;
private var recordFlag:Boolean=false;
private static const START_RECORD:String='start recording';
private static const STOP_RECORD:String='stop recording';
[Bindable]public var controlBtnLabel:String=START_RECORD;
private function init():void{
if(!Microphone.isSupported){
Alert.show("Cannot find a Microphone");
controlBtn.enabled=false;
return;
}
targetFile = new File(File.desktopDirectory.nativePath+"/sound.mp3");
microphone = Microphone.getMicrophone(0);
microphone.setSilenceLevel(0);
microphone.rate = 44;
}
然后处理按钮的动作,执行开始录制或停止录制操作。
private function clickHandler():void{
if(recordFlag){
controlBtnLabel=START_RECORD;
recordFlag=false;
this.stopRecording();
}else{
controlBtnLabel=STOP_RECORD;
recordFlag=true;
this.startRecording();
}
}
开始录制时,先删除原有的音频文件,然后监听Microphone的SampleDataEvent.SAMPLE_DATA事件。
public function startRecording():void{
if(targetFile.exists){
targetFile.deleteFile();
}
recordedData=new ByteArray();
microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, onMicData);
}
private function onMicData(event:SampleDataEvent):void {
recordedData.writeBytes(event.data);
}
当点击了停止录制时,移除Microphone的事件监听,并使用WAVWriter来生成一个音频文件。
public function stopRecording():void{
microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, onMicData);
saveWAV();
}
public function saveWAV():void{
var wavWriter:WAVWriter = new WAVWriter();
var stream:FileStream = new FileStream();
recordedData.position = 0;
wavWriter.numOfChannels = 1;
wavWriter.sampleBitRate = 16;
wavWriter.samplingRate = 44100;
stream.open( targetFile, FileMode.WRITE );
wavWriter.processSamples( stream, recordedData, 44100, 1 );
stream.close();
}
数小时前,Adobe labs上放出AIR 2 RC1版本,从它的release note中可以发现不少的新特性:
- 增强打印机的支持
- 支持TLS/SSL socket通信
- 支持外部存储设备检测
- 具备高级网络功能,如secure sockets, UDP, 监听sockets
- 支持本地代码集成
- 使用默认应用程序打开文件
- 多点触摸,手势支持
- 增加获取麦克风数据的API
- WebKit更新至支持HTML5/CSS3
- 全局错误处理
- 跨平台印刷能力提升
- 安全性提升
虽然正式版还没有发布,不过已经告别Beta版本了,于是立刻利用这个最新的SDK编译了Twitter Air,并无bug修改和新功能加入。
由于Adobe AIR 2 Beta 1目前已经不在被支持,所以基于该虚拟机创建的应用程序无法正确启动了,也包括我基本上每天都会使用的twitter客户端Twitter Air。不过把系统时间设置在5月1号及其以前则可以正常启动,但是每次启动之前都要修改系统时间,启动之后又要改回来,这样未免太繁琐,于是想写个一站式解决方案的脚本。
大致思路是这样的:
- 修改系统日期至2010年5月1日前某一天
- 启动Twitter Air
- 完全启动后(大约要1秒钟),改回系统时间
然后查阅Google baidu之,最后用Ruby完成脚本:
# 获得当前系统时间
now=Time::now
# 修改系统日期至2010年4月1日
system('date 2010-4-1')
# 创建一个进程执行Twitter Air
IO.popen("D:/AIR Program Files/Twitter Air/Twitter Air.exe",'r')
# 等待3秒让Twitter Air启动完全
sleep(3)
# 改回系统日期
system("date #{now.year}-#{now.mon}-#{now.day}")
seesmic-as3-xmpp是XMPP在ActionScript脚本上的一个实现。或许更加出名的是xiff这个框架,但是目前它并不支持TLS加密,所以需要要TLS支持的时候,更好用的是seesmic-as3-xmpp。
人人网的IM工具校内通是基于XMPP协议进行通信的,根据网络上各路神仙的指示,使用基于XMPP框架的API可以很方便的更新一条状态。那么,在我使用桌面工具Twitter Air更新twitter的时候也可以同步更新到人人网,虽然人人网提供了REST API供应用程序调用,但是它们的验证机制明显需要花费更多的时间。
要想成功地连接到人人网,账号密码是必不可少的,人人网用户注册账号是Email地址,Email地址前的用户名无法保证唯一性,所以人人网用户都有一个额外的数字标识,就像QQ号一样,登陆之后可以从浏览器地址中得到该标识,例如http://www.renren.com/Home.do?id=9527这个用户的ID是9527。在进行XMPP连接前,要设置连接的JID, PASSWORD和SERVER三个值,RFC 3920中规定一个完整的JID应该是id@domain/resource这样一个形式,resource可以作为一个账户多处登陆的会话ID。按照这个规定,人人网用户9527的JID则是9527@talk.xiaonei.com。
下面在AIR中试着更新人人网的状态。打开Flash Builder新建一个AIR工程,将seesmic-as3-xmpp加入到编译路径,工程代码大致如下(MXML省略):
import com.hurlant.crypto.tls.TLSConfig;
import com.hurlant.crypto.tls.TLSEngine;
import com.hurlant.crypto.tls.TLSEvent;
import com.hurlant.crypto.tls.TLSSocket;
import com.seesmic.as3.xmpp.XMPP;
import com.seesmic.as3.xmpp.XMPPEvent;
var xmpp:XMPP;
private function init():void{
xmpp=new XMPP("USER_ID@talk.xiaonei.com","USER_PASSWORD","talk.xiaonei.com");
xmpp.addEventListener(XMPPEvent.SESSION, handleSession,false,0,true);
xmpp.setupTLS(TLSEvent,TLSConfig,TLSEngine,TLSSocket);
xmpp.connect();
}
private function handleSession(e:XMPPEvent):void {
var status:String="a presence sent by AIR using XMPP protocol";
xmpp.sendPresence(status);
}
设置好正确的ID和密码,编译运行,然后登陆人人网就会发现状态已经更新了。have fun!
今天我终于升级了twitter客户端软件Twitter Air。相对于上一版本,V0.3加入了search user, follow user, unfollow user, change profile image等功能。虽然还没有支持direct message,但是这些功能已经基本满足日常需求了。
Twitter Air基于Adobe AIR技术构建,客户端需要安装Adobe AIR2 beta1,而目前AIR的正式版本为1.5,所以使用该软件时需要先手动安装Adobe AIR2 beta1,而安装了Adobe AIR2 beta2的用户可能需要先卸载AIR再安装Adobe AIR2 beta1。在这方面,我也十分恼火,希望Adobe尽快放出AIR2的正式版。
首先,苦于没有twitter账号朋友可以从这里进行注册:http://twitese.darkices.com/。
由于某些原因,目前国内无法直接访问twitter.com的REST API,所以Twitter Air使用了API Proxy来获取和更新数据。目前使用的API proxy是本人空间的一个地址:????(已移除) 我并不保证这个地址永久可用,所以在软件不能使用的情况下可以搜索其它可用的API Proxy。
当然,如果你拥有一个国外的PHP空间,也可以搭建自己的API Proxy,具体方法请参考:http://code.google.com/p/tweetr/
最后要感谢一些开源框架的作者,没有他们的杰出贡献,Twitter Air也不能这么顺利的完成:
Robotlegs是一个纯ActionScript(指不依赖Flex框架中的代码或特性)写成的MVC微型架构。它简单易用,为应用程序的设计提供一个清晰的层次结构,并且它的DI(Dependency Inject)特性容易让人对这个迷人的框架产生“依赖”。
tweetr是一个twitter api的library, 它既包括一个AS3的API, 还包括一个PHP的API proxy,更新一条tweet,follow一个user都靠它们来实现了。
kingnarestyle是一套Flex skin, 这套黑色皮肤是十分受本人喜爱的,这里“严重”声明一下。
Merapi是一个用于Java和AIR之间通信的桥接库。通过它可以极大的扩展AIR在本地的执行能力,当然前提是客户端不仅装有AIR运行时虚拟机,还需要安装有Java虚拟机。Merapi通过Socket来通信,使用Adobe的AMF作为数据传输格式。下面看看如何在Flash Builder中创建一个基于Adobe AIR的桌面软件。
在Java和ActionScript两端都存在一名为Bridge的类,它是一个Singleton,用来注册消息类型和发送消息。在这个例子中,AIR向Java端发送一个名为”flashEvent”的消息,消息内容是一个Dictionary实例;并且监听名为”javaEvent”的消息。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import demo.JavaMessageHandler;
import demo.SerializeMessageHandler;
import merapi.Bridge;
import merapi.messages.Message;
import merapi.error.MerapiErrorMessage;
private function initApp():void{
//register a error handler
new SerializeMessageHandler();
//send a message
var message:Message=new Message();
message.type="flashEvent";
var data:Dictionary=new Dictionary();
data["name"]="colorhook";
message.data=data;
message.send();
//register a message handler
Bridge.getInstance().registerMessageHandler("javaEvent",
new JavaMessageHandler());
}
]]>
</mx:Script>
</mx:WindowedApplication>
CoreErrorHandler继承自EventDispatcher,实现了IMessageHandler接口,它在构造函数中就集成了错误处理。所以不需要显示的在Bridge中注册,而是构造一个实例就行了。SerializeMessageHandler继承自CoreErrorHandler,用来处理全局错误。
package demo{
import merapi.handlers.mxml.CoreErrorHandler;
import mx.rpc.events.ResultEvent;
public class SerializeMessageHandler extends CoreErrorHandler{
public function SerializeMessageHandler(type:String=null){
super(type);
this.addEventListener(ResultEvent.RESULT,onMessageResult);
}
private function onMessageResult(event:ResultEvent):void{
trace("SerializeMessageHandler:",event);
}
}
}
JavaMessageHandler实现了接口IMessageHandler,并在handleMessage方法中输出从Java中返回的数据。
package demo{
import merapi.handlers.IMessageHandler;
import merapi.messages.IMessage;
public class JavaMessageHandler implements IMessageHandler{
public function handleMessage(message:IMessage):void{
trace(message.type);
trace(message.data);
}
}
}
编译运行会发现控制台输出SerializeMessageHandler中的trace信息,因为目前还没有开启Java端的ServerSocket。所以下面来启动一个Java程序。首先调用Bridge.open()来启动ServerSocket。然后监听名为”flashEvent”的消息。
package demo;
import org.apache.log4j.Logger;
import merapi.Bridge;
public class Application {
protected Logger logger=Logger.getLogger(Application.class);
public Application(){
logger.info("Application start");
//open Bridge
Bridge.open();
//register a message handler
Bridge.getInstance().registerMessageHandler("flashEvent",
new AIRMessageHandler());
}
public static void main(String[] args){
new Application();
}
}
在消息处理器AIRMessageHandler中,输出来自Flash的数据,AMF将ActionScript中的Dictionary映射为Java中的Map。接受到数据之后,我们再从Java中发出一个Message,该Message携带了一个List类型的数据,在Flash中,它会被映射成Array类型。
package demo;
import java.util.*;
import org.apache.log4j.Logger;
import merapi.handlers.IMessageHandler;
import merapi.messages.IMessage;
import merapi.messages.Message;
public class AIRMessageHandler implements IMessageHandler {
protected Logger logger=Logger.getLogger(AIRMessageHandler.class);
@Override
public void handleMessage(IMessage message) {
//handle message
logger.info(message.getType());
Map<String,String> map=(Map<String, String>)message.getData();
logger.info(map.get("name"));
//send a new message
Message newMessage=new Message();
newMessage.setType("javaEvent");
List<String> list=new ArrayList<String>();
list.add("Flash Player");
list.add("AIR");
newMessage.setData(list);
newMessage.send();
}
}
Merapi在Java端用到了Spring, log4j和Adobe AMF相关包, 所以运行时要保证项目包含了这些jar包。可以从Merapi的Google Code中得到这些包。
AIR2的发布,让我们在AIR和Java通信方面有了新的选择: flerry。
flerry使用了AIR2的新特性NativeProcess,它直接创建了一个进程了执行Java程序。从其作者的blog上可以了解更多信息: http://www.riaspace.net/2010/01/flerry-flex-java-bridge-for-adobe-air-2-0/