カテゴリー : AIR for iOS

DisplayObject.cacheAsBitmapMatrix

以前のflashでは描画を高速化するためにDisplayObject.cacheAsBitmapというパラメータがありましたが、さらにモバイルデバイスにおいては描画が大切だということで、GPUを利用した際に回転やスケールを行った時もキャッシュされるDisplayObject.cacheAsBitmapMatrixというプロパティが追加されました。

このプロパティはpackager for iphone、air for androidの両方で使うことができます。

使い方の参考例 dio:DisplayObject

//↓の2行が必要。新しくmatrixをつくって割り当ててもOK!
dio.cacheAsBitmap = true;
dio.cacheAsBitmapMatrix = new Matrix();

//あとはいつもどおり回転や縮小すればOK
dio.scaleX = dio.scaleY = 0.5;
dio.rotation = 20;

比較動画を作ってみました。
サンプルは透過処理施したBitmapをMCで包み、7個重ねた状態でrotationとscaleを時間とともに変化させたものをNexusOneでプレビューしたものです。
左側:CPUで計算。cacheAsBitmapMatrixなし。
右側:GPUで計算。cacheAsBitmapMatrix有り。
やはりcacheAsBitmapMatrixを使うと圧倒的に速い!!!

Twitter のOAUTHを通過させるサンプル

※tweetr1.0b3での動作確認ができています(2012/11/14)

AIR for AndroidでTwitterのOAuthを通過させるサンプルを作ってみました。

その前にOAuthって何って方はこちらをご参照ください。

言葉は知ってるけど仕組みとかは分からないって方はこちら

TwitterのPublicTimelineなどwebから誰でもアクセス出来る部分は認証なしでAPIを叩けますが、つぶやきをPOSTしたり@メンションを取得したりするのは認証が必要です。この認証をtwitterではOAuth認証というものを使っています。OAuthはWEBサービスなどで一般的に用いることが出来ますが、いままでswf単体では実現不可能な機能でした。(※javascriptとの連携なら可能)

swf単体では難しいこの認証ですがAIRではHTMLLoaderという(swf内に指定したURLのHTML表示できる)機能が実装されていてAIRアプリケーションであれば単体で実装が可能になっています。

で、AIR2.5にあたるairforandroidではHTMLLoaderによく似たStageWebViewというものが実装されました。このStageWebViewを使ってOAuthを実装したサンプルを作ってみます。

TwitterのAPIを叩くライブラリは既にいくつか存在します。

今回はOAuthにも対応しているTweetrを使いました。しかし、TweetrではOAuthをHTMLLoaderを使っているので、この部分を改造してAIRforAndroidで使えるようにStageWebViewで置き換える処理を追加、編集しました。実際にテストしてみたい場合はダウンロードしたTweetrのライブラリ内のOAuth.asを下記のサンプルに置き換えれば動くと思います。

プロジェクトは下のような感じ。

編集するファイルは Main.as  と com.swfjunkie.tweetr.oauth.OAuth.as の2点

Main.as

package
{
	import com.swfjunkie.tweetr.oauth.OAuth;
	import com.swfjunkie.tweetr.oauth.events.OAuthEvent;
	import com.swfjunkie.tweetr.Tweetr;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.html.HTMLLoader;
	import flash.media.StageWebView;
	import flash.net.URLLoader;
	import flash.net.URLRequest;

	public class Main extends Sprite
	{
		private var tweetr:Tweetr;
		private var oauth:OAuth;
		private var webview:StageWebView;
		private const CONSUMER_KEY:String = "取得したKEY";
		private const CONSUMER_SECRET:String = "取得したパス";

		public function Main()
		{
			stage.scaleMode = "noScale";
            		stage.align = "TL";
			init();
		}
		private function init():void {

			tweetr = new Tweetr();

 			oauth = new OAuth();
			oauth.consumerKey = CONSUMER_KEY;
			oauth.consumerSecret = CONSUMER_SECRET;
			oauth.callbackURL = "auth後にコールバックするURL(なんでもいい)";
			oauth.pinlessAuth = true;

			oauth.addEventListener(OAuthEvent.COMPLETE, handleOAuthEvent);
			oauth.addEventListener(OAuthEvent.ERROR, handleOAuthEvent);

			webview = new StageWebView();
			webview.stage = this.stage;
			webview.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
			oauth.webview = webview;
			oauth.getAuthorizationRequest();

		}
		private function handleOAuthEvent(event:OAuthEvent):void{
			if (event.type == OAuthEvent.COMPLETE)
			{
				tweetr.oAuth = oauth;

				//メッセージ(ステータス更新)を送る
				//tweetr.updateStatus("testpost");

				//タイムラインを取得する
				//tweetr.getPublicTimeLine();

				//OAuthが終わったらTweetrでやりたい放題できます。

				// prints username, user id and the final tokens
				trace("outh.string", oauth.toString());
			}
			else
			{
				trace("ERROR: "+event.text);
			}
		}
	}
}

OAuth.as

package com.swfjunkie.tweetr.oauth
{
    import com.hurlant.crypto.Crypto;
    import com.hurlant.crypto.hash.HMAC;
    import com.hurlant.util.Base64;
    import com.hurlant.util.Hex;
    import com.swfjunkie.tweetr.oauth.events.OAuthEvent;

    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.external.ExternalInterface;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLVariables;
    import flash.utils.ByteArray;

    //CONFIG::AIR
	import flash.media.StageWebView;

    /**
     * Dispatched when the OAuth has succesfully completed a Request.
     * @eventType com.swfjunkie.tweetr.oauth.events.OAuthEvent.COMPLETE
     */
    [Event(name="complete", type="com.swfjunkie.tweetr.oauth.OAuthEvent")]

    /**
     * Dispatched when something goes wrong while trying to authorize
     * @eventType com.swfjunkie.tweetr.oauth.events.OAuthEvent.ERROR
     */
    [Event(name="error", type="com.swfjunkie.tweetr.oauth.OAuthEvent")]

    /**
     * OAuth Authentication Utility - requires the <a href="http://code.google.com/p/as3crypto/" target="_blank">as3crypto library</a> to work.
     * @author Sandro Ducceschi [swfjunkie.com, Switzerland]
     */
    public class OAuth extends EventDispatcher implements IOAuth
    {
        //
        //  Class variables
        //
        //--------------------------------------------------------------------------
        private static const OAUTH_DOMAIN:String = "http://twitter.com";
        private static const REQUEST_TOKEN:String = "/oauth/request_token";
        private static const AUTHORIZE:String = "/oauth/authorize";
        private static const ACCESS:String = "/oauth/access_token";
        //--------------------------------------------------------------------------
        //
        //  Initialization
        //
        //--------------------------------------------------------------------------

        /**
         * Creates a new OAuth Instance
         */
        public function OAuth()
        {
            super();
            urlLoader = new URLLoader();
            urlLoader.addEventListener(Event.COMPLETE, handleComplete);
            urlLoader.addEventListener(IOErrorEvent.IO_ERROR, handleError);
            urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleSecurityError);
        }

        //--------------------------------------------------------------------------
        //
        //  Variables
        //
        //--------------------------------------------------------------------------
        private var request:String;
        private var urlLoader:URLLoader;
        private var verifier:String;
        //--------------------------------------------------------------------------
        //
        //  Properties
        //
        //--------------------------------------------------------------------------
        /**
         * Get/Set the Consumer Key for your Application
         */
        public var consumerKey:String = "";
        /**
         * Get/set the Consumer Secret for your Application
         */
        public var consumerSecret:String = "";
        /**
         * Get/Set the User Token
         */
        public var oauthToken:String = "";
        /**
         * Get/Set the User Token Secret
         */
        public var oauthTokenSecret:String = "";

        private var _userId:String;
        /**
         * Get the twitter user_id (retrieval only available after successful user authorization)
         */
        public function get userId():String
        {
            if (_userId)
                return _userId;
            return null;
        }

        private var _callbackURL:String = "oob";
        /**
         * <b><font color="#00AA00">NEW</font></b> - Get/Set the OAuth Callback URL
         */
        public function get callbackURL():String
        {
            return decodeURIComponent(_callbackURL);
        }
        public function set callbackURL(value:String):void
        {
            _callbackURL = encodeURIComponent(value);
        }

        private var _username:String;
        /**
         * Get/set the twitter screen_name (retrieval only available after successful user authorization)
         */
        public function get username():String
        {
            if (_username)
                return _username;
            return null;
        }
        public function set username(value:String):void
        {
            _username = value;
        }

        private var _serviceHost:String = OAUTH_DOMAIN;
        /**
         * Service Host URL you want to use.
         * This has to be changed if you are going to use tweetr
         * from a web app. Since the crossdomain policy of twitter.com
         * is very restrictive. use Tweetr's own PHPProxy Class for this.
         */
        public function get serviceHost():String
        {
            return _serviceHost;
        }
        public function set serviceHost(value:String):void
        {
            if (value.indexOf("http://") == -1 && value.indexOf("https://") == -1)
                _serviceHost = "http://"+value;
            else
                _serviceHost = value;
        }

        /**
         * <b><font color="#00AA00">NEW</font></b> - Whether to use pinless OAuth or not.<br/>
         * If you set this to true, you will have to supply
         * a callback url via <code>callbackURL</code>
         */
        public var pinlessAuth:Boolean = false;

        /**
         * <div class="airIcon"><b><font color="#00AA00">NEW</font></b> - <b>AIR only!</b> The HTMLLoader to be used to display the OAuth
         * Authentication Process from Twitter in.</div>
         */
        //CONFIG::AIR
        public var webview:StageWebView;
        //--------------------------------------------------------------------------
        //
        //  Additional getters and setters
        //
        //--------------------------------------------------------------------------
        private function get time():String
        {
            return Math.round(new Date().getTime() / 1000).toString();
        }

        private function get nonce():String
        {
            return Math.round(Math.random() * 99999).toString();
        }
        //--------------------------------------------------------------------------
        //
        // Overridden API
        //
        //--------------------------------------------------------------------------

        //--------------------------------------------------------------------------
        //
        //  API
        //
        //--------------------------------------------------------------------------
        /**
         * Requests a OAuth Authorization Token and will build the proper authorization URL if successful.
         * When the URL has been created a <code>OAuthEvent.COMPLETE</code> will be fired containing the url.
         */
        public function getAuthorizationRequest():void
        {
            request = REQUEST_TOKEN;
            var urlRequest:URLRequest = new URLRequest(OAUTH_DOMAIN+REQUEST_TOKEN);
            urlRequest.url = _serviceHost + REQUEST_TOKEN + "?"+ getSignedRequest("GET", urlRequest.url);
            urlLoader.load(urlRequest);
        }

        /**
         * Requests the final Access Token to finish the OAuth Authorization.
         * When the Request succeeds a <code>OAuthEvent.COMPLETE</code> will be fired and the OAuth Instance will contain all the information needed to successfully call any Twitter API Method.
         * @param verifier   PIN or verifier_token given by Twitter on the Authorization Page.
         */
        public function requestAccessToken(verifier:String):void
        {
            request = ACCESS;
            this.verifier = verifier;
            var urlRequest:URLRequest = new URLRequest(OAUTH_DOMAIN+ACCESS);
            urlRequest.url = _serviceHost + ACCESS + "?"+ getSignedRequest("GET", urlRequest.url);
            urlLoader.load(urlRequest);
        }

        /**
         * Signs a Request and returns an proper encoded argument string.<br/>
         * <b>There usually is no need to call this by yourself.</b><br/><br/>
         * @param method    The URLRequest Method used. Valid values are POST and GET
         * @param url       The Request URL
         * @param urlVars   URLVariables that need to be signed
         */
        public function getSignedRequest(method:String, url:String, urlVars:URLVariables = null):String
        {
            var args:Array = [];

            if (request)
                args.push({name: "oauth_callback", value: _callbackURL});
            args.push({name: "oauth_consumer_key", value: consumerKey});
            args.push({name: "oauth_nonce", value: nonce});
            args.push({name: "oauth_signature_method", value: "HMAC-SHA1"});
            args.push({name: "oauth_timestamp", value: time});
            args.push({name: "oauth_version", value: "1.0"});

            if (!request || request == ACCESS)
            {
                args.push({name: "oauth_token", value: oauthToken});
                if (request == ACCESS)
                    args.push({name: "oauth_verifier", value: verifier});
            }

            for (var nameValue:String in urlVars)
                args.push({name: nameValue, value: urlVars[nameValue]});

            args.sortOn("name");

            var n:int = args.length;
            var vars:String = "";
            for (var i:int = 0; i < n; i++)
            {
                if (args[i]["name"] != "_method")
                {
                    vars += args[i]["name"]+"="+args[i]["value"];
                    if (i != n-1)
                        vars += "&";
                }
            }
            var signString:String = method.toUpperCase() +"&" + encodeURIComponent(url) + "&" + encodeURIComponent(vars);
            var hmac:HMAC =  Crypto.getHMAC("sha1");
            var key:ByteArray = Hex.toArray( Hex.fromString(encodeURIComponent(consumerSecret) + "&" + encodeURIComponent(oauthTokenSecret)));
            var data:ByteArray = Hex.toArray( Hex.fromString( signString ) );
            var sha:String = Base64.encodeByteArray( hmac.compute( key, data ) );
            vars += "&oauth_signature="+encodeURIComponent(sha);
            return vars;
        }

        /**
         * <b><font color="#00AA00">NEW</font></b> - Returns username, userid, oauth token
         * and secret in a practical string 😉
         */
        override public function toString():String
        {
            return "Username: "+_username+"\n"+
                    "User Id: "+_userId+"\n"+
                    "OAuth Token: "+oauthToken+"\n"+
                    "OAuth Token Secret: "+oauthTokenSecret;
        }

        //--------------------------------------------------------------------------
        //
        //  Overridden methods: _SuperClassName_
        //
        //--------------------------------------------------------------------------

        //--------------------------------------------------------------------------
        //
        //  Methods
        //
        //--------------------------------------------------------------------------

        private function buildAuthorizationRequest(data:String):void
        {
            var splitArr:Array = data.split("&");
            var n:int = splitArr.length;
            for (var i:int = 0; i < n; i++)
            {
                var element:Array = String(splitArr[i]).split("=");
                if (element[0] == "oauth_token")
                {
                    oauthToken = element[1];
                    break;
                }
            }
            var url:String = OAUTH_DOMAIN + AUTHORIZE +"?oauth_token="+encodeURIComponent(oauthToken);

            if (!pinlessAuth)
                dispatchEvent(new OAuthEvent(OAuthEvent.COMPLETE, url));
            else
                callAuthorize(url);
        }

        private function parseAccessResponse(data:String):void
        {
            var splitArr:Array = data.split("&");
            var n:int = splitArr.length;
            for (var i:int = 0; i < n; i++)
            {
                var element:Array = String(splitArr[i]).split("=");
                switch (element[0])
                {
                    case "oauth_token":
                    {
                        oauthToken = element[1];
                        break;
                    }
                    case "oauth_token_secret":
                    {
                        oauthTokenSecret = element[1];
                        break;
                    }
                    case "user_id":
                    {
                        _userId = element[1];
                        break;
                    }
                    case "screen_name":
                    {
                        _username = element[1];
                        break;
                    }
                }
            }
            dispatchEvent(new OAuthEvent(OAuthEvent.COMPLETE));
        }

        //------------------------------------------
        //  Conditional Authorize Call Methods
        //------------------------------------------

        //CONFIG::WEB
		/*
        private function callAuthorize(url:String):void
        {
            if (ExternalInterface.available)
            {
                ExternalInterface.addCallback("setVerifier", requestAccessToken);
                ExternalInterface.call("OAuth.callAuthorize", url);
            }
        }
        */

        //CONFIG::AIR
        private function callAuthorize(url:String):void
        {
            if (webview)
            {
                webview.addEventListener(Event.LOCATION_CHANGE, handleDocumentComplete);
				webview.loadURL(url);
            }
        }

        //--------------------------------------------------------------------------
        //
        //  Broadcasting
        //
        //--------------------------------------------------------------------------

        //--------------------------------------------------------------------------
        //
        //  Eventhandling
        //
        //--------------------------------------------------------------------------

        private function handleComplete(event:Event):void
        {

            if (request == REQUEST_TOKEN)
                buildAuthorizationRequest(urlLoader.data);

            if (request == ACCESS)
                parseAccessResponse(urlLoader.data);
        }

        private function handleError(event:IOErrorEvent):void
        {
            dispatchEvent(new OAuthEvent(OAuthEvent.ERROR, null, event.text));
        }

        private function handleSecurityError(event:SecurityErrorEvent):void
        {
            dispatchEvent(new OAuthEvent(OAuthEvent.ERROR, null, event.text));
        }

        //CONFIG::AIR
        private function handleDocumentComplete(event:Event):void
        {
            var sStr:String = "oauth_verifier=";
            var location:String = webview.location;
            var hasLocation:Boolean = webview.location.indexOf(location) != -1;
            var oAuthVerifierIndex:int = location.indexOf(sStr);

            if (hasLocation && oAuthVerifierIndex != -1)
            {
                webview.removeEventListener(Event.LOCATION_CHANGE, handleDocumentComplete);
				webview.dispose();
                verifier = location.substr(oAuthVerifierIndex + sStr.length, location.length);
                requestAccessToken(verifier);
            }
        }
    }
}

CPU&メモリ節約コマンド一覧

モバイルデバイス向けの開発ではメモリ使用量やCPUの占有率などデスクトップに比べると制約されている部分をシビアに調整する必要があります。

調整時に必要なコマンド一覧を下にまとめました。

	//オブジェクト廃棄(removeEventListener後)
	removeChild(Object);
	Object = null;

	//ボタンの中に階層構造を含む場合※イベントバブリングをキャンセル
	MovieClip.mouseChildren = false;

	//ビットマップ廃棄
	bitmapdata.dispose();
	bitmapdata = null;

	//XML廃棄
	System.disposeXML(XML);

	//Loaderの廃棄
	Loader.unloadAndStop();

	//GC起動
	System.gc();

	//使用メモリーを調べる
	trace(System.totalMemory / 1024);

	//空きメモリーを調べる
	trace(System.freeMemory / 1024);

	//指定した表示オブジェクトの使用メモリを調べる
	//import flash.sampler.getSize ←にあります。
	trace(getSize( DisplayObject ));

その他メモリや描画の高速化に関するtipsまとめ
http://cuaoar.jp/2010/04/flash-1-1.html
http://cuaoar.jp/2010/04/flash-4.html
http://cuaoar.jp/2010/04/flash-3.html
http://cuaoar.jp/2010/03/flash-player-101.html

http://actionscript.g.hatena.ne.jp/ConquestArrow/20070621/1182359767


※airforandroidではStageQualityを使ってみましたが、無視されているようでした。

ListActivityみたいなものをair for androidで!

※作ってから気がついたんです。。。。。Heroに同じようなコンポーネントが用意されているのを。。。。そっちを使ってください。。。

androidやiphoneosでよく見られる、Twitterのタイムラインなどでよく使われるListActivityをair for androidで作ってみた。

いままでどうやって作るのか分からなかったけど、以下のような方法で実現できました。我流なのでもっといい方法がある可能性高いです。

普通に作った場合、スクロールを終えたタイミングでTOUCH_TAPとTOUCH_ROLL_OUTが両方発生してしまうのでListActivityのような希望している動作が得られない。

仕組みは簡単でTouchEvent.TOUCH_BEGINを受けたときに指の座標をキャプチャしておき、TOUCH_MOVEで一定以上の移動量が検知できた場合Sprite.mouseChildrenをfalseにしてしまうというものです。

以下スクリプトは冗長的なので参考までに。。。。。

ドキュメントクラス

package
{
	import flash.display.Sprite;
	import flash.ui.Multitouch;
	import flash.ui.MultitouchInputMode;

	public class Main extends Sprite
	{
		public function Main()
		{
			Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
			addChild(new Lists());
		}
	}
}

Lists.as

package
{
	import flash.display.Sprite;
	import flash.geom.Rectangle;
	import flash.events.TouchEvent;
	import flash.geom.Point;

	public class Lists extends Sprite
	{
		private var startPos:Point = new Point();
		private const POSLIMIT:Number = 50;
		private const MARGIN:Number = 20;

		public function Lists()
		{
			createList();
			addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
		}

		private function createList():void {
			for (var i:uint = 0; i < 30; i++) {
				var mylist:ListMaster = new ListMaster();
				mylist.id = i;
				mylist.txtf.text = i.toString();
				mylist.y = mylist.height * i;
				addChild(mylist);
			}
		}

		private function onTouchBegin(e:TouchEvent):void {
			mouseChildren = true;
			startPos.x = e.stageX;
			startPos.y = e.stageY;
			startTouchDrag(e.touchPointID, false, new Rectangle(0, MARGIN, 0, 800 - height - MARGIN));
			addEventListener(TouchEvent.TOUCH_ROLL_OUT, onTouchOut);
			addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
			trace("touchBegin");
		}
		private function onTouchMove(e:TouchEvent):void {
			var nowPos:Point = new Point(e.stageX, e.stageY);
			var isPosFlg:Boolean = calculatePosAbs(nowPos);
			mouseChildren = isPosFlg;
			if (!isPosFlg) {
				removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
			}
		}
		private function onTouchOut(e:TouchEvent):void {
			stopTouchDrag(e.touchPointID);
			if(hasEventListener(TouchEvent.TOUCH_MOVE)){
				removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
			}
			removeEventListener(TouchEvent.TOUCH_ROLL_OUT, onTouchOut);
			mouseChildren = true;
			trace("touchEnd");
		}

		private function calculatePosAbs(endPos:Point):Boolean {
			var isFlg:Boolean;
			trace(Point.distance(startPos, endPos));
			if (Point.distance(startPos, endPos) > POSLIMIT) {
				isFlg = false;
			}else {
				isFlg = true;
			}
			return isFlg;
		}
	}
}

ListMaster.as

package
{
	import flash.display.MovieClip;
	import flash.text.TextField;
	import flash.events.TouchEvent;

	public class ListMaster extends MovieClip
	{
		private var _id:int;
		public var txtf:TextField;

		public function ListMaster()
		{
			txtf = txt;//設置済みTextFieldを参照
			addEventListener(TouchEvent.TOUCH_TAP, onTouch);
		}

		private function onTouch(e:TouchEvent):void {
			gotoAndPlay(2);
			trace("touchTAP", _id);
		}

		public function set id(value:int):void {
			_id = value;
		}
		public function get id():int {
			return _id;
		}
	}
}

air for android と packager for iphone でVJアプリを作ってみた。

air for android と packager for iphoneを使って VJミキサーを作ってみました。
動画を混ぜたりスイッチングするという処理はそもそも高負荷なので端末サイドで行うことは前提としていませんが、動画をコントロールするコントローラとして端末を利用するというスタンスでアプリを作っています。

ほぼ同じソースを使って、それぞれair for android と packager for iphone で作った動作サンプルをアップしました。
もともとandroid用に作ったものをpackager for iphoneに移植したのですが、圧倒的にandroidの方がスムーズに動いているのがわかると思います。iphoneは同じ処理をしていますがコマ落ちが激しく処理についていませんでした。
ワンソースマルチユースを前提としている場合は処理負荷が軽く、なおかつair2以下の共通で使えるものに限定したものであれば可能だと思います。

Packager for iphone について

2010/10/16時点での日記です。今後アップデートが行われる予定なので参考程度に。

簡単なまとめ

・ダウンロードURL

http://labs.adobe.com/downloads/packagerforiphone.html

・使い方(日本語)

http://help.adobe.com/ja_JP/as3/iphone/index.html

・apple developer(証明書やプロビジョニングファイル取得)

http://developer.apple.com/

開発環境

・FlashCS5

・FlashBuilder

・FlashDevlop

これもandroidと一緒でSDKの中にあるbinフォルダを環境変数に登録しておけばコマンドプロンプトからpkiファイルをパッケージングできる。

pfi -package -target ipa-app-store -provisioning-profile [プロビジョニングファイルへのパス] -storetype pkcs12 -keystore [p12証明書へのパス] -storepass [p12証明書のパスワード] [生成するipaファイルの名前] [application.xmlへのパス] -C [assetファイル] [swfファイルへのパス] [他Asset達]

新機能

  • Accelerometer,AccelerometerEvent
  • Geolocation,GeolocationEvent
  • MutiTouch,TouchEvent,GestureEvent

サポートされない機能(主なもの)

  • Camera
  • HTMLLoader
  • Microphone
  • NativeApplication
  • File(一部サポート)
  • Loader(アセット内のみ)

注意点

・ハードウェアアクセラレーションを正しく理解しておく。

・ボタンにする表示オブジェクトはネストしない。もしくはmouseChildrenをfalse

・画像の縦横の大きさは2のべき乗が望ましい。1px超えると無駄が多くなる。

・ボタンのおおきさ。押しやすい大きさは44px以上。ボタン同士の間隔も重要

・ArrayよりVector使うこと。

・不必要なオブジェクトはremoveChildかvisibleをfalseに。

・ブレンドモード、フィルターはきつい。特にレイヤーブレンドモード。

・モーフィングやマスクもきつい。

・MovieClip.graphic、Sprite.graphicはあまり使わない方がいい。

・表示オブジェクトの大きさは1024px ☓1024px以内に制限すること。

・ビデオの上や、下に再描画が必要な表示オブジェクトを置かない。

雑感

思ったより処理がおぼつかないのでかなりシビアにつくり込む必要があると思います。ここらへんはair for androidと同じなのですが、それよりもスペックが低いように見受けられるので負荷の高いものはNGです。毎回描画が必要なもの、メモリを食うもの、ビデオ関連など。。。できることは自ずと制限されてきそうです。

また、packageriphoneはair2、airforandroidはair2.5といまのところパッケージが異なりサポートされるAPIもことなることからワンソースですべてのデバイスを!という話にはならなさそうです。ゲームとかデバイスのセンサやOSまわりにアクセスしないものなら全然OKっぽいです。