Home > Archives > 2009-04

2009-04

flash lite1.1やdocomo端末でswfにGETパラメータを保持させることが、こんなにも難しいと知ってたらFlasherにはなりませんでした。あっ、すこし言い過ぎました

モバイルサイト向けのアクセス解析ツールでセッションを保持させるために、swfにGETパラメータを仕込まないといけない状況になりました。

このアクセス解析ツールでは、

  • html→htmlへの遷移ではセッションがうまくとれる
  • html→swfへの遷移ではGETパラメータを渡して強引にセッションを取得
  • swf→htmlへの遷移もGETパラメータを渡してセッションを継続させる

という課題がありました。swfが間に入るとひと手間かかってしまいます。詳しい流れは下図を参照してください。

とても簡単そうに見えますね。しかし!作業は難航しました。

Flash lite1.xでは普通にやってるとGETパラメータを処理できない

まずはFlash lite1.1の予習から

  • docomoの904iまではFlash Lite1.1。かなり多くの端末に1.1が搭載されている。docomoの資料
  • flashvarsが使えない
  • GETパラメータも受け取れない
  • _urlプロパティがないので、無理やり取得もできない
    • 取得したとしてもindexOf()がないので解析しようがない

というわけで、通常GETパラメータをFlash lite1.x上では扱うことができません。

じゃあ、swf→php→htmlとして、swfのGETパラメータをリファで取ってphpで処理すればいいんじゃね?と思ったらdocomoはリファを渡さない

swf→htmlの遷移の間にphpを挟み、環境変数のHTTP_REFFER(リファのURLを取得)を使って、GETパラメータを抜き取ろうと思いました。しかし!

  • docomoはHTTP_REFFERを渡さない

どうしようもありません。ググっているとHTTP_REFFERなどの環境変数に頼ったコーディングはよくないともありました。

結局swfを動的にGETパラメータの変数をswfに埋め込んで…という手法で

どうしようもなかったので、ついに避けていた手法をとることにしました。swfmillという選択肢もありましたが、とりあえず簡単っぽく実現しやすいものを選びました。

FACEs: 携帯Flash (FLASH Lite 1.1) へ普通にパラメータを渡す

このソースを少しいじくって今回の要望に沿う形にしてみました。「?」以下のGETパラメータをそっくりそのままFlashの中に変数として持たせます。

swfをゴニョゴニョして表示するphp (swf.php)
<?php
	require_once "wrap.php";
	$params = strstr($_SERVER["REQUEST_URI"], "?");
	echo swf_param_insert('hoge.swf', "trackParams", $params);
?>
wrap.phpで追加した関数
function swf_param_insert($file, $varsName, $item){
	header("Content-Type: application/x-shockwave-flash");
	
	$tags	= build_string($varsName, $item);
	$src	= file_get_contents($file);
	$i	= (ord($src[8])>>1)+5;
	$length	= ceil((((8-($i&7))&7)+$i)/8)+17;
	$head	= substr($src,0,$length);
	return(
		substr($head,0,4).
		pack("V",strlen($src)+strlen($tags)).
		substr($head,8).
		$tags.
		substr($src,$length)
	);
}

function build_string($varsName, $item) {
	
	$s = sprintf(
		"x96%sx00%sx00x96%sx00%sx00x1d",
		pack("v",strlen($varsName)+2),	$varsName,
		pack("v",strlen($item)+2),	$item
	);
	return(sprintf(
		"x3fx03%s%sx00",
		pack("V",strlen($s)+1),
		$s
	));
}

バイナリに分解してゴニョゴニョしてますが、わけわかんないです。わかんないのでfunction名も適当です。ヘッダのファイルサイズを増やして、tag(変数)を埋め込んでいるということがなんとなくわかる程度です。

SWFのバイナリに詳しく知りたいかたは以下のリンクを辿るかググってみてください。そのあと僕に手取り足取り教えるか、けしからん動画をください。

今回説明したサンプル

で、この技術、ほかに使えんの?

ご存知のとおりバスキュールさんのGyorol2009年の年賀サイトでこれが使われてると思われます。最近はバスキュールさん以外のとこでもケータイ連動やってましたね。だいぶ浸透してきてるのかな?

超便利なローダーBulkLoaderの落とし穴にハマってきました

便利なAS3用ローダー:BulkLoaderの解説は他のサイトにおまかせ!

BulkLoaderは複数の素材をまとめて読み込める万能ローダーです。解説はほかのサイトにおまかせ!ぜひ読んでください。読んだら僕のサイトに帰ってこなくても大丈夫です!

BulkLoaderの便利ポイントをまとめると

  • まとめてロードできる
  • String形式のurlをadd()するだけでロードの準備はOK。さらにvideoなのかxmlなのかjpgなのかなどを自動判別してロードしてくれる(きちんとtype指定もできるのでやったほうがいいです)
  • ロードが終わったら、あらかじめBulkLoaderに渡しておいたIDやurlのstringで取得できる
  • getXML()とかgetBitmapdata()などで好みのインスタンスで取得できる
  • 複数ロードのパーセントや何個中何個がロードできたかを取得できる。
  • ロードしたものを取得後、メモリに残したり、取得したらメモリから消したりと、メモリ管理が簡単

といったところです。ものすごく便利です。

今回ハマったローディングパーセント処理

今回、外部素材を10個ほど読み込んでいました。しかし、パーセント表示がおかしな挙動になってしまいました。

  1. 最初の1秒間くらいでパーセントが100%近くに達し
  2. その後の1秒で10%ちかくまで減り、
  3. その後は正常に100%まで達しました。

原因は2つあって、

  1. ロードするときにproressイベントが発動するまで、bytesTotalが見えない問題
  2. BulkLoaderのパーセント表示には2つ種類があり、そのうち強引な作りのほうを選んでしまった

1.ロードするときにproressイベントが発動するまで、bytesTotalが見えない問題

外部素材との接続を確立してproressイベントが発動するまではbytesTotalが見えません。下のスクリプトで確認してみましょう。

このように、progressEventが発生するまでbytesLoadedやbytesTotalはわかりません。複数ロード時にはこのへんの問題があります。

BulkLoaderのパーセント表示には2つ種類があり、そのうち強引な作りのほうを選んでしまった

次にBulkLoaderが持っている2種類のパーセント表示を見てみましょう。

  1. 読み込みが完了したアイテム数 / トータルのアイテム数(BulkProgressEvent.ratioLoaded)
  2. 今までに読み込んだアイテムの総bytesLoaded / トータルのアイテムの総bytesTotal(BulkProgressEvent.percentLoaded

「1.完了数/総数」は複数ロードするときによく使われる手法ですが、2つしかロードがないときは50%ずつ増えることになるので、使いどころが難しいときもあります。
正確なパーセントを知りたいときは後者の「bytesLoadedとbytsTotalの比率」を使います。

しかし、ここが大きな落とし穴となっていました。

BulkLoaderはこのパーセント表示を強引な手法で実装しています。前述のとおり、flash.event.ProgressEventが飛んでこない限り、bytesTotalを知る術はありません。BulkLoaderでは、

  1. bytesTotalを取得できたitemだけを加算し、
  2. すべてのitemのbytesLoadedと上記のbytesTotalの比率からパーセントを表示します

つまり、すべてのitemのbytesTotalがわかるのは最後のitemのprogressが始まったときになのに、分母(bytesTotal)が変動する状態でパーセント表示を開始してしまうのです。

ロード直後では
800/1000(80%)
だったものが、その次のフレームで
1000/10000(10%)
となる可能性があるのです。

じゃあどうする?

2009-10-06追記 : weightPercentを使う

以下のやりかたよりもスマートな解法がありました。BulkProgressEvent.weightPercentを使うともっとまともなパーセントを取得できます。
こちらの記事に書きました。「BulkLoaderで「もう悩まない!」ための6つのtipsをまずは14日間で売上No.1!!

1.読み込みが完了したアイテム数 / トータルのアイテム数をとる

これが一番安全ですね。パーセント表示は正確なものが期待できませんし、トータルのアイテム数が2つ3つのときはおおざっぱになるので、ごまかしの効くviewにしましょう

2.読み込み順序に優先順位をつけ、重たいものから先に読み込む

先に軽いファイルを大量に読み込むと、重たいファイルを読み込み始めた瞬間にグッと分母が上昇してしまいます。重たいファイルから読めば分母の変動が少ないので、ある程度ゴマカシが効くようになります。

//優先順位はこんな感じで設定
//addの引数でpriorityを設定。priorityが高いやつが優先的に読み込まれる。重たいファイルを優先的に指定しとく。
var bulkLoader:BulkLoader = new BulkLoader("main loading");
bulkLoader.add("めっさ重たい.flv", { priority : 1000 });
bulkLoader.add("コニシキ.flv", { priority : 1000 });
bulkLoader.add("ダイエットコーラ.xml", { priority : 0 });
bulkLoader.add("糖分ゼロ.xml", { priority : 0 });
bulkLoader.add("ふわっふわ.xml", { priority : 0 });
bulkLoader.add("納品前日に仕様変更.swf", { priority : 500000 });
bulkLoader.addEventListener(~~~);
bulkLoader.start();

addメソッドの引数はasdocで

重たいファイルは後回しにした方がいいときの方が多いので、そのへんはトレードオフとかを考えてベターな手法を選びましょう。

  • Comments (Close): 0
  • Trackbacks (Close): 0

Home > Archives > 2009-04


Search
Feeds
Meta

Return to page top