Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Air iOS SharedObject deleted after updating

I'm using SharedObjects in my game to store the progress of the player in the game (level scores, unlocked levels, etc.).

Everything is working fine, but the problem is when I submitted an update of the game (with the same certificates and the same names of the .swf and .ipa files) when the game is updated the old SharedObject is deleted and this is very big problem for the game and for me.

Both versions of the game are made with Flash CS 6 and Air SDK 3.5.

Any idea why the SharedObject is deleted, how can I prevent that?

like image 498
Martin Grigorov Avatar asked Nov 12 '22 17:11

Martin Grigorov


1 Answers

I'm assuming that the reason why SharedObject becomes overwritten is because it's bundled with the .ipa during conversion.

I understand that will not help your current situation with salvaging your SharedObject but you could try using flash.filesystem to read/write your data to a preference file instead of employing SharedObject in the future.

Below is my Archive class that I use with my own work, but I've never developed for iOS before so i'm not certain that it will function as it does on other deployment targets, although I believe it should.

Use Case:

//Imports
import com.mattie.data.Archive;
import com.mattie.events.ArchiveEvent;

//Constants
private static const PREF_CANVAS_VOLUME:String = "prefCanvasVolume";
private static const DEFAULT_VOLUME:Number = 0.5;

//Initialize Archive
private function initArchive():void
{
    archive = new Archive();
    archive.addEventListener(ArchiveEvent.LOAD, init);
    archive.load();
}

//Initialize
private function init(event:ArchiveEvent):void
{
    archive.removeEventListener(ArchiveEvent.LOAD, init);

    canvasVolume = archive.read(PREF_CANVAS_VOLUME, DEFAULT_VOLUME);         
}

//Application Exiting Event Handler
private function applicationExitingEventHandler(event:Event):void
{
    stage.nativeWindow.removeEventListener(Event.CLOSING, applicationExitingEventHandler);

    archive.write(PREF_CANVAS_VOLUME, canvas.volume);

    archive.addEventListener(ArchiveEvent.SAVE, archiveSavedEventHandler);
    archive.save();
}

//Archive Saved Event Handler
private function archiveSavedEventHandler(event:ArchiveEvent):void
{
    archive.removeEventListener(ArchiveEvent.SAVE, archiveSavedEventHandler);

    NativeApplication.nativeApplication.exit();
}

Archive Class

package com.mattie.data
{
    //Imports
    import com.mattie.events.ArchiveEvent;
    import flash.data.EncryptedLocalStore;
    import flash.desktop.NativeApplication;
    import flash.events.EventDispatcher;
    import flash.filesystem.File;
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;
    import flash.net.registerClassAlias;
    import flash.utils.ByteArray;

    //Class
    public final class Archive extends EventDispatcher
    {
        //Properties
        private static var singleton:Archive;

        //Variables
        private var file:File;
        private var data:Object;

        //Constructor
        public function Archive()
        {
            if (singleton)
            {
                throw new Error("Archive is a singleton that is only accessible via the \"archive\" public property.");
            }

            file = File.applicationStorageDirectory.resolvePath(NativeApplication.nativeApplication.applicationID + "Archive");

            data = new Object();

            registerClassAlias("Item", Item);
        }

        //Load
        public function load():void
        {
            if (file.exists)
            {
                var fileStream:FileStream = new FileStream();
                fileStream.open(file, FileMode.READ);

                data = fileStream.readObject();

                fileStream.close();
            }

            dispatchEvent(new ArchiveEvent(ArchiveEvent.LOAD));
        }

        //Read
        public function read(key:String, defaultValue:* = null):*
        {
            var value:* = defaultValue;

            if (data[key] != undefined)
            {
                var item:Item = Item(data[key]);

                if (item.encrypted)
                {
                    var bytes:ByteArray = EncryptedLocalStore.getItem(key);

                    if (bytes == null)
                    {                       
                        return value;
                    }

                    switch (item.value)
                    {
                        case "Boolean":     value = bytes.readBoolean();                        break;
                        case "int":         value = bytes.readInt();                            break;
                        case "uint":        value = bytes.readUnsignedInt();                    break;
                        case "Number":      value = bytes.readDouble();                         break;
                        case "ByteArray":           bytes.readBytes(value = new ByteArray());   break;

                        default:            value = bytes.readUTFBytes(bytes.length);
                    }
                }
                else
                {
                    value = item.value;                    
                }
            }

            return value;
        }

        //Write
        public function write(key:String, value:*, encrypted:Boolean = false, autoSave:Boolean = false):void
        {
            var oldValue:* = read(key);

            if (oldValue != value)
            {
                var item:Item = new Item();
                item.encrypted = encrypted;

                if (encrypted)
                {
                    var constructorString:String = String(value.constructor);
                    constructorString = constructorString.substring(constructorString.lastIndexOf(" ") + 1, constructorString.length - 1);

                    item.value = constructorString;

                    var bytes:ByteArray = new ByteArray();

                    switch (value.constructor)
                    {
                        case Boolean:       bytes.writeBoolean(value);          break;                  
                        case int:           bytes.writeInt(value);              break;
                        case uint:          bytes.writeUnsignedInt(value);      break;
                        case Number:        bytes.writeDouble(value);           break;
                        case ByteArray:     bytes.writeBytes(value);            break;

                        default:            bytes.writeUTFBytes(value);
                    }

                    EncryptedLocalStore.setItem(key, bytes);
                }
                else
                {
                    item.value = value;                    
                }

                data[key] = item;

                dispatchEvent(new ArchiveEvent(ArchiveEvent.WRITE, key, oldValue, value));

                if (autoSave)
                {                    
                    save();
                }
            }
        }

        //Remove
        public function remove(key:String, autoSave:Boolean = false):void
        {
            if (data[key] != undefined)
            {
                var oldValue:* = read(key);

                if (Item(data[key]).encrypted)
                {                    
                    EncryptedLocalStore.removeItem(key);
                }

                delete data[key];

                dispatchEvent(new ArchiveEvent(ArchiveEvent.DELETE, key, oldValue));

                if (autoSave)
                {                    
                    save();
                }
            }
        }

        //Contains
        public function contains(key:String):Boolean
        {
            return (data[key] != undefined);
        }

        //Save
        public function save():void
        {
            var fileStream:FileStream = new FileStream();
            fileStream.open(file, FileMode.WRITE);
            fileStream.writeObject(data);
            fileStream.close();

            dispatchEvent(new ArchiveEvent(ArchiveEvent.SAVE));
        }

        //Get Singleton
        public static function get archive():Archive
        {
            if (!singleton)
            {
                singleton = new Archive();
            }

            return singleton;
        }
    }
}

//Item
class Item
{
    //Variables
    public var value:*;
    public var encrypted:Boolean = false;
}

Archive Event Class

package com.mattie.events
{
    //Imports
    import flash.events.Event;

    //Class
    public class ArchiveEvent extends Event
    {
        //Constants
        public static const LOAD:String = "load";
        public static const WRITE:String = "write";
        public static const DELETE:String = "delete";
        public static const SAVE:String = "save";

        //Properties
        public var key:String;
        public var oldValue:*;
        public var newValue:*;

        //Constructor
        public function ArchiveEvent(type:String, key:String = null, oldValue:* = null, newValue:* = null) 
        {
            super(type);

            this.key = key;
            this.oldValue = oldValue;
            this.newValue = newValue;
        }

        //Clone
        public override function clone():Event
        {
            return new ArchiveEvent(type, key, oldValue, newValue);
        }

        //To String
        public override function toString():String
        {
            return formatToString("ArchiveEvent", "type", "key", "oldValue", "newValue");
        }
    }
}
like image 99
Chunky Chunk Avatar answered Nov 15 '22 07:11

Chunky Chunk