AIR アプリケーションの呼び出しと終了

Adobe AIR 1.0 およびそれ以降

この節では、インストールした Adobe® AIR® アプリケーションを呼び出す方法、および実行中のアプリケーションの終了に使用するオプションと考慮事項について説明します。

注意: NativeApplication、InvokeEvent および BrowserInvokeEvent オブジェクトは、AIR アプリケーションサンドボックスで実行されている SWF コンテンツでのみ使用できます。Flash Player ランタイムで実行されている SWF コンテンツ、ブラウザーまたはスタンドアローンプレーヤー(プロジェクター)内で実行されている SWF コンテンツおよびアプリケーションサンドボックスの外部の AIR アプリケーションで実行されている SWF コンテンツは、これらのクラスにアクセスできません。

AIR アプリケーションの呼び出しと終了に関する簡単な説明およびコード例については、Adobe Developer Connection で次のクイックスタートの記事を参照してください。

アプリケーションの呼び出し

AIR アプリケーションは、ユーザー(またはオペレーティングシステム)が次の動作を行った場合に呼び出されます。

  • アプリケーションをデスクトップシェルから起動する。

  • アプリケーションをコマンドラインシェルのコマンドとして使用する。

  • アプリケーションがデフォルトで関連付けられている種類のファイルを開く。

  • (Mac OS X)ドックタスクバーでアプリケーションアイコンをクリックする(アプリケーションが現在実行中であるかどうかは問いません)。

  • インストーラーでアプリケーションの起動を選択する(新規インストール作業の最後、またはインストール済みアプリケーションの AIR ファイルをダブルクリックした後)。

  • インストールされたバージョンがアプリケーションのアップデートを自動処理していることを表示したときに、AIR アプリケーションのアップデートを開始する(アプリケーション記述ファイルに <customUpdateUI>true</customUpdateUI> 宣言を含めている場合)。

  • (iOS)Apple Push Notification サービス(APNs)から通知を受信する。

  • URL を経由してアプリケーションを起動する。

  • AIR アプリケーション向けの識別情報を指定した com.adobe.air.AIR launchApplication() メソッドを呼び出す Flash バッジまたはアプリケーションをホストしている Web ページを表示する(ブラウザーによる呼び出しを可能にするには、アプリケーション記述子に <allowBrowserInvocation>true</allowBrowserInvocation> 宣言も含まれている必要があります)。

AIR アプリケーションが呼び出されるたびに、AIR はシングルトンの NativeApplication オブジェクトを通じて、型 invoke の InvokeEvent オブジェクトを送出します。アプリケーション時間が自分自身を初期化し、イベントリスナーを登録できるようにするには、invoke イベントを破棄せず、キューに入れる必要があります。リスナーが登録されると、キューに入れられているすべてのイベントが直ちに送出されます。

注意: ブラウザー呼び出し機能を使用してアプリケーションが呼び出されると、NativeApplication オブジェクトは、そのアプリケーションが既に実行中でなければ、invoke イベントのみを送出します。

invoke イベントを受け取るには、NativeApplication オブジェクト(NativeApplication.nativeApplication)の addEventListener() メソッドを呼び出します。イベントリスナーは、invoke イベントについて登録されると、登録前に発生したすべての invoke イベントも受け取ります。キューに入れられた invoke イベントは、addEventListener() に対する呼び出しが返された後、短い間隔で一度に 1 つずつ送出されます。このプロセス中に新しい invoke イベントが発生した場合、このイベントを、キューに入れられた 1 つ以上のイベントが送出される前に送出することができます。このイベントキューイングにより、初期化コードが実行される前に発生した任意の invoke イベントを処理できます。イベントリスナーは、実行の比較的遅い時点(アプリケーション初期化の後)で追加された場合でも、アプリケーション起動後に発生したすべての invoke イベントを受け取ります。

1 つの AIR アプリケーションについて、起動されるインスタンスは 1 つだけです。既に実行されているアプリケーションが再び呼び出されると、AIR は実行中のインスタンスに対して新しい invoke イベントを送出します。invoke イベントに応答し、適切なアクションを実行する(例えば新しいドキュメントウィンドウを開く)ことは、AIR アプリケーションの役割です。

InvokeEvent オブジェクトには、アプリケーションと、そのアプリケーションが呼び出されたディレクトリに渡された任意の引数が格納されます。アプリケーションがファイルの種類による関連付けによって呼び出された場合には、コマンドライン引数にそのファイルへのフルパスが含まれます。同様に、アプリケーションがアプリケーションアップデートのために呼び出された場合には、アップデート AIR ファイルへのフルパスが設定されます。

1 回の操作で複数のファイルが開かれる場合、Mac OS X では InvokeEvent オブジェクトが 1 回送出されます。各ファイルは arguments 配列に格納されます。Windows および Linux では、各ファイルごとに InvokeEvent オブジェクトが送出されます。

アプリケーションが invoke イベントを処理できるようにするには、その NativeApplication オブジェクトにリスナーを次のように登録します。

NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvokeEvent); 

さらに、イベントリスナーを次のように定義します。

var arguments:Array; 
var currentDir:File; 
public function onInvokeEvent(invocation:InvokeEvent):void { 
    arguments = invocation.arguments; 
    currentDir = invocation.currentDirectory; 
} 

コマンドライン引数のキャプチャ

AIR アプリケーションの呼び出しに関連するコマンドライン引数は、NativeApplication オブジェクトによって送出される InvokeEvent オブジェクトで送出されます。InvokeEvent の arguments プロパティには、AIR アプリケーションの呼び出し時にオペレーティングシステムによって渡される引数の配列が格納されています。引数にファイルの相対パスが含まれている場合、パスを解決するには、通常は currentDirectory プロパティを使用します。

AIR プログラムに渡される引数は、次の表に示すように、二重引用符で囲まれている場合を除いて、空白で区切られたストリングとして扱われます。

引数

配列

tick tock

{tick,tock}

tick "tick tock"

{tick,tick tock}

"tick" “tock”

{tick,tock}

\"tick\" \"tock\"

{"tick","tock"}

InvokeEvent オブジェクトの currentDirectory プロパティには、そのアプリケーションが起動されたディレクトリを表す File オブジェクトが格納されます。

アプリケーションが、そのアプリケーションによって登録された種類のファイルが開かれたことによって呼び出された場合には、そのファイルへのネイティブパスがコマンドライン引数にストリングとして設定されます(ファイルを開いたり、ファイルに対して目的の操作を実行することは、アプリケーションの役割です)。同様に、アプリケーションがアップデートを自動で(標準の AIR アップデートユーザーインターフェイスを使用せずに)実行するようにプログラムされている場合には、一致するアプリケーション ID を持つアプリケーションを格納した AIR ファイルをユーザーがダブルクリックしたときに、AIR ファイルへのネイティブパスが設定されます。

ファイルにアクセスするには、currentDirectory File オブジェクトの resolve() メソッドを次のように使用します。

if((invokeEvent.currentDirectory != null)&&(invokeEvent.arguments.length > 0)){ 
    dir = invokeEvent.currentDirectory; 
    fileToOpen = dir.resolvePath(invokeEvent.arguments[0]); 
}

引数が本当にファイルへのパスであるかどうかについても検証する必要があります。

例:呼び出しイベントログ

次の例では、invoke イベントに対するリスナーを登録し、このイベントを処理する方法を示します。この例では、受け取ったすべての呼び出しイベントを記録し、現在のディレクトリとコマンドライン引数を表示します。

ActionScript の例

package  
{ 
    import flash.display.Sprite; 
    import flash.events.InvokeEvent; 
    import flash.desktop.NativeApplication; 
    import flash.text.TextField; 
         
    public class InvokeEventLogExample extends Sprite 
    { 
        public var log:TextField; 
         
        public function InvokeEventLogExample() 
        { 
            log = new TextField(); 
            log.x = 15; 
            log.y = 15; 
            log.width = 520; 
            log.height = 370; 
            log.background = true; 
             
            addChild(log); 
 
            NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke); 
        } 
             
        public function onInvoke(invokeEvent:InvokeEvent):void 
        { 
            var now:String = new Date().toTimeString(); 
            logEvent("Invoke event received: " + now); 
                     
            if (invokeEvent.currentDirectory != null) 
            { 
                logEvent("Current directory=" + invokeEvent.currentDirectory.nativePath); 
            }  
            else  
            { 
                logEvent("--no directory information available--"); 
            } 
                     
            if (invokeEvent.arguments.length > 0) 
            { 
                logEvent("Arguments: " + invokeEvent.arguments.toString()); 
            }  
            else  
            { 
                logEvent("--no arguments--"); 
            } 
        } 
                 
        public function logEvent(entry:String):void  
        { 
            log.appendText(entry + "\n"); 
            trace(entry); 
        } 
    } 
} 

Flex の例

<?xml version="1.0" encoding="utf-8"?> 
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" 
    invoke="onInvoke(event)" title="Invocation Event Log"> 
    <mx:Script> 
    <![CDATA[ 
    import flash.events.InvokeEvent; 
    import flash.desktop.NativeApplication; 
 
    public function onInvoke(invokeEvent:InvokeEvent):void { 
        var now:String = new Date().toTimeString(); 
        logEvent("Invoke event received: " + now); 
                 
        if (invokeEvent.currentDirectory != null){ 
            logEvent("Current directory=" + invokeEvent.currentDirectory.nativePath); 
        } else { 
            logEvent("--no directory information available--"); 
        } 
                 
        if (invokeEvent.arguments.length > 0){ 
            logEvent("Arguments: " + invokeEvent.arguments.toString()); 
        } else { 
            logEvent("--no arguments--"); 
        } 
    } 
             
    public function logEvent(entry:String):void { 
        log.text += entry + "\n"; 
        trace(entry); 
    } 
    ]]> 
    </mx:Script> 
    <mx:TextArea id="log" width="100%" height="100%" editable="false" 
        valueCommit="log.verticalScrollPosition=log.textHeight;"/> 
</mx:WindowedApplication>

ユーザーログイン時の AIR アプリケーションの呼び出し

AIR アプリケーションが、現在のユーザーがログインしたときに自動的に起動するように設定するには、NativeApplication startAtLogin プロパティを true に設定します。このように設定すると、アプリケーションはユーザーがログインすると自動的に起動します。ログイン時にアプリケーションが自動起動しないようにするには、設定を false に変更するか、ユーザーが設定をオペレーティングシステムから手動で変更するか、またはアプリケーションをアンインストールします。ログイン時の起動は、実行時設定です。この設定は、現在のユーザーにのみ適用されます。startAtLogin プロパティを true に設定するには、アプリケーションがインストールされている必要があります。アプリケーションがインストールされていない(例えば ADL で起動される)場合、プロパティを設定するとエラーがスローされます。

注意: アプリケーションは、コンピューターシステムの起動時には起動しません。アプリケーションは、ユーザーのログイン時に起動します。

アプリケーションが自動的に起動されたのか、ユーザーアクションの結果起動されたのかを判別するには、InvokeEvent オブジェクトの reason プロパティを確認できます。このプロパティが InvokeEventReason.LOGIN の場合、アプリケーションは自動的に起動したことになります。その他の起動手順については、reason プロパティは次のように設定されます。

  • InvokeEventReason.NOTIFICATION(iOS の場合のみ)- アプリケーションは APNs を経由して起動されました。APNs について詳しくは、「プッシュ通知の使用」を参照してください。

  • InvokeEventReason.OPEN_URL - アプリケーションは他のアプリケーションまたはシステムによって起動されました。

  • InvokeEventReason.Standard - その他すべての場合。

reason プロパティにアクセスするには、アプリケーションのターゲットを AIR 1.5.1 以降にする必要があります(アプリケーション記述ファイルで正しい名前空間値を設定します)。

次の単純化されたアプリケーションでは、InvokeEvent reason プロパティを使用して、invoke イベントの発生時の動作方法を決定します。 reason プロパティが「login」である場合、アプリケーションは背景に留まります。それ以外の場合、メインアプリケーションが表示されるようになります。このパターンを使用しているアプリケーションは、バックグラウンド処理やイベント監視を実行できるように通常ログイン時に起動し、ユーザーがトリガーした invoke イベントに応じてウィンドウを開きます。

package { 
    import flash.desktop.InvokeEventReason; 
    import flash.desktop.NativeApplication; 
    import flash.display.Sprite; 
    import flash.events.InvokeEvent; 
 
    public class StartAtLogin extends Sprite 
    { 
        public function StartAtLogin() 
        { 
            try 
            { 
                NativeApplication.nativeApplication.startAtLogin = true; 
            } 
            catch ( e:Error ) 
            { 
                trace( "Cannot set startAtLogin:" + e.message ); 
            } 
             
            NativeApplication.nativeApplication.addEventListener( InvokeEvent.INVOKE, onInvoke ); 
        } 
                 
        private function onInvoke( event:InvokeEvent ):void 
        { 
            if( event.reason == InvokeEventReason.LOGIN ) 
            { 
                //do background processing... 
                trace( "Running in background..." ); 
            }             
            else 
            { 
                this.stage.nativeWindow.activate(); 
            } 
        } 
    } 
}
注意: 動作の違いを確認するには、アプリケーションをパッケージ化してインストールします。startAtLogin プロパティは、インストール済みのアプリケーションに対してのみ設定できます。

ブラウザーからの AIR アプリケーションの呼び出し

ブラウザー呼び出し機能を使用すると、Web サイトでは、インストールされている AIR アプリケーションをブラウザーから起動されるように起動できます。ブラウザーによる呼び出しは、アプリケーション記述ファイルで allowBrowserInvocation が次のように true に設定されている場合にのみ許可されます。

<allowBrowserInvocation>true</allowBrowserInvocation>

アプリケーションがブラウザーによって呼び出されると、アプリケーションの NativeApplication オブジェクトは BrowserInvokeEvent オブジェクトを送出します。

BrowserInvokeEvent イベントを受け取るには、AIR アプリケーションの NativeApplication オブジェクト(NativeApplication.nativeApplication)の addEventListener() メソッドを呼び出します。イベントリスナーは、BrowserInvokeEvent イベントについて登録されると、登録前に発生したすべての BrowserInvokeEvent イベントも受け取ります。これらのイベントは、addEventListener() に対する呼び出しが返された後で送出されますが、登録後に受け取られる可能性のある他の BrowserInvokeEvent イベントよりも前とは限りません。これにより、初期化コードが実行される前(例えばアプリケーションがブラウザーから最初に呼び出されたとき)に発生した BrowserInvokeEvent イベントを処理できます。イベントリスナーは、実行の比較的遅い時点(アプリケーション初期化の後)で追加された場合でも、アプリケーション起動後に発生したすべての BrowserInvokeEvent イベントを受け取ります。

BrowserInvokeEvent オブジェクトには、次のプロパティが含まれます。

プロパティ

説明

arguments

アプリケーションに渡す引数(ストリング)の配列。

isHTTPS

ブラウザー内のコンテンツが https URL スキームを使用する(true)か、使用しない(false)かを指定します。

isUserEvent

ブラウザーによる呼び出しがユーザーイベント(例えばマウスクリック)で発生したかどうかを示します。AIR 1.0 では、このプロパティは常に true に設定されます。AIR では、ブラウザー呼び出し機能に対するユーザーイベントが必要です。

sandboxType

ブラウザー内のコンテンツに対して使用するサンドボックスのタイプ。有効値の定義は、Security.sandboxType プロパティで使用できる有効値の場合と同じで、次のいずれかです。

  • Security.APPLICATION — コンテンツは、アプリケーションセキュリティサンドボックスで実行されます。

  • Security.LOCAL_TRUSTED — コンテンツは、local-with-filesystem セキュリティサンドボックスで実行されます。

  • Security.LOCAL_WITH_FILE — コンテンツは、local-with-filesystem セキュリティサンドボックスで実行されます。

  • Security.LOCAL_WITH_NETWORK — コンテンツは、local-with-networking セキュリティサンドボックスで実行されます。

  • Security.REMOTE — コンテンツは、リモート(ネットワーク)ドメインで実行されます。

securityDomain

ブラウザー内のコンテンツのセキュリティドメイン。例えば「www.adobe.com」や「www.example.org」など。このプロパティは、リモートのセキュリティサンドボックスで実行されるコンテンツ(ネットワークドメインからのコンテンツ)に対してのみ設定されます。ローカルまたはアプリケーションセキュリティサンドボックスで実行されるコンテンツに対しては設定されません。

ブラウザー呼び出し機能を使用する場合は、セキュリティ上の影響を考慮してください。Web サイトで AIR アプリケーションが起動されると、アプリケーションは BrowserInvokeEvent オブジェクトの arguments プロパティを介してデータを送信できます。このデータを、ファイルやコードを読み込む API のような注意を必要とする操作で使用する場合には、慎重に行う必要があります。リスクのレベルは、アプリケーションがそのデータを使用して実行する処理の種類によって異なります。アプリケーションが特定の Web サイトだけで呼び出されることを想定している場合、そのアプリケーションは BrowserInvokeEvent オブジェクトの securityDomain プロパティを検査する必要があります。また、そのアプリケーションを呼び出す Web サイトに対して、HTTPs を使用するように要求することもできます。これは、BrowserInvokeEvent オブジェクトの isHTTPS プロパティを検査することで検証できます。

アプリケーションは、渡されたデータを検証する必要があります。例えば、あるアプリケーションが特定のドメインの URL を渡されることを予期している場合、そのアプリケーションは、その URL が本当にそのドメインを指し示しているかどうかを検証する必要があります。これにより、攻撃者がアプリケーションを不正に操作して重要なデータを送信させることを防ぐことができます。

ローカルのリソースを指し示す可能性のある BrowserInvokeEvent 引数を、アプリケーションで使用しないでください。例えば、アプリケーションでは、ブラウザーから渡されたパスに基づいて File オブジェクトを作成することは避けてください。ブラウザーからリモートのパスが渡されることを想定している場合、アプリケーションでは、リモートプロトコルの代わりに file:// プロトコルがパスに使用されていないことを確認する必要があります。

アプリケーションの終了

アプリケーションを終了する最も早い方法は、NativeApplication exit() メソッドを呼び出すことです。これは、アプリケーションで保存するデータやクリーンアップするリソースがない場合には、適切に機能します。exit() を呼び出すと、すべてのウィンドウが閉じ、アプリケーションが終了します。しかし、例えば重要なデータを保存するために、アプリケーションのウィンドウやその他のコンポーネントが終了プロセスを中断できるようにする場合は、exit() を呼び出す前に、適切な警告イベントを送出します。

アプリケーションを適切な手順に従ってシャットダウンするためのもう一つの方法は、シャットダウンプロセスを開始する方法とは関係なく、単一の実行経路を設定することです。ユーザー(またはオペレーティングシステム)は、次に示す方法でアプリケーションの終了をトリガーすることができます。

  • NativeApplication.nativeApplication.autoExittrue の場合に、最後のアプリケーションウィンドウを閉じる。

  • オペレーティングシステムから、アプリケーション終了コマンドを選択する(例えば、ユーザーがデフォルトのメニューからアプリケーションを終了するコマンドを選択した場合)。(これは Mac OS でのみ可能です。Windows および Linux では、システムクロムによるアプリケーション終了コマンドは提供されていません。)

  • コンピューターをシャットダウンする。

終了コマンドがオペレーティングシステムを介して、これらのいずれかの方法で渡されると、NativeApplication は exiting イベントを送出します。リスナーが exiting イベントをキャンセルしなければ、開いているすべてのウィンドウが閉じられます。各ウィンドウは closing イベントを送出し、次に close イベントを送出します。いずれかのウィンドウで closing イベントがキャンセルされると、シャットダウンプロセスは停止します。

アプリケーションで、ウィンドウを閉じる順序が重要である場合には、NativeApplication からの exiting イベントをリッスンし、ユーザー自身がウィンドウを正しい順序で閉じます。これは、例えば、ツールパレットを含むドキュメントウィンドウがある場合などに、必要となる可能性があります。システムがパレットを閉じたが、ユーザーはデータを保存するために終了コマンドをキャンセルすることにした、というような場合には、これは非常に不便です。Windows では、exiting イベントを受け取る唯一の機会は、最後のウィンドウを閉じた後です(NativeApplication オブジェクトの autoExit プロパティが true に設定されている場合)。

すべてのプラットフォームで一貫性のある動作を実現するためには、終了シーケンスがオペレーティングシステムクロム、メニューコマンド、アプリケーションロジックのいずれから開始される場合でも、アプリケーションを終了するための、次に示す正しい方法を遵守してください。

  1. 常に exiting イベントを NativeApplication オブジェクトから、アプリケーションコードで exit() を呼び出す前に送出し、アプリケーションの他のコンポーネントがこのイベントをキャンセルしていないことを確認します。

    public function applicationExit():void { 
        var exitingEvent:Event = new Event(Event.EXITING, false, true); 
        NativeApplication.nativeApplication.dispatchEvent(exitingEvent); 
        if (!exitingEvent.isDefaultPrevented()) { 
            NativeApplication.nativeApplication.exit(); 
        } 
    } 
  2. NativeApplication.nativeApplication オブジェクトから送出されたアプリケーションの exiting イベントをリッスンし、ハンドラーですべてのウィンドウを閉じます(最初に closing イベントを送出します)。すべてのウィンドウが閉じたら、アプリケーションデータの保存や一時ファイルの削除などの必要なクリーンアップタスクを実行します。クリーンアップでは同期メソッドのみを使用することで、アプリケーションの終了前にそれらのメソッドが必ず終了するようにします。

    ウィンドウを閉じる順序が重要でない場合は、NativeApplication.nativeApplication.openedWindows 配列をループし、各ウィンドウを順次閉じていきます。順序が重要である場合には、ウィンドウを正しい順序で閉じる手段を提供します。

    private function onExiting(exitingEvent:Event):void { 
        var winClosingEvent:Event; 
        for each (var win:NativeWindow in NativeApplication.nativeApplication.openedWindows) { 
            winClosingEvent = new Event(Event.CLOSING,false,true); 
            win.dispatchEvent(winClosingEvent); 
            if (!winClosingEvent.isDefaultPrevented()) { 
                win.close(); 
            } else { 
                exitingEvent.preventDefault(); 
            } 
        } 
         
        if (!exitingEvent.isDefaultPrevented()) { 
            //perform cleanup 
        } 
    } 
  3. 各ウィンドウは、それ自身の closing イベントをリッスンすることで、常にそれ自身のクリーンアップを処理する必要があります。

  4. アプリケーションでは、使用する exiting リスナーを 1 つだけにします。これは、以前に呼び出されたハンドラーは、後続のハンドラーが exiting イベントをキャンセルするかどうかを知ることができないためです(また、実行の順序に依拠することも賢明ではありません)。