запуск приложения Adobe AIR несколько раз - PullRequest
12 голосов
/ 07 февраля 2010

Adobe air runtime не позволяет запускать более одного экземпляра приложения air одновременно. Безопасно ли обойти это ограничение путем произвольного изменения идентификатора издателя? Кто-нибудь знает, планирует ли Adobe разрешить одновременное использование нескольких экземпляров в Air 2.0?

Ответы [ 6 ]

21 голосов
/ 17 февраля 2010

Мы успешно внедрили хак, чтобы обойти это ограничение в чистом виде в AIR, не меняя идентификатор издателя (которому, как мне кажется, требуется несколько сертификатов).

Как вы знаете, AIR внедряет свой Mutex, используя уникальный идентификатор приложения. Этот идентификатор рассчитывается с использованием идентификатора приложения и идентификатора издателя (извлекается из сертификата, подписавшего приложение).

В каталоге установки приложения AIR находится папка META-INF (или в / share / using Linux). Эта папка META-INF содержит папку AIR, в которой находится файл application.xml. Этот файл содержит тег <id />, который определяет идентификатор приложения, который используется при вычислении идентификатора мьютекса. Если ваше приложение может записывать в папку установки, вы можете использовать API File для его редактирования во время выполнения, произвольно изменяя тег <id />, позволяя одновременно запускать несколько процессов одного приложения.

Это имеет некоторые раздражающие побочные эффекты, такие как создание новой папки в папке File.applicationStorageDirectory каждый раз. Но, используя LocalConnection, вы можете минимизировать это, многократно используя один и тот же идентификатор, регистрируя, какие из них можно использовать повторно. Кроме того, SharedObject хранятся в этой папке, поэтому не могут использоваться (или должны копироваться каждый раз, когда создается новый экземпляр, и синхронизируются, хотя LocalConnection).

Насколько я знаю, Adobe не планирует снимать это собственное ограничение. Он был реализован для мультиплатформенных целей, особенно в MacOS, где док-станция делает это более сложным (не так легко запустить одно и то же приложение дважды с помощью док-станции).

Официальный способ сделать это - поймать событие InvokeEvent.INVOKE и делать что-то вроде открытия нового окна. И в этом поведении не планируется никаких изменений для AIR 2.0.

1 голос
/ 25 февраля 2014

Дубликатор Air Application поможет вам в этой части. С его помощью вы можете запустить несколько экземпляров одного и того же приложения AIR.

https://github.com/chrisdeely/AirAppDuplicator

Просто скопируйте каталог приложения с новым именем и новым идентификатором приложения.

1 голос
/ 14 февраля 2010

Поможет ли вам, если вы инкапсулируете логику своего приложения в класс, который может работать в окне и позволять пользователю создавать несколько экземпляров этого окна в одном приложении? это поможет?

Какова основная причина, по которой вам нужно несколько приложений?

0 голосов
/ 03 мая 2017
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) { }
        }
    }   
}
0 голосов
/ 18 июня 2016

Только что сделал быстрый урок для реализации решения Тина. Просто позвоните. 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) ;
    }
}
0 голосов
/ 20 декабря 2012

Это нарушит автоматическое обновление, будьте предупреждены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...