存档

文章标签 ‘ActionScript’

发布as-spring 2.4

2010年8月4日 ColorHook 没有评论

ActionScript作为一个编译型(解释+编译)语言,经常需要把一些变量存在外部文件中,如XML文档。但是经常去解析XML文件就不是一件令人愉快的事情,而且变化点不是String, Number等基本类型的话,解析完XML后还要做更多的事情,于是as-spring诞生了。

as-spring是我的一个基于Flash平台的类库,作为一个Ioc反射框架,它在平时工作中给我带来了很多便利。我以前有过几篇博客提到过它:

  1. 在ActionScript中使用简单的Spring框架来实现IOC
  2. 使用Spring来配置RemoteObject
  3. 发布as-spring 2.1

这次升级加入了部分新的特征,用来消除使用过程中遇到的一些不便之处。具体特征如下:

1. 简化基本类型的数据类型定义

以前定义一个Bean都是用<bean>标签来定义,如果我要定义一个String类型的Bean,需要这样来定义:

<bean class='String'>
    <constructor-arg value='This is a String'/>
</bean>

现在可以用<element>标签来定义:

<element value='This is a String' type='String'/>

2. 增加了数组定义

以前定义数组没有好的方法,特别是当数组的元素不是基本类型时。现在可以用<list>标签来定义:

<list id='arr'>
    <element value='true'/>
    <bean>
    </bean>
    <list>
    </list>
</list>
3. 增加了Hash Object的定义

这个功能其实在以前就可以很方便的实现,只是现在加入了一个更符合思维的定义方式:

<map>
    <key name='apple' value='[iPhone,iPad]'>
    <key name='google'>
        <value>android</value>
    </key>
    <key name='ms'>
        <list>
               <element value='XP'/>
               <element value='Vista'/>
               <element value='Win7'/>
        </list>
    </key>
</map>

本来打算加入对flash.utils.Dictionary的定义的,最后还是放弃了,主要是因为暂时没有遇到迫切需要Dictionary的应用场景,如果以后遇到了,可以考虑加入这个功能。

使用ActionScript更新{新浪微博}

2010年8月4日 ColorHook 没有评论

新浪微博作为一个微博应用在国内还是比较流行的,至少我周围的人就有很多是她的用户。由于新浪微博开放了类似twitter的API, 所以有一部分推友使用了twitter至新浪微博的同步脚本,这里我想使用ActionScript来更新一个新浪微博。

通过API来更新新浪微博有一个前提条件,就是需要注册成为sina的开发者,并创建一个应用还获得一个app key。这些不在详述,具体请参考新浪微博官方站点。获得app key后就可以开始使用ActionScript来正常调用相关API了。

这里我没有使用号称相对安全的OAuth方式登陆,而是使用更直接的Basic Authorization来通过验证,下面是完整代码:

//Define parameters
var username:String='新浪微博用户名';
var password:String='新浪微博密码';
var source:String='新浪微博app key';
var API_URL:String='http://api.t.sina.com.cn';  //新浪微博API domain
var status:String='需要更新的状态';
 
//define HTTP request
var encodedCredentials:String=Base64.encode(username + ":" + password);
var authHeader:URLRequestHeader=new URLRequestHeader("Authorization", 
                                               "Basic " + encodedCredentials);
var url:String = API_URL+ '/statuses/update.xml';
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
variables.source = source;
variables.status = status;
request.data = variables;
request.requestHeaders.push(authHeader);
request.method = 'POST';
 
//send HTTP request.
var loader:URLLoader=new URLLoader();
loader.addEventListener(Event.COMPLETE, onLoaderComplete);
loader.load(request);
 
//HTTP response
function onLoaderComplete(e){
    trace (e.target.data);
}

这里只用到1个外部类Base64,用于HTTP请求中对用户名密码进行加密,该类可以从as3crypto类库中获得。

下载Base64外部库后,设置好正确的classpath,然后替换相关参数,执行代码来更新你的新浪微博吧。

have fun!

使用seesmic-as3-xmpp更新renren状态

2010年4月11日 ColorHook 没有评论

seesmic-as3-xmppXMPP在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 Air V0.3 Released

2010年4月9日 ColorHook 没有评论

今天我终于升级了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也不能这么顺利的完成:

1. Robotlegs

Robotlegs是一个纯ActionScript(指不依赖Flex框架中的代码或特性)写成的MVC微型架构。它简单易用,为应用程序的设计提供一个清晰的层次结构,并且它的DI(Dependency Inject)特性容易让人对这个迷人的框架产生“依赖”。

2. tweetr

tweetr是一个twitter api的library, 它既包括一个AS3的API, 还包括一个PHP的API proxy,更新一条tweet,follow一个user都靠它们来实现了。

3. kingnarestyle

kingnarestyle是一套Flex skin, 这套黑色皮肤是十分受本人喜爱的,这里“严重”声明一下。

as3signals tutorial

2010年2月26日 ColorHook 没有评论

用于Flash平台的开源事件模型as3signals目前在开源社区逐步升温,我在之前的一篇Blog中也略有提到了它诞生的历史原因。如今,许多著名的Flash框架开始与as3signals联姻,这里是它们的一些结合体:

跟EventDispathcer相比,as3signals有更易用的接口,如add, remove, dispatch。并且它还有一些EventDispatcher没有的接口,如addOnce, removeAll。

下面看看如何使用as3signals来触发和监听事件:

public class Dispatcher{
 
	public var signal:Signal;
	public function Dispatcher(){
		signal=new Signal();
	}
}
 
var dispatcher:Dispatcher=new Dispatcher();
dispatcher.signal.add(signalHandler);
function signalHandler():void{
	trace("signal dispatched");
}
dispatcher.signal.dispatch();

ISignal.dispatch()支持可变参数,这意味着通信时可以传递任意数量的对象。Signal的构造函数可以指定dispatch传输的数据类型,这利于在编译期间找出潜在bug。

public class Dispatcher{
 
	public var signal:Signal;
	public function Dispatcher(){
		signal=new Signal(String,String);
	}
}
 
var dispatcher:Dispatcher=new Dispatcher();
dispatcher.signal.add(signalHandler);
function signalHandler(p:String,q:String):void{
	trace("signal dispatched");
}
dispatcher.signal.dispatch("cool","as3Signals");

DeluxeSignal支持事件监听器的优先级以及事件的冒泡。addOnce监听的事件只会执行一次,这将为我们提供很大的便利。

var deluxeSignal:DeluxeSignal = new DeluxeSignal(this);
deluxeSignal.addOnce(deluxeSignalHandler);
deluxeSignal.dispatch(new GenericEvent());
deluxeSignal.dispatch(new GenericEvent());
 
function deluxeSignalHandler(event:GenericEvent):void {
	trace("deluxeSignal dispatched: ",event.target);
}

NativeSignal用于结合EventDispatcher,这样原本有EventDispatcher发出的事件转交给了Signal。

var nativeSignal:NativeSignal = new NativeSignal(stage, MouseEvent.CLICK, MouseEvent);
nativeSignal.add(nativeMouseHandler);
 
function nativeMouseHandler(event:MouseEvent):void {
	trace("nativeMouseHandler: stage clicked");
}

除了易用的接口之外,它在性能上也表现不凡:http://alecmce.com/as3/events-and-signals-performance-tests

使用Merapi来在AIR和Java中通信

2010年2月2日 ColorHook 没有评论

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包。可以从MerapiGoogle 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/

如何修改Flash IDE中组件的样式

2009年12月23日 ColorHook 没有评论

Flash IDE中fl包内的组件由StyleManager负责样式的统一管理,每个组件的诞生都会在StyleManager中进行登记。我们可以通过三个途径来修改、查看和清除(也是一种修改行为)组件的样式:

1. 通过组件实例修改

对组件实例调用setStyle会对单个组件修改样式,其他组件的样式不受影响。

instance<UIComponent>.getStyle(name:String):Object;
instance<UIComponent>.setStyle(name:String,value:String):void;
instance<UIComponent>.clearStyle(name:String):void;

这里创建两个Button和一个Label,并对其中一个Button修改样式。

import fl.controls.Button;
import fl.controls.Label;
import fl.managers.StyleManager;
var textFormat:TextFormat=new TextFormat();
textFormat.size=12;
button1=new Button;
button2=new Button;
button2.y=40;
label=new Label;
label.y=80;
addChild(button1);
addChild(button2);
addChild(label);
button1.setStyle('textFormat',textFormat);
2. 通过组件类型修改

通过这种方式可以修改某一类组件的样式,而其他类型组件的样式不受影响。

StyleManager.getComponentStyle(component:Object,name:String):Object;
StyleManager.setComponentStyle(component:Object,name:String,style:Object):void;
StyleManager.clearComponentStyle(component:Object,name:String):void;

修改所有Button的字号,而Label不受影响。

StyleManager.setComponentStyle(Button,'textFormat',textFormat);
3. 通过全局样式修改

通过这种方式可以所有组件的样式。fl组件默认的字体大小是10,如果显示中文是达不到好的效果的,用这种方式能最快的修改组件字体大小。

StyleManager.getStyle(name:String):Object;
StyleManager.setStyle(name:String,value:Object):void;
StyleManager.clearStyle(name:String):void;

修改Button和Label的字号。

StyleManager.setStyle('textFormat',textFormat);

组件在渲染时,会根据这个顺序依次查找样式,按优先级来算单个实例最高,然后是类型样式,接着是全局样式,如果这些样式都没有被设置过,将采用默认样式。默认样式被定义在组件的静态方法中,StyleManager会查找组件的静态方法getStyleDefinition(如果存在的话)来得到默认样式。因此,在自定义组件中,声明静态方法getStyleDefinition是一个好的习惯。