Home > ActionScript 2.0 | ActionScript 3.0 | JSFL > [JSFL]リアルタイムにパブリッシュを実行するコンポーネントRealPub[AIR]

[JSFL]リアルタイムにパブリッシュを実行するコンポーネントRealPub[AIR]

http://www.libspark.org/wiki/kaede/RealPub

http://www.libspark.org/svn/mxp/RealPub/RealPub.zip

少し遅れてのコミットになってしまいましたが、先日行われたJSFL勉強会で発表したJSFLをSparkで公開しました。もともと、このコンーネントは以前行われたDTL.asで、吉川さんが公開して話題となったAIRアプリで実現するASエディタのリアルタイムパブリッシュ機能を、サーバー無しで実現させようと考え、開発しました。

リアルタイムパブリッシュ・コンポーネントRealPub

RealPubは、SWFPanel+AS3/JSFL/AIRの技術を使用したコンポーネントです。実行結果は題目通り、指定された秒数ごとにパブリッシュを実行し、専用のAIRアプリに表示します。FLASHコンポーネント内から独立するAIRアプリのため、常に最前面に表示することができ、パブリッシュ結果の確認を容易にします。

使い方は以下から

使い方

  1. RealPubコンポーネント及び、RealPubViewer(AIR)をインストール
  2. 対象のFlaを開く
  3. ウィンドウ>他のパネル>RealPub
  4. RealPubパネルが表示され、delayを設定し、start。
  5. RealPubパネルの下部にreadyが表示後、RealPubViewerを実行
  6. リアルタイムパブリッシュ開始

仕組み

フロー

RealPubの仕組みはActionScript3.0のLocalConnectionによって、以下のフローで処理されています。

  1. RealPub(SWFPanel)がLocalConnectionを生成
  2. RealPubViewer(AIR)がLocalConnectionを生成、RealPubに接続。
  3. RealPubがJSFLでターゲットとなる.flaにLocalConnectionの設定を施したasを埋め込む
  4. JSFLでターゲットの.flaをパブリッシュ
  5. ターゲットはRealPubに自身のSWFパスをLocalConnectionで接続後、送信。
  6. 埋め込んだasを除去
  7. パブリッシュされたSWFのパスを取得したRealPubは、そのパスをRealPubViewerに送信。
  8. RealPubViewerがLoaderでロード。ワンクール終了をRealPubに送信。
  9. RealPubが処理を繰返し。

ポイント

AIR・SWFの双方向通信(LocalConnection)

AIRとSWF間の通信は、SWF同士間とは異なり、SWFは送信時(send()メソッド)にAIRに対して特殊なIDを付与しなければなりません。この時、SWFはAIRのIDを取得する術がないので、AIRがSWFにパスを送信する必要があります。しかし、AIR側もSWFがローカルのため、特殊な接続詞"localhost:"を付与します。必要なidはNativeApplication.applicationID,そしてNativeApplication.publisherIDです。現在のアプリケーションは、NativeApplication.nativeApplicationで取得します。

AIR→SWFでのLocalConnection.send
conn.send("localhost:"+ConnectName.PANEL,"getViewerDataHandler",NativeApplication.nativeApplication.applicationID,NativeApplication.nativeApplication.publisherID)


これらのidを予めSWFに送信しておき、SWFがAIRに通信する際に付与します。

SWF→AIRでのLocalConnection.send
conn.send("app#" + applicationID + "." + publisherID + ":" + ConnectName.VIEWER, "getSWFURIHandler", URI)


この辺りの詳しい操作は、taiga氏のデバイス連動 AIR アプリケーション開発手法 が詳しいので参照すると良いでしょう。

SWFからJSFLを実行する(MMExecute/fl.runScript)

SWFからJSFLを実行するには、MMExecute関数を使用します。MMexecute関数はadobe.utils.MMExecuteパッケージに属する関数で、Flashオーサリング時のみに実行することのできる特殊な関数のため、SWFPanelが立ち上がっていない状態で動かすことはできません。下記のMMExecuteで指定されているJSFLコードのrunScript()関数は、flオブジェクトに属する関数で、特定のディレクトリに格納されているJSFLを実行します。第二引数でメソッド名を、第三引数で対象のメソッドに渡す引数を指定することができます。

MMExecute('fl.runScript(fl.configURI+"Javascript/realpub.jsfl","removeSettingLayer",'+addedLayerIndex+')')

ソース

RealPubPanel(SWFPanel)

package {
	import adobe.utils.MMExecute;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.net.LocalConnection;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.utils.Timer;
	
	/**@author kamoyusuke */
	public class RealPubPanel extends MovieClip {
		
		public static const CONNECT_NAME:String = "pub_panel";
		
		private var conn:LocalConnection;
		private var applicationID:String;
		private var publisherID:String;
		
		private var timer:Timer;
		private var addedLayerIndex:int;
		private var _isActive:Boolean;
		
		public function RealPubPanel():void{
			button.addEventListener(MouseEvent.CLICK,init)
		}
		
		private function init(e:MouseEvent):void {
			if (!button.selected) {//中止
				//ローカルコネクトの設定
				conn = new LocalConnection();
				conn.allowDomain("*");
				conn.client = this;
				conn.connect(ConnectName.PANEL);
				timer = new Timer(delay.value)
				timer.addEventListener(TimerEvent.TIMER, timerHandler)
				status.text = "ready"
				if (applicationID && publisherID) {//既に一度接続されていたら再試行
					refresh();
				}
			}else {//停止
				conn.close();
				timer.stop();
				timer.removeEventListener(TimerEvent.TIMER, timerHandler)
				status.text = ""
			}
		}
		
		/**
		 * localConnectによって
		 * Viewerの情報を受信(AIR)
		 * @param	...args
		 */
		public function getViewerDataHandler(...args):void {
			//MMExecute('fl.trace("' + args + '")')
			applicationID = args[0];
			publisherID = args[1];
			
			status.text = "connected"
			
			refresh();
		}
		
		/**
		 *カレントのflaにlocalConnectionのasを記述し、パブリッシュ。
		 * パブリッシュ後、記述したレイヤーを削除。
		 */
		private function refresh():void {
			if (!isActive) {
				status.text = "refreshing"
				addSettingLayer();
				publish();
				removeSettingLayer();
			}else {
				timer.start();
			}
		}
		
		/**
		 * LocalConnectionを施したレイヤーを生成
		 */
		private function addSettingLayer():void{
			addedLayerIndex = int(MMExecute('fl.runScript(fl.configURI+"Javascript/realpub.jsfl","addSettingLayer","'+ConnectName.PANEL+'","getSWFURIHandler")'));
		}
		
		/**
		 * 生成したレイヤーを削除
		 */
		private function removeSettingLayer():void{
			MMExecute('fl.runScript(fl.configURI+"Javascript/realpub.jsfl","removeSettingLayer",'+addedLayerIndex+')');
		}
		
		/**
		 * パブリッシュ
		 */
		private function publish():void {
			MMExecute('fl.getDocumentDOM().testMovie();')//ムービープレビュー
		}
		
		/**
		 * カレントで開いているflaのlocalconection.send()によって受信
		 * 受信したURIをViewer(AIR)に送信
		 * @param	URI 現在パブリッシュされているSWFのURI
		 */
		public function getSWFURIHandler(URI:String):void {
			MMExecute('fl.closeAllPlayerDocuments();')//ムービープレビューを閉じる
			//MMExecute('fl.trace("' + URI + '")')
			conn.send("app#" + applicationID + "." + publisherID + ":" + ConnectName.VIEWER, "getSWFURIHandler", URI)
		}
		
		/**
		 * ViewerがSWFを表示完了
		 */
		public function loadedSWFHandler():void{
			//MMExecute('fl.trace("ViewerがSWFを表示完了")');
			status.text = "ready"
			timer.start();//タイマーが発動
		}
		
		/**
		 * 再リフレッシュ
		 * @param	e
		 */
		private function timerHandler(e:TimerEvent):void {
			timer.stop();
			refresh();
		}
		
		/**
		 * Viewerが現在アクティブかどうか
		 */
		public function get isActive():Boolean { return _isActive; }
		
		public function setIsActive(value:Boolean):void {
			_isActive = value;
		}
		
		
		
	}
	
}

RealPubViewer(AIR)

package {
	import flash.desktop.NativeApplication;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.NativeWindow;
	import flash.display.NativeWindow;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.StatusEvent;
	import flash.geom.Rectangle;
	import flash.net.LocalConnection;
	import flash.net.URLRequest;
	import flash.text.TextField;
	
	/**@author kamoyusuke */
	public class RealPubViewer extends MovieClip {
		
		public static const CONNECT_NAME:String = "pub_viewer";
		private var conn:LocalConnection;
		private var loader:Loader;
		private var nativeWindow:NativeWindow;
		
		public function RealPubViewer():void{
			addEventListener(Event.ADDED_TO_STAGE,init)
		}
		
		private function init(e:Event):void {
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			nativeWindow = stage.nativeWindow;
			nativeWindow.alwaysInFront = true;
			conn = new LocalConnection();
			conn.client = this;
			conn.connect(RealPubViewer.CONNECT_NAME);
			conn.addEventListener(StatusEvent.STATUS, function(e:StatusEvent) {
				//var text:TextField = addChild(new TextField()) as TextField;
				//text.text = e.level;
			});
			//AIRの情報をパネルに送信
			conn.send("localhost:"+ConnectName.PANEL,"getViewerDataHandler",NativeApplication.nativeApplication.applicationID,NativeApplication.nativeApplication.publisherID)
			
			loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler)
			
			addEventListener(Event.ACTIVATE,activeHandler)
			addEventListener(Event.DEACTIVATE, activeHandler)
		}
		
		/**
		 * 現在ウィンドウの有効可否を送信
		 * @param	e
		 */
		private function activeHandler(e:Event):void {
			conn.send("localhost:" + ConnectName.PANEL, "setIsActive", (e.type == Event.ACTIVATE))
		}
		
		/**
		 * パネルにlocalconection.send()によって受信
		 * @param	URI 現在パブリッシュされているSWFのURI
		 */
		public function getSWFURIHandler(URI:String):void {
			if (contains(loader)) {
				removeChild(loader)
				loader.unload();
			}
			loader.load(new URLRequest(URI))
		}
		
		/**
		 * ロード完了ハンドラ
		 * @param	e
		 */
		private function completeHandler(e:Event):void {
			conn.send("localhost:" + ConnectName.PANEL, "loadedSWFHandler")
			addChild(loader)
			nativeWindow.bounds = new Rectangle(nativeWindow.x,nativeWindow.y,loader.contentLoaderInfo.width,loader.contentLoaderInfo.height+nativeWindow.minSize.y);
		}
		
	}
	
}

addSettingLayer(JSFL)

var currentTimeLine = fl.getDocumentDOM().getTimeline();
function addSettingLayer(connectName,handlerName){
	var layerIndex = currentTimeLine.addNewLayer("localConnectionAS","normal",true)
	var connectSettingAS = [
		'import flash.net.LocalConnection;',
		'var conn:LocalConnection = new LocalConnection();',
		'conn.send("'+connectName+'","'+handlerName+'",stage.loaderInfo.url)'
	].join("\n")
	currentTimeLine.layers[layerIndex].frames[0].actionScript = connectSettingAS
	return layerIndex
}

function removeSettingLayer(layerIndex){
	currentTimeLine.deleteLayer(layerIndex)
}

Summer Camp 2010 野中文雄のActionScript 3.0による 三次元表現

無料  ActionScript 3.0による 三次元表現 in アップルストア 銀座

フィジカルコンピューティング ラボラトリー

Comments:1

Comment Form

コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。

key 2009年4月 8日 11:10

すごく素敵です!

Trackbacks:0

TrackBack URL for this entry
http://xingxx.com/mt/mt-tb.cgi/51
Listed below are links to weblogs that reference
[JSFL]リアルタイムにパブリッシュを実行するコンポーネントRealPub[AIR] from xingxx

Home > ActionScript 2.0 | ActionScript 3.0 | JSFL > [JSFL]リアルタイムにパブリッシュを実行するコンポーネントRealPub[AIR]

Search
Feeds
Tag Cloud

Return to page top