明日もデザインで食べていこう![35]スマホアプリ、PhoneGap環境とTitanium環境で苦労した後にFlash CS6環境で苦労をする
── 秋葉秀樹 ──

投稿:  著者:


こんにちは、秋葉です。

モバイルアプリを作らないといけない状況でみなさんはどう対応しますか?私ははっきり言って、iPhoneアプリもAndroidアプリも新しい言語を学習してまで作りたいとは思わないです。だから人にお願いすると思うし、それでいいと考えています。

ここ最近では、共通の言語で開発できるソリューションがあって、そちらの人気もあります。スマートフォンのネイティブアプリケーション開発環境のなかでも、「共通のコードでつくれる」と耳にしたことがあるものを色々試し、Flash環境ではどうだろう? と思ってちょっとだけ触ってみました。

私がつくるものは大したコードでもなく、俗にいう「Hello World!」を表示するだけでも精一杯という状況ですので、それぞれ専門でされている方にとってはあまり参考にならないかもしれません。あくまで、これからやってみようかな? と思われている方向けに、です。




■Adobe Flash CS6環境

ご存知Flashです。基本的にFlash Biulderのような本格的なコード開発環境でなくても、簡単なアプリならこれでつくることができます。

CS5からこの機能が付き始めましたが、CS5発売直前になって急にAppleが「iPhoneにはXcode環境でないとダメ(緩く略すと)」というお布令が出て、一時期、心待ちにしていたFlash使いが残念な思いをしたこともあります。なお、Flashを動かす言語はActionScriptですが、ちょっとした注意点を覚えておいてください。

・アプリ書き出し用のActionScriptのバージョンは3.0でないとダメです。2以前だと使えないです。
・モーショントゥイーンのアニメーションもスマホで動きます。
・iPhone実機での動作確認は、デベロッパープログラム(有料)に参加登録しなくてはいけません、ただしAndroidでは実機で動作確認ができます。

ActionScript 3.0になって出来ることが幅広くなりました。ただし、それなりに学習コストが増えます。高度なことをやりたいのであれば、それ相当のスキルが必要となります。

一昔前はFlashといえば、いかに魅力的なアニメーションコンテンツを表現できるかが評価されていたのですが、今ではFlashの活用方法も変わったという感じもします。

一方ではどんどん高度なインタラクティブコンテンツを開発できる環境として活用されるその反面、昔ながらのアニメーション表現のニーズが減ったのはiOSのFlash非対応が大きな理由と言われています。

Flashでつくったモーショントゥイーンのアニメーションは、iPhoneでもAndroidでも動きますが、ここでいう「動き」というのは、あくまで「命令通り動くけど、パフォーマンスは期待しないほうがいい」という、一応厳しい言い方をしておきます。少ないムービークリップの動きでも、厳密に言えばパフォーマンスはガタ落ちします、が、一応動きます、という意味でとらえてください。

なので、ActionScriptの知識がない方でも、工夫次第では今までのFlash制作スキルだけでiPhoneなどのアプリがつくれる可能性はあります。もちろん、どんなアプリになるかによりますが。ちょっと試してみよう、という方であれば、スクリプトなしでもFlashアニメーションをiPhoneやAndroidアプリにできますので、「軽く試したい」という方にはおすすめです。

前述したとおり、iPhoneの場合はAppleのデベロッパープログラムに参加しないと、実機へアプリが転送できないので、気軽に試したい方はAndroid実機にて試すのがよいでしょう。

Flash Player11以降で「Stage3D」という、高度な描画処理にGPUを使う仕組みが搭載されたので、上手に使えばコンピュータの性能をフルに使ったインタラクティブコンテンツやゲームがつくれます。場合によっては、いままでのFlash Playerの1000倍近くの(ここは場合によりますが)パフォーマンスを発揮できると言われています。スマートフォンでもこの機能で貢献されるパフォーマンスがあるかもしれません。

■TitaniumやPhoneGapとFlash環境、どっちにする? それとも...やめる?

違い、というか結局「使い慣れている」ものを極めた方が早い、と考えています。これからFlashはどうなる? とか小賢しいことを考えるより、Flash開発に慣れている方は、今までの自分のスキルも活かせるし、精神的な部分でモチベーションが上がるのは実は非常に重要です。

ある仲の良い現役バリバリのエンジニアが「開発に必要なこと、最後は根性だ」と言ってました。ただ単に精神論を言っているのではない、というのはすぐにわかりました。彼が言っているのは、動かないプログラムを動かすために信じられるものは自分しかいないということでしょう。

確かに今はネットでググるという便利な手段があるので、もちろんその恩恵をうけることはあるでしょう。しかし、「問題解決能力」を総合して「根性」でまとめるのは、決して間違いではないと考えています。

◎Titaniumの場合

基本、デザイン部分もロジック部分もJavaScriptを使ってコーディングします。最近ではそれ以外の方法もありますが、原則、という意味でとらえてください。例えばラベルひとつをつくるにも、JavaScriptで以下のように書いて表示させます。UIをコードで生成するという、デザイナーにはハードルの高い作業になるでしょう。

var label1 = Titanium.UI.createLabel({ // ラベルのオブジェクトを生成
color:'#999', // 文字の色を決める
text:'I am Window 1', // 表示される文字の内容
font:{fontSize:20,fontFamily:'Helvetica Neue'}, // フォントサイズなども決められる
textAlign:'center' // CSSでいうtext-align: centerです
});

win1.add(label1); // ウインドウに表示

これで画面に「I am Window 1」と表示されるわけです。(下記画像参照)
< http://media.tumblr.com/tumblr_lfq8rvv7DE1qz7kgs >

「タップされたら別のウインドウを開く」といったプログラムを仕込むこともできますので、ボタン代わりに使うことも一応可能です(ただしボタンはボタンらしいデザインのUIが用意されています)。

TitaniumのメリットはiOSやAndroid OSで用意されている、UIパーツをそのまま使えることです。わざわざボタンのデザインを書きおこす必要はありません(むしろオリジナルの外観を生成する方がハードルとなる場合があります)。

◎PhoneGapの場合

基本的にHTML+CSS+JavaScriptといった、私たちが慣れ親しんだ技術を使ってできたWebページをアプリ側でラップするものです。なので、アプリの見た目や動作はWebページ(HTMLファイル)そのもの、と言ってもまあまあ大方は間違いではありません。

本来、ネイティブアプリとして配信する目的以外に、HTMLベース(Webベース)で不可能な、デバイスの機能アクセスを実現させることが目的でもあります。Webブラウザで、カメラで写真を撮ったり、連絡帳にアクセスしたりというのは不可能なので、その部分だけPhoneGapのチカラを借りて実現させるのです(ここで言う「不可能」とは案件ベースでという意味です。実際はAndroid 3以降では実現可能となりますが、iPhoneでは無理です)。

さらに、PhoneGapのAPIリファレンスを見ると、いくつかの仕様はHTML5で策定されている文法などに近いものがあるので、学習コストも避けられそうです。

最近ではAdobe DreamweaverがPhoneGapを採用していますが、CS6からは「オンラインで生成」することが可能になっています。Webサイトをつくる感覚で、専用のパネルからビルドするとオンラインでファイルを生成してくれるサービスで、そのパネルからアプリファイルをダウンロードできるというものです。

メリットはWebの標準技術でつくれる、もうその一点だけでしょう。ボタンもCSS3で角丸やグラデーションを現在は-webkit-ベンダープリフィックスを付けて記述するだけでOKです。ヘッダ、フッタ固定にして真ん中スクロールなどは、スマホサイトでおなじみのjQuery Mobileを使ってPhoneGapでラップすると、ネイティブアプリで良く見かけるエフェクトや横スライドなどもWebベースでつくれることが期待できそうです。

◎依存する怖さ

こうするとかなり、私たちのスキルを活かせるということで期待できそうですが、なかなかそうもいかない場面もあります。TitaniumもPhoneGapもFlashも同じことが言えますが、ビルドで失敗することや実機転送で失敗することは当たり前にあると思っておいてください(一概にいえないところはどれも同じ、すんなり思い通りにいかないものです)。

そのとき、私たちは自身のスキルで対処できるでしょうか? きっと困難に遭遇する覚悟が必要でしょう。そもそもネイティブな作り方をしていない以上(つまりiPhoneではXcode環境でなかったり、AndroidだったらJavaで書かなかったり)一度トラブルに見舞われてしまったら、その解決策を探すだけで相当の労力を要求されます。

たとえば、Xcodeの設定にトラブルの原因があったとしても、Xcodeを触ったことがない人にとっては、そこからが未知の領域です。

iPhoneアプリは前述の通り、デベロッパープログラムに登録することで実機転送が可能ですが、プロビジョニングファイルの作成、AppIDとのひも付け、さらにテスト用実機の登録までサイト上で行わないと実機テストは不可能です。ここをスムーズに行うだけでも、それなりに経験と知識が要求されるので、初心者にはハードルが高いのです。

他にも問題があります。これらのプロダクトは、基本的にJavaScriptやActionScriptで書かれたコードを、ネイティブのコードに解釈しなおすことでカメラやコンパス、音楽プレイヤーファイルなどにアクセスできます。

しかしこれらの機能に、例えばiPhoneアプリをObjective-Cで制御できる新しい機能が追加されたとしたら、それを解釈できるAPIというプログラムが実装されるまで、その機能を使うことはできない可能性があるのです。

ただ、ひとつお断りをいれておくと、これらの手法やプロダクトはやはり便利ですばらしいと思います。だから、否定するつもりはないです。でも言いたいことは、大事なことはこれから仕事として始めたい人は、こういったリスクが存在するんだということをはじめに知っておく必要がある、ということです。

結局私はFlashというプラットフォームが一番向いているかな、と思いました(人それぞれってことです)。「ワンソースでマルチデバイス」とか「Web技術でつくれる」とか、うたわれていますが、その反面リスクにも注意しながら向き合っていくべきと考えた方がいいでしょう。

◎Flash環境でカメラ撮影〜サーバに送信する

実はとても便利で楽しいです、ハマると大変だけど、それでも「根性」で問題解決できる人が生き残れるんだろうな......。

さて、以前の記事でTitaniumでカメラアプリをつくり、WEB上のPHPファイルに写真を送るというものを書きましたが、Flashではどうなるのでしょう?
< https://bn.dgcr.com/archives/20120416140300.html
>

いきなり両方のOS対応だと敷居が高いので、実機転送が簡単なAndroidに絞ってやってみました。Flashの方が得意という方はちょっと参考にしてください。

動作としては、ボタンをタップ→カメラ起動→撮影終了→画像が大きいので縮小→縮小した画像をビットマップにつくり直す→サーバに送信となります。解説のためシンプルな実装となるので、撮影終了したら無条件にPHPに送信します。

・開発環境 Flash CS6
・コンピュータ iMac
・テスト実機 Galaxy S2
・使用ライブラリ JPGEncoder(ビットマップをJPEGに変換するためのライブラリ)
< https://github.com/mikechambers/as3corelib
>

Android機をUSBでiMacにつなぎます。パブリッシュすると自動的に実機にインストール・起動するには「ファイル → Air3.2 for Android 設定 → デプロイ」内で設定できます。最初は証明書の作成が求められますので、同じ画面から証明書をつくってください。とくに登録はいりません。

タイムラインの1フレーム目にシャッター用のムービークリップでボタンの形を作ります(これがタップされるとカメラが起動するようにつくります)。ムービークリップの名前を「btn」としましょう。

その上に新規レイヤーを作成してスクリプトを書きましょう。
以下のActionScriptになりますがその前に、JPGEncoderの読み込みをしっかり設定しておきましょう。
「環境設定 → カテゴリ(ActionScript) → ActionScript 3.0 設定...」
内で設定しておきます。設定方法がわからなければこちらを読みましょう。
< http://help.adobe.com/ja_JP/flash/cs/using/WS3e7c64e37a1d85e1e229110db38dec34-7fa4a.html
>

Flashファイル 1フレーム目のスクリプト
----------------------------------------------------------------------

import com.adobe.images.JPGEncoder; //ダウンロードしたライブラリを読み込む

var btn:MovieClip = this.getChildByName("btn") as MovieClip;
//ムービークリップ「btn」を取得する
var photoBitmap:Bitmap;

if (CameraUI.isSupported) { // デバイスにカメラがサポートされているか?
var camera:CameraUI = new CameraUI();
camera.addEventListener( MediaEvent.COMPLETE, imageCaptured );
btn.addEventListener(MouseEvent.CLICK, onClick);
} else {
// カメラサポートされていないときの処理
}

function onClick(evt:MouseEvent):void {
// 撮影ボタンのタップでカメラを起動
camera.launch( MediaType.IMAGE );
}

function imageCaptured( evt:MediaEvent ):void {
//カメラ撮影が終了
var imagePromise:MediaPromise = evt.data;
var loader:Loader = new Loader();
if (imagePromise.isAsync) {
loader.contentLoaderInfo.addEventListener( Event.COMPLETE,
promiseLoaderLoaded );
loader.loadFilePromise( imagePromise );
}
}

function promiseLoaderLoaded( evt:Event ):void {
//撮った写真が縦のつもりなのに横になっているので縦に修正(任意で)
photoBitmap = evt.target.content as Bitmap;
var w:uint = 400; //横400pxとする
var scale:Number = w / photoBitmap.width; // 横サイズにもとづき縮小率を計算
var matrix:Matrix = new Matrix();// 座標はそのままで行列で変形させる
matrix.scale(scale,scale); //縮小
matrix.rotate(90*Math.PI/180); // 時計回り90度回転
matrix.translate(photoBitmap.height*scale, 0); // 右に「縦の長さ」分移動させる
photoBitmap.transform.matrix = matrix;
var sp:Sprite = new Sprite();
sp.addChild(photoBitmap); // ビットマップをスプライトに入れてみる
addChild(sp); // スプライトを表示
send2PHP(sp);
}

// 画像をPHPに送信
function send2PHP(sp:Sprite):void{
var bmd:BitmapData = new BitmapData(sp.width, sp.height);
// スプライト内に縮小された画像をビットマップデータにdrawしてサムネイル取得完了!
bmd.draw(sp);
var jpgEncoder:JPGEncoder = new JPGEncoder(); // JPEG作成
var byteArr:ByteArray = jpgEncoder.encode(bmd);
// JavaScriptでやるAjax通信のようなものが以下。JPEGデータをバイト配列でPOST送信
var urlRequest:URLRequest = new URLRequest( /*PHPのアドレス*/ ); //
CGIPath...サーバCGIURL
var urlLoader:URLLoader = new URLLoader();
urlRequest.contentType = "application/octet-stream";
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = byteArr;
urlLoader.load(urlRequest);
urlLoader.addEventListener(Event.COMPLETE, function (e:Event):void{
//送信が成功したときの処理
})
}

----------------------------------------------------------------------

PHPファイルの内容(同階層のphotoフォルダに写真をアップし、data.txtに画像ファイル名を書き込む)

----------------------------------------------------------------------

$fname = "photo/".date("Ymdhis").".jpg"; //ファイル名を決定
$bin= file_get_contents( "php://input" ); //バイナリデータを受け取る
// 画像ファイルとして書き出す
$fp = fopen( $fname, "w" );
fwrite($fp, $bin);
fclose($fp);

// テキストファイルにログを記録
$pointer=fopen("photo/data.txt", "a");
flock($pointer, LOCK_EX);
fputs($pointer, $fname."\n");
flock($pointer, LOCK_UN);
fclose($pointer);

//ActionScriptにメッセージを返す
print($fname."をアップしました");

----------------------------------------------------------------------

実際はサーバーからエラーが帰ってきたときなどの処理も、ActionScript側で行うとよいでしょう。TitaniumやPhoneGapとJavaScriptでつくるカメラ投稿アプリと、FlashとActionScript 3.0でつくるカメラ投稿アプリ。

みなさんはどちらでやりますか?
え、やらない?
それも選択肢として正しいでしょう......。

【あきば・ひでき】hidetaro7@gmail.com
< http://www.akibahideki.com/blog/
>

テクニカルディレクター・デザイナー。DTP黎明期からグラフィックデザインを学び、東京都営団地下鉄など交通広告を多数手がける。同時に音楽活動も活発に行い、西日本半全国ツアーなどを展開、某専門学校のテーマソングを作詞作曲、編曲から楽器全てを演奏してレコーディングするなど、マルチなクリエイティブ活動も。最近では東京と大阪の教育施設などで講師業をも務める。HTML CSS JavaScript Flash ActionScript 3DCG Movie DTP GraphicDesign...多種スキルを持つ。Web標準技術だけに執着せず、すべてのメディアで説得力のある表現にチカラを注ぎたい、そんな仕事をしたい。