すべて
Flex/AIR開発には、ところどころに「落とし穴」があります。過去3年間のFlex/AIR開発を通じて、筆者はそうした「落とし穴」にことごとくハマり、そのたびに「二度と繰り返すまい」との思いで要点をメモしてきました。本連載では、その筆者の「Flex/AIRハマり帳」をもとに、これからFlex/AIR開発を始める方が同じ過ちを繰り返さないためのささやかなtipsを紹介していきたいと思います(なお、ここで紹介するtipsは、あくまで筆者の経験に基づいて得られたものであり、アドビシステムズの公式な提供情報ではないことにご留意ください)。
Flex/AIR開発では、「ああこれは最初から用意しておくべきだった……」と後悔しがちなポイントがいくつかあります。そのひとつが、Flex/AIRアプリケーションを「開発用」と「本番用」とで切り替える仕組みです。
Flex/AIRに限らず、Webアプリケーション開発では、開発やテスト、そして実運用といった段階に応じて、以下のような複数のサーバーを用意することが一般的です。
プロジェクトによっては、ステージング環境が省略されることも多いでしょう。しかし少なくとも、開発環境と本番環境は別々の環境(Webサーバー、アプリケーションサーバー、DBサーバーなど)を用意し、開発環境上で徹底的にテストしたのち、リリース日には最新コードを本番環境に載せる――というリリース作業を実施するやり方が主流ではないでしょうか。
Flex/AIRではないHTMLベースのWebアプリケーションの場合は、こうした開発環境と本番環境の区別はそれほど難しくありません。例えば前者のサーバーがdev.example.com、後者のサーバーがwww.example.comというドメイン名であるとして、開発作業やテスト作業を行う時は開発者がWebブラウザ上でdev.example.comというURLを入力すれば、開発環境に接続できます。この入力さえ間違えなければ、両者を混同することはありません。
しかしFlex/AIRの場合(とりわけAIRの場合)は注意が必要です。例えばFlex/AIRアプリケーションの内部でHTTPServiceなどを使用してサーバーに接続するケースでは、その接続先はアプリケーション自身が指定します。
var httpService:HTTPService = new HTTPService();
httpService.url = "http://dev.example.com/hello";
このように、HTTPServiceオブジェクトのurlプロパティにて接続先URLを指定するため、開発作業やテスト作業ではdev.example.com、実運用ならwww.example.comといった具合にURL内のホスト名を適宜切り替える必要があるのです。
Flexの場合は、この問題への対処はさほど難しくありません。Flexでは、「mx.core.Application.application.url」プロパティを参照することで自分自身のダウンロード元URLを取得できます。さらにmx.utils.URLUtil.getServerNameメソッドを組み合わせることで、サーバーのホスト名を動的に取得できます。このホスト名を元に接続先URLを組み立てれば、「開発環境のFlexアプリは開発サーバーに接続し、本番環境のFlexアプリは本番サーバーに接続する」という動きを自動的に実現できます。
var url:String = Application.application.url;
var hostname:String = URLUtil.getServerName(url);
httpService.url = "http://" + hostname + "/hello";
以下のサンプルページでは、この方法を用いてホスト名を自動取得しています。
ただしこの方法には1点注意が必要です。このFlexアプリケーションをFlex Builder上で実行もしくはデバッグすると、Application.application.urlには「file:///C:/<Flex Builderのワークスペースのパス>/adc_sample03/bin-debug/adc_sample04_1.swf」といったローカルファイルを参照するURLが入ってしまい、当然URLUtil.getServerNameメソッドは正しいホスト名を返すことができません。よって例えば、アプリケーションURLが「file:///」で始まる場合は開発サーバーのホスト名を固定的に返すコードを記述する、といった対策が必要になります。
上述の方法は、残念ながらAIRアプリケーションでは使えません。ご存じのとおりAIRアプリケーションはWebブラウザ内部で表示されるWebページではなく、「.air」ファイルによってインストールされたデスクトップアプリケーションであるため、Application.application.urlプロパティには例えば「app:/foo.swf」といった値が入り、接続先のホスト名を取り出すことが不可能です。
よってAIRアプリにおいては、.airファイルのリリースビルドを作成する時点で、そのビルドが「開発用」なのか「本番用」なのかを識別するフラグを以下のような手段で埋め込んでおく必要があります。例えば、定数保持用のASクラスなどに以下のような定数のかたちでフラグを記述します。
public static const ENV:String = "dev";
//public static const ENV:String = "prod"; // 開発中はコメントアウトしておく
あとは、同フラグの値に応じて接続先ホスト名を切り替えたり、デバッグやテスト用に埋め込まれたコードを実行したりといったロジックを記述しておきます。また、こうしたフラグや接続先ホスト名をリソースバンドルに記述しておく方法もあります。
もうひとつ便利な方法はAIRのファイルシステムAPIを利用して実行環境を判断する方法です。例えば、以下のようなコードをAIRアプリ内で記述します。
var isDev:Boolean = File.desktopDirectory.resolvePath("dev").exists;
このコードでは、AIRアプリが実行されたPCのデスクトップ上に「dev」という名称のファイルまたはフォルダが存在するかチェックし、存在するならisDev変数にtrueをセットしています。一方、開発者やテスト担当者は、作業に使用するPCのデスクトップ上にdevという名称の空のファイルを必ず作成しておきます。これにより、AIRアプリのリリースビルドを「開発用」と「本番用」の2種類を用意しなくても、1つのビルドでそれぞれの環境用に自動切り替えする仕組みを実現できます。
ちなみに、AIRでは「NativeApplication.nativeApplication.publisherID」プロパティの値を参照することでAIRアプリの発行者IDを取得できますが、Flex Builder上で実行されるAIRアプリの場合には同プロパティが空になります。この性質を利用して、AIRアプリが「Flex Builder上で開発作業中」なのか「インストール済みアプリケーションとして実行中」なのかを判定できます。開発環境として必ずFlex Builderを用いる場合は、この方法も自動切り替えの手段として有効です。
Flex/AIRアプリケーションを実運用する際には、「開発用」か「本番用」かの違いのほかにも、「アプリケーションのバージョン」の違いも重要となるケースがあります。バージョン間でサーバー側が提供するAPIの動作が大きく変更されたような場合、古いバージョンのFlex/AIRアプリから新しいバージョンのサーバーに接続すると、サーバー側の実装方法によっては動作やデータ内容に不具合が発生することもあります。
こうした状況を防ぐには、Flex/AIRアプリからサーバーにリクエストを送信する際に、アプリのバージョン番号も合わせて送信してサーバー側でそれをチェックします。もし古いバージョンのアプリからのリクエストであれば、サーバー側からエラーを通知します。AIRアプリの場合は、すぐさまアップデート機能を起動すればよいでしょう。
もちろん、AIRアプリの細かなバージョンアップのたびにこうしたアップデートを強制すると、ユーザーにとって使いにくくなる場合もあります。よって、例えばアプリのバージョン番号を「1.0」のように「<メジャーバージョン番号>.<マイナーバージョン番号>」という形式にしておき、「メジャーバージョン番号が変化した場合は強制アップデート」、「マイナーバージョン番号が変化した場合はユーザーへのお知らせのみ」といったロジックにしておくのがより現実的です。
以上、今回はFlex/AIRアプリの実行環境の違いを検出し、接続先サーバーやそのほかのロジックを切り替える方法を紹介しました。筆者が担当したある案件では、開発の初期からこうした仕組みを用意しておかなかったために、テスト時に誤って開発中のAIRクライアントから本番サーバーに接続してしまいデータベース内容の不整合が発生したケースがありました。幸いサービスのリリース前でしたので大事には至りませんでしたが、こうした仕組みの重要さを知らされました。ぜひ皆さんのプロジェクトでも検討してみてください。