AIR/Flex: 2010年9月アーカイブ

夕べ書いた URLLoader + URLRequest で Web サーバからファイルを取得する AIR アプリに、BASIC 認証処理を追加してみた。
実際の運用では、BASIC 認証を行うことになるからな、多分。

(1) Base64Encoder クラスが定義されている mx.utils.* パッケージを import
        import mx.utils.*;
(2) Base64Encoder クラスを使って認証情報(ユーザID,パスワード)を Base64 encode
(3) http request header に Authorization ヘッダラインを追加((2)で encode したデータをセット)

という手順。具体的には、

    <mx:Script>
    <![CDATA[

        import mx.utils.*;
        <略>

        private function getHttp():void {

            var user:String    = "user1"; // ログインID
            var password:String    = "passwd1"; // パスワード
            var encoder:Base64Encoder    = new Base64Encoder();
            encoder.encode(user + ":" + password); // Base64 encode

            var req:URLRequest = new URLRequest();
            req.url    = "http://www.exsample.com/test/hoge.jpg";
            req.requestHeaders = [new URLRequestHeader("Authorization", "Basic " + encoder.toString())]; // Authorization ヘッダラインを追加
            req.userAgent    = "Test Bot 1.0";

            var loader:URLLoader = new URLLoader();

            loader.addEventListener(Event.COMPLETE,loadComp);

            loader.dataFormat = URLLoaderDataFormat.BINARY;
            loader.load(req);

        }

        <略>

    ]]>
    </mx:Script>

ちゅう感じじゃね。

requestHeaders プロパティは配列なので、

            var authorization:URLRequestHeader = new URLRequestHeader("Authorization", "Basic " + encoder.toString());
            req.requestHeaders.push(authorization);

という具合に push してやってもいいけど。うむ。push した方がコード的にはきれいかな。(好みの問題だが:-P)

これで BASIC 認証した先にあるデータもバッチリ落としてくることが出来るようになった。

まあ、今回の案件、別に生データを持って行かれても困るようなものではないので、わざわざ BASIC 認証をかける必要も無いのだが、そこは、それ。最近は、「セキュリティのことはちゃんと考えてますよ!」というポーズも必要だからなあ。(^^;

システム屋として「そこは別に必要ないでしょ?」と思うことでもな。(^^;

今度作成予定の Adobe AIR アプリに、Webサーバ上から特定のファイルを落としてくる機能をつけないといけないので、どんな方法があるか試してみようと思って、取りあえず URLLoader + URLRequest クラス利用で作ってみた。

「受信スタート」ボタンを押したら、Web サーバ上の画像ファイルを取得し、それを hoge.jpg という名前で書き出すだけのプログラム。

最初は HTTPService クラスを使った方がいいのかなと(だって名前がそのものずばりだから)色々やってみたのだが、どうも HTTPService クラスは Web サービス用?
データをどうしても ByteArray で取り出せないので諦めた。
XML や CSV などのテキストデータではうまくいったんだけどなあ。

で、取りあえず URLLoader + URLRequest クラスを利用してデータを取得するパターンのソースが↓こんな感じ。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="274" height="120">
   
    <mx:Script>
    <![CDATA[

        import flash.events.Event;
        import flash.net.URLLoader;
        import flash.net.URLLoaderDataFormat;
        import flash.net.URLRequest;
        import flash.net.URLRequestHeader;
        import flash.net.URLVariables;
        import flash.utils.ByteArray;

        private function getHttp():void {

            var req:URLRequest = new URLRequest();
            req.url    = "http://www.exsample.com/test/hoge.jpg";
            req.userAgent    = "Test Bot 1.0";

            var loader:URLLoader = new URLLoader();

            loader.addEventListener(Event.COMPLETE,loadComp);

            loader.dataFormat = URLLoaderDataFormat.BINARY;
            loader.load(req);

        }

        private function loadComp(event:Event):void{

            var urlLoader:URLLoader = event.target as URLLoader;
            var byte:ByteArray    = urlLoader.data as ByteArray;

            var file:File    = File.userDirectory.resolvePath("hoge.jpg");
            var stream:FileStream    = new FileStream();
            stream.openAsync(file, FileMode.WRITE);
            stream.writeBytes(byte, 0, byte.bytesAvailable);
            stream.close();

        }

    ]]>
    </mx:Script>

    <mx:Button x="93.5" y="20" label="受信スタート" id="button1" click="getHttp();"/>

</mx:WindowedApplication>

最初、取得するデータの型を

    loader.dataFormat = URLLoaderDataFormat.BINARY;

という具合に指定してなかったので(多分、ディフォルト値は'TEXT'?)、ハマってしまった。
いやあ、日頃、データ型の無い Perl を使うことが多いんでねえ。

バイナリだろうがテキストだろうが、生のデータを返してくるプロパティがあればいいのにな。

20100902_air2.jpg

今度作る AIR アプリでは、リモートサーバから Web ページ表示のためのファイル(HTML 及び画像ファイル等)を一旦ローカルマシン上に取得し、それを HTML コンポーネントで表示する予定。
回線が混んでいる時に、ジワジワと画面が表示されるのを見せたくないからだ。スパっと次画面に切り替えたいわけよ。

ということで、そのファイルの取得に(プロトコルは FTP にするか HTTP にするか現時点ではわからないが)Socket 通信を行うことになるので、Socket クラスを試しに使ってみた。

サーバ名を入力してボタンを押したら、そのトップページの HTML ソースを表示するだけの AIR アプリだ。

HTML 開発者用 Adobe AIR API リファレンスガイドには、JavaScript から AIR ランタイムクラスを使用する例が載っていたので、それを AIR アプリ用に変更してみた。

以下のようなソース。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="398" height="318">

 <mx:Script>

  <![CDATA[

  public var socket:Socket;
  public var response:String;

  private function get_html():void {

   socket = new Socket(input1.text, 80);
   socket.addEventListener(Event.CLOSE, closeHandler);
   socket.addEventListener(Event.CONNECT, connectHandler);
   socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
   socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
   socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
 
  }

  private function writeln(str:String):void {

   str += "\n";

   try {
    socket.writeUTFBytes(str);
   }
   catch(e:String) {
    trace(e);
   }
  }

  private function sendRequest():void {

   trace("sendRequest");
   response = "";
   writeln("GET /");
   socket.flush();

  }

  private function readResponse():void {

   var str:String = socket.readUTFBytes(socket.bytesAvailable);
   response += str;

  }

  private function closeHandler(event:Event):void {

   trace("closeHandler: " + event);
   text1.text = response.toString();

  }

  private function connectHandler(event:Event):void {

   trace("connectHandler: " + event);
   sendRequest();

  }

  private function ioErrorHandler(event:IOErrorEvent):void {

   trace("ioErrorHandler: " + event);

  }

  private function securityErrorHandler(event:SecurityErrorEvent):void {

   trace("securityErrorHandler: " + event);

  }

  private function socketDataHandler(event:ProgressEvent):void {

   trace("socketDataHandler: " + event);
   readResponse();

  }

  ]]>

 </mx:Script>

 <mx:Text x="10" y="68" text="" width="376" height="238" id="text1"/>
 <mx:TextInput x="10" y="23" id="input1" width="297"/>
 <mx:Button x="315" y="23" label="Access" id="button1" click="get_html()"/>
 
</mx:WindowedApplication>

これでばっちり Web サーバと Socket 通信を行うことが出来た。

昔、Visual Basic 6 や Perl ではけっこう Socket 通信アプリを書いたが、最近はとんとご無沙汰だった。

さて、FTP プロトコルのシーケンスを思い出さないとな(^^;

20100902_test.jpg

今度、デジタルサイネージシステムを AIR アプリケーションで実装する話があるのだが、それに関連してユーザより

・AIR アプリ上で複数の Web 画面を同時に表示できるか?
・ローカルファイルも問題なく表示出来るか?

という二点について確認の依頼があったので試してみた。

結論から言えばどちらも問題無し。

3つの HTML コンポーネント(HTML レンダリングエンジンは WebKit)を AIR アプリ上に配置し、それぞれ、

http://www.yahoo.co.jp/
http://www.excite.co.jp/
・D:\X\hogehoge\test\test1.html(ローカルファイル)

にアクセスしてみたが、問題なく表示された。

ローカルファイルについては、Mac OS X 10.6 上でもテストしてみたが、

file:///Users/hogehoge/Documents/TEST/test.html(ローカルファイル)

へのアクセスも問題なく表示された。

ま、当然の結果だが、最近はセキュリティ関係のからみで、ローカルファイルへのアクセスが凄く制限される(ややこしい手順を踏まないとアクセス出来ない)ケースが多いので、そこがちょっと心配だったのだ。

このアーカイブについて

このページには、2010年9月以降に書かれたブログ記事のうちAIR/Flexカテゴリに属しているものが含まれています。

前のアーカイブはAIR/Flex: 2010年5月です。

次のアーカイブはAIR/Flex: 2010年11月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。


月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら