多次启动 Adob​​e AIR 应用程序

Posted

技术标签:

【中文标题】多次启动 Adob​​e AIR 应用程序【英文标题】:starting an Adobe AIR application multiple times 【发布时间】:2011-01-14 02:37:54 【问题描述】:

Adobe air 运行时可防止同时启动多个 air 应用程序实例。通过任意更改发布者 ID 来规避此限制是否安全?有谁知道 Adob​​e 是否计划在 Air 2.0 中允许多个并发实例?

【问题讨论】:

请回答好以获得赏金。 【参考方案1】:

如果您将应用程序的逻辑封装为一个可以在窗口中运行并允许用户在一个应用程序中创建该窗口的多个实例的类,会有所帮助吗?会有帮助吗?

您需要多个应用程序的主要原因是什么?

【讨论】:

感谢您的回答,但我专门寻找单独的进程。有许多好处,例如在多处理器计算机上并行执行。 我明白了,谢谢你的解释。好问题。您可以在 Java 中拥有单独的进程...这可能是冗长的,通过 Merapi(merapiproject.net) 连接 AIR 和 Java 有什么好处吗? 再次,有趣的帖子,但它是题外话。 Merapi 是 IPC 框架而不是链接框架(如 JNI),因此无法链接到多线程 java 库;必须有一个单独启动的java进程。此外,使用 java 助手只会提供并行处理,而不是多进程的其他优点。让我们回到最初的问题:我正在寻找一种方法来启动 Flex AIR 应用程序的多个实例,特别是在 AIR 运行时中运行具有多个发布者 ID 的同一个 swf 是否合法。 只是出于好奇:空中应用是否仅限于一个线程? Lorenzo:是的,似乎仅限于一个。 flexjunk.com/2009/01/15/multi-threading-in-flexair【参考方案2】:

我们以纯 AIR 方式成功实施了一种破解方法来规避此限制,而无需更改发布者 ID(我认为这需要多个证书)。

如您所知,AIR 正在使用唯一的应用程序标识符来实现其 Mutex。此标识符是使用应用程序 ID 和发布者标识符(从签署应用程序的证书中提取的)计算得出的。

在 AIR 应用程序的安装目录中,有一个 META-INF 文件夹(或在 /share/ 中使用 Linux)。此 META-INF 文件夹包含一个 AIR 文件夹,其中包含一个“application.xml”文件。该文件包含一个<id /> 标记,它定义了应用程序标识符,用于计算互斥体标识符。如果你的应用程序可以写入安装文件夹,你可以在运行时使用File API 对其进行编辑,随机更改<id />标签,允许同一应用程序的多个进程同时运行。

这会产生一些烦人的副作用,例如每次都在 File.applicationStorageDirectory 文件夹中创建一个新文件夹。但是使用LocalConnection,您可以通过记录哪些标识符可以免费重用来多次重用相同的标识符,从而最大限度地减少这种情况。另外,SharedObject存储在这个文件夹中,所以不能使用(或者每次创建新实例时都必须复制,并通过LocalConnection同步)。

据我所知,Adobe 不打算取消这个原生限制。它是为多平台目的而实现的,特别是在 MacOS 上,其中 Dock 使这变得更加复杂(使用 Dock 启动同一个应用程序两次并不容易)。

这样做的官方方法是捕捉InvokeEvent.INVOKE 事件,并执行诸如打开新窗口之类的操作。 AIR 2.0 没有计划在此行为上进行任何更改。

【讨论】:

【参考方案3】:

这将破坏自动更新,请注意。

【讨论】:

【参考方案4】:

Air Application 复印机将在这部分为您提供帮助。使用它,您可以运行同一个 AIR 应用程序的多个实例。

https://github.com/chrisdeely/AirAppDuplicator

它只是简单地使用新名称和新应用程序 ID 复制您的应用程序目录。

【讨论】:

【参考方案5】:

刚刚做了一个快速课程来实现 Tyn 的解决方案。简单地打电话。 MultipleInstanceAirApp.changeMetaInfId(stage);

你并不真的需要舞台部分,但我在测试时用它来改变窗口的位置。 总之,尽情享受吧!

import flash.display.Stage;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;

/**
 * @author Lachhh
 */
public class MultipleInstanceAirApp 
    static private var loadFile : File;
    static private var thePath:String = "./META-INF/AIR/application.xml";
    static private var myGameId:String = "YOUR_GAME_ID";
    static private var stage:Stage ;
    static private var metaInfString:String ;

    static public var instanceNumber:int = 0;

    static public function changeMetaInfId(pStage:Stage):void 
        stage = pStage;
        var path:String = File.applicationDirectory.resolvePath(thePath).nativePath; 
        loadFile = new File(path);

        loadFile.addEventListener(Event.COMPLETE, onLoadMetaInf);
        loadFile.addEventListener(IOErrorEvent.IO_ERROR, onIoError);
        loadFile.load();
    

    private static function onLoadMetaInf(event : Event) : void 
        loadFile.removeEventListener(Event.COMPLETE, onLoadMetaInf);
        metaInfString = loadFile.data.toString();
        replaceMetaInfIdIfFound();
        saveStringToMetaInf(metaInfString);
    

    static public function saveStringToMetaInf(s:String):void 
        var b:ByteArray = new ByteArray();
        b.writeUTFBytes(s);
        saveFile(b);
    

    static public function saveFile(data:ByteArray):void 
        var thePath:String = File.applicationDirectory.resolvePath(thePath).nativePath;     
        var saveFile:File = new File(thePath);
        var fileStream:FileStream = new FileStream();
        fileStream.openAsync(saveFile, FileMode.WRITE);
        fileStream.writeBytes(data);
        fileStream.addEventListener(Event.CLOSE, onClose);
        fileStream.close();
    

    static private function replaceMetaInfIdIfFound():void 
        if(checkToReplaceId(1, 2)) return ;
        if(checkToReplaceId(2, 3)) return ;
        if(checkToReplaceId(3, 4)) return ;
        checkToReplaceId(4, 1);

    

    static private function checkToReplaceId(i:int, newI:int):Boolean 
        var id:String = getGameIdWithBrackets(i);
        var newId:String = getGameIdWithBrackets(newI);
        if(metaInfString.indexOf(id) != -1) 
            metaInfString = myReplace(metaInfString, id, newId);
            instanceNumber = newI;
            return true;
        
        return false;
    

    private static function onClose(event : Event) : void 
        trace("all done!");
        placeScreenAccordingToInstanceNumber();
    

    static private function placeScreenAccordingToInstanceNumber():void ;
        switch(instanceNumber) 
            case 1 : 
                stage.nativeWindow.x = 115;
                stage.nativeWindow.y = 37;
                break;
            case 2 : 
                stage.nativeWindow.x = 115 + 660;
                stage.nativeWindow.y = 37;
                break;
            case 3 : 
                stage.nativeWindow.x = 115;
                stage.nativeWindow.y = 37 + 380;
                break;
            case 4 : 
                stage.nativeWindow.x = 115 + 660;
                stage.nativeWindow.y = 37 + 380;
                break;
        
    

    private static function onIoError(event : IOErrorEvent) : void 
        trace("io Error");
    

    static private function getGameIdOriginalWithBrackets():String 
        return "<id>" + myGameId + "</id>";
    

    static private function getGameIdWithBrackets(i:int):String 
        if(i == 1) return getGameIdOriginalWithBrackets();
        return "<id>" + myGameId + i + "</id>";
    

    static public function myReplace(msg:String, toFind:String, toBeReplacedWith:String):String 
        return msg.split(toFind).join(toBeReplacedWith) ;
    

【讨论】:

【参考方案6】:
package hobis.airpc 

    import flash.events.Event;
    import flash.filesystem.File;   
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;
    import flash.utils.ByteArray;
    import jhb0b.utils.MArrayUtil;

    public final class MAppXmlUpdateCounter
    
        private static var _AppXmlFile:File;

        public static function Update():void
        
            _AppXmlFile = new File(File.applicationDirectory.nativePath);           
            _AppXmlFile = _AppXmlFile.resolvePath('META-INF\\AIR\\application.xml');
            _AppXmlFile.addEventListener(Event.COMPLETE, ppOpened);
            _AppXmlFile.load();         
        

        private static function ppOpened(evt:Event):void
        
            const trx1:RegExp = /<id>[\s\S]*?<\/id>/;
            const trx2:RegExp = /<([^>]+)>/g;

            var tXmlStr:String = _AppXmlFile.data.toString();
            var tMatArr:Array = tXmlStr.match(trx1);
            if (!MArrayUtil.is_empty(tMatArr))
            
                var tIdTagStr:String = tMatArr[0];
                var tIdValStr:String = tIdTagStr.replace(trx2, '');

                var tOriVal:String;
                var tNumVal:uint;
                var tStrArr:Array = tIdValStr.split('-');
                if (tStrArr != null)
                
                    if (tStrArr.length == 2)
                    
                        tOriVal = tStrArr[0];
                        tNumVal = int(tStrArr[1]);                              
                    
                    else
                    if (tStrArr.length == 1)
                    
                        tOriVal = tStrArr[0];
                        tNumVal = 0;
                    
                    tNumVal++;

                    var tIdNewStr:String = '<id>' + tOriVal + '-' + tNumVal + '<\/id>';                 
                    var tNewXmlStr:String = tXmlStr.replace(tIdTagStr, tIdNewStr);                  
                    ppSaveFile(tNewXmlStr);
                
            
            _AppXmlFile = null;
        

        private static function ppSaveFile(val:String):void
        
            var tfs:FileStream;
            try
            
                tfs = new FileStream();
                tfs.openAsync(_AppXmlFile, FileMode.WRITE);
                var tba:ByteArray = new ByteArray();
                tba.writeUTFBytes(val);         
                tfs.writeBytes(tba);                
                tba.clear();
            
            catch (e:Error)  
            try
            
                tfs.close();
            
            catch (e:Error)  
        
       

【讨论】:

欢迎来到 Stack Overflow!虽然欢迎使用此代码 sn-p,并且可能会提供一些帮助,但它将是 greatly improved if it included an explanation 的 如何 它解决了这个问题。没有这个,你的回答就没有多少教育价值了——记住你是在为未来的读者回答这个问题,而不仅仅是现在提问的人!请edit您的答案添加解释,并说明适用的限制和假设。

以上是关于多次启动 Adob​​e AIR 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

将参数从 Java 活动传递到 Adob​​e AIR 应用程序

将参数从 Java 活动传递到 Adob​​e AIR 应用程序

iOS 8 中的 Adob​​e AIR - 后台通知操作

在 ActionScript 3.0 中以编程方式检测 Adob​​e Air 和 Adob​​e Flex

将 Flex 转换为 Adob​​e Air

选择大量文件时 Adob​​e Air 应用程序关闭