存档

文章标签 ‘Flash’

使用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/

Gordon, 用JavaScript写的开源Flash runtime

2010年1月19日 ColorHook 没有评论

Gordon是一个用JavaScript写成的并且开源的Flash runtime, 它使用JavaScript解析SWF文件并使用SVG重新渲染到浏览器上,下面是一些实例,它们可以运行在iPhone和iPod Touch上。wooooo~~

http://paulirish.com/work/gordon/demos/

github上可以找到Gordon全部源码和Demo:

http://github.com/tobeytailor/gordon

如何修改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是一个好的习惯。

ActionScript Quiz

2009年12月21日 ColorHook 没有评论

写在前面

FFDMag 2009年6月刊Getting Started with Adobe Open Source Media Framework上Maxim Zaks有一个关于ActionScript的小测验,觉得有意思,于是题目全部拷过来,答案也翻译过来。

Quiz

1. What is the right trace output?
var a = true; trace(a?"a":"b");

a) a
b) b

2. Which lines of code can be compiled?

a) trace(10.toString());
b) trace(/dfgr/.source);
c) trace(.toXMLString());
d) trace({a:12}.a.toString());
e) trace(true.toString());
f) trace([1,2,3].toString());

3. What is the right trace output?
var a = 10; trace((a=a*a,a/2));

a) 10
b) 5
c) 50
d) 100
e) won’t compile

4. What is the right trace output?
trace((var a=10*10,a/2));

a) 10
b) 5
c) 50
d) 100
e) won’t compile

5. What is the right trace output?
var f:Function;
trace((f=function(){return 10},f()/2));

a) 10
b) 5
c) 50
d) 100
e) won’t compile

6. What will happen?
trace(<hallo/*an OpenTag*/></{(trace("CloseTag"),"hallo")}>.toXMLString())

a) Compile Error
b) Runtime Error
c) trace “CloseTag”
d) trace “CloseTag

7. Which example can be compiled?

a) package{class C1{function f1(){}function f1(i:int){}}}
b) package{class C1{function f1(){}static function f1(i:int){}}}
c) package{class C1{function f1(){}AS3 function f1(i:int){}}}

8. Which Constructor is OK?

a) package{public class C1{public function C1(){}}}
b) package{public class C1{function C1(){}}}
c) package{public class C1{internal function C1(){}}}
d) package{public class C1{private function C1(){}}}
e) package{public class C1{public function C1():C1{return this;}}}
f) package{public class C1{public function C1():void{}}}

9. Which example can be compiled?

a) package{public class C1{public function C1(){super()}}}
b) package{public class C1{public function C1(){this()}}}
c) package{public class C1{public function foo(){super()}}}
d) package{public class C1{public static function foo(){this}}}
e) package{public class C1{public function foo(){super.foo()}}}

10. Which statement is wrong?

a) I am able to import classes that are stored in a package with the name “default” (default is a keyword). Example: import default.ClassA;
b) I am able to import classes that are stored in a sub package with the name “default” (default is a keyword). Example: import my.default.ClassA;
c) I am able to import classes that are stored in a sub package with name “true” (true is a keyword). Example: import my.true.ClassA;

11. What us the right trace output order?
package
{
	import flash.display.Sprite;
 
	trace("A");
	public class Test extends Sprite{
		trace("B");
		function Test(){
			trace("C");
		}
		trace("D");
	}
	trace("E");
}
trace("F");

a) A,B,C,D,E,F
b) C,B,D,A,E,F
c) B,D,A,E,F,C

12. Which example can be compiled?

a) package{public class C1{namespace ns1; namespace ns2; ns1 function foo(){}ns2 function foo(){}}}
b) package{public class C1{namespace ns1=”ns”; namespace ns2=”ns”; ns1 function foo(){}ns2 function foo(){}}}
c) package{public class C1{namespace ns1; ns1 function foo(){}public function foo(){}}}
d) package{public class C1{namespace ns1=”"; ns1 function foo(){}public function foo(){}}}

13. What is the right trace output?
trace(function(){return "hallo";}())

a) hallo
b) won’t compile

答案及解释

  • 1) 问号是一个条件操作符,语法是 condition ? positive case: negative case; 所以正确答案是 a)。
  • 2) ActionScript 3是一个严谨的面向对象的语言。这意味着它没有基本类型,并且每个表达式都是一种对象的一个实例。这也是为什么可以用操作符”.“来直接调用方法。只有一个例外:number literal。 正确答案是 b),c),d),e),f) 。
  • 3) 在AcrionScript中,小括号中可以有一系列表达式,它会返回最后一个表达式的值,可以把它看做内联的匿名函数,正确答案是 c)。
  • 4) 规则和问题3)一样,但是小括号内不允许作声明,正确答案是 e)。
  • 5) 小括号内不允许作声明,但是可以赋值,正确答案是 b)。
  • 6) 这里使用了小括号,也使用了XML,在XML中可以使用大括号来执行AS,正确答案是 d)。
  • 7) AS3是一个面向对象的语言,但是它不支持overload,所以a)是错的,b)和c)可以,因为b)将另一个方法声明为static,c)中的方法是在不同的命名空间下。
  • 8) AS3的构造器必须声明为public并且无返回类型,所以c) , d) , e)是错误的。有趣的是b) ,尽管没有声明修饰符它却是正确的,他的访问类型仍然是public,而不是通常的internal。
  • 9) “super()”只能在构造器中被调用,”this()”会产生错误,并且”this”不能放在静态方法中。正确答案是 a)和e) 。
  • 10) 这个例子展示了一个ActionScript不易被发觉的性质,按通常理解三个都应该是错误的,但是实际上b)是正确的。所以正确答案是 a)和c) 。
  • 11) 当加载一个类到内存中,按通常理解三个都应该是错误的,但是实际上b)是正确的。所以正确答案是 a)和c) 。
  • 12) 如同问题7),方法重载是不允许的,但它们可以声明在不同的命名空间下,如果声明命名空间而没有对它赋值,它们会在运行时通过包名,类名和名称被赋值。
  • 13) AS3中的Function是一个Closure,定义一个Closure之后可以直接调用它。正确答案是 a) 。

小结

这个测试中只覆盖了AS3语言特性的一小部分,不知道所有的答案不是一件丢脸的事情,但是你像题目5、6或者10那样写代码就是一件丢脸的事。代码应该干净、易读。希望你能从这些题目中得到乐趣。