Air android/mobile: same sharedobject for different apps? - android

I have two apps, one is a trial version the other the full version of a game, both made with adobe air. While saving data via the sharedobjects solution is no problem, I would like to use "one" savegame for both appsm, so users can keep their progress when upgrading to the full version. I tried around a little. But code like e.g. ...:
SharedObject.getLocal("myApp","/");
... doesnt work. So the question is, is there a way to have two Air apps using the same shared object? Or maybe if not using, at least "read" the shared object of another Air app?
Thanks in advance,
ANB_Seth

The answer is yes, I actually made a game transfer system for iOS and Android via network connection and 6 digit hash the user has to enter in the newly installed app to fetch the SO from the server. You could do this with a simple file stored locally on the SD card or other local storage device.
/**
* send this user's current save data to the server
*/
public function send():void{
var ba:ByteArray = new ByteArray();
// Main.sv.user - is the registerClassAlias object we write/read locally via SharedObject
ba.writeObject(Main.sv.user);
var name:String = Crypto.hash("Random Secrect Salt - typically user score, name, etc.");
// create 6 digit hash
var key:String = Crypto.hash(name).slice(0, 6).toUpperCase();
var request:URLRequest = new URLRequest ( 'https://sharedobject.com/transfer/save/name/'+name+'/key/'+key );
var loader: URLLoader = new URLLoader();
request.contentType = 'application/octet-stream';
request.method = URLRequestMethod.POST;
request.data = ba;
loader.addEventListener(IOErrorEvent.IO_ERROR, function (evt:Event) {
trace("error - network");
onSaveRestoreEvent(1);
});
loader.addEventListener(Event.COMPLETE, function (evt:Event) {
addChild(new BaseDialog("Save Sent To Server", "Your data has been sent to the server. To get this data back from the server " +
"you will need your secret key. Please write this six digit key down:\n"+name));
});
loader.load( request );
}
/**
* create a GET SO dialog
*/
public function receive():void{
var text:Sprite = new Sprite();
var textInput:TextInput = new TextInput();
textInput.width = Constants.SCREEN_WIDTH-100;
textInput.y = -50;
text.addChild(textInput);
var dialog:BaseDialog = new BaseDialog("Enter Secret Save Key", "Please enter your six digit secret save key in the field below, then press \"Get\".\n\n",
"Get", function():void{
text.removeChildren();
var url:String = "https://sharedobject.com/transfer/get/name/"+textInput.text; //servlet url
var request:URLRequest = new URLRequest(url);
//get rid of the cache issue:
var urlVariables:URLVariables = new URLVariables();
urlVariables.nocache = new Date().getTime();
request.data = urlVariables;
request.method = URLRequestMethod.GET;
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, function (evt:Event) {
var loader:URLLoader = URLLoader(evt.target);
var bytes:ByteArray = loader.data as ByteArray;
bytes.position = 0;
if(bytes.length <= 10 || !(bytes.readObject() is User)){
onSaveRestoreEvent(2);
}else{
try{
bytes.position = 0;
Main.sv.user = (bytes.readObject() as User);
Main.sv.save();
onSaveRestoreEvent(0);
}
catch( e : EOFError ){
onSaveRestoreEvent(3);
}
}
});
loader.addEventListener(IOErrorEvent.IO_ERROR, function (evt:Event) {
trace("error - network");
onSaveRestoreEvent(1);
});
loader.load(request);
},
"Close", function():void{text.removeChildren();}, null, null, text);
dispatchEvent(new CreateBaseDialogEvent(dialog));
}
/**
* called after the restore save system is done
* #param prompt int [0 = complete][1 = error network][2 = error key][3 = error EOF]
*/
private function onSaveRestoreEvent(prompt:int):void{
var dialog:BaseDialog;
if(prompt == 0){
dialog = new BaseDialog("Restore Complete!", "All save data has been restored.");
}else if(prompt == 1){
dialog = new BaseDialog("Network Error!", "Please seek an internet connection and try again.");
}else if(prompt == 2){
dialog = new BaseDialog("Invalid Secret Key!", "The key you've entered seems to be invalid, or the save data has expired on the server. " +
"Data only lasts on the server for 24 hours.");
}else{
dialog = new BaseDialog("Error!", "There was an issue getting the file from the server. Please try the transfer again.");
}
dispatchEvent(new CreateBaseDialogEvent(dialog));
}

Related

Sending response to generated session

I'm wiriting my application in Android, but i don't know how to send response only to device whos generated session with special ID in express-session. For example, i have 3 phones and click at the same time button login with difference data in pools, all 3 devices captured the same object instead of 3 different destined ( first response object from express was caught by 3 devices rest 2 object ignored, i want to sent object every one of them ).
....
var express = require('express');
var session = require('express-session');
var crypto = require('crypto');
var uuid = require('node-uuid');
var app = express();
app.use(session({
secret: 'DFGDFG',
resave: false,
saveUninitialized:false,
genid:function(req){
return crypto.createHash('sha256').update(uuid.v1()).update(crypto.randomBytes(256)).digest("hex");
},
}));
app.post('/login', (request,response)=> {
var post_data = request.body;
request.session.user = post_data.user;
request.session.password = post_data.password;
if(err){
console.log("error");
}
else{
var db= client.db('test');
db.collection('object').findOne({'user':request.session.user}, function(error,user){
if(user.password == request.session.password){
request.session.amount = user.amount; // if password was correct, sending amount account
console.log('Success');
res.send(request.session.amount);
}
else{
console.log('Password invalid');
}
}
});

Faces indexed by iOS/Android app are not detected by Android/iOS App - AWS Rekognition

So I have been working on a product (Android First and then iOS) for a long time that index faces of people using AWS Rekognition and when they are again scanned later, it identifies them.
It's working great when I index a face from an Android device and then try to search it with an Android device. But if I try to search it later on iOS app, it doesn't find it. Same is the result if I go other way round. Index with iOS, search with Android, not found.
The collection ID is same while indexing and searching on both devices. I couldn't figure out how is it possible that a face indexed by one OS type, same region, same collection, couldn't be found while on other device.
If anyone here could try and help me with the issue, please do. I'll be really thankful.
Update 1: I have called "listCollections" function on both iOS and android apps. Both of them are showing different list of collections. This is the issue. But I can't figure our why it is happening. The identity pool and region is same on both of them.
Here is my Android Code to access Rekognition:
mCredentialsProvider = new CognitoCachingCredentialsProvider(
mContext,
"us-east-2:xbxfxexf-x5x5-xax7-x9xf-x5x0xexfx1xb", // Identity pool ID
Regions.US_EAST_2 // Region
);
mUUID = UUID.randomUUID().toString().replace("-", "");
mAmazonS3Client = new AmazonS3Client(mCredentialsProvider);
mAmazonS3Client.setRegion(Region.getRegion(Regions.US_EAST_2));
mAmazonRekognitionClient = new AmazonRekognitionClient(mCredentialsProvider);
if(!mAmazonS3Client.doesBucketExist(mFacesBucket)) {
mAmazonS3Client.createBucket(mFacesBucket);
}
Log.i(TAG, "Uploading image to S3 Bucket");
mAmazonS3Client.putObject(mFacesBucket, getS3ObjectName(), new File(data[0].toString()));
Log.i(TAG, "Image Uploaded");
Image image = new Image();
try {
image.setBytes(ByteBuffer.wrap(Files.toByteArray(new File(data[0].toString()))));
} catch (IOException e) {
e.printStackTrace();
}
Log.i(TAG, "Indexing image");
IndexFacesRequest indexFacesRequest =new IndexFacesRequest()
.withCollectionId(mFacesCollection)
.withImage(image)
.withExternalImageId(mUUID)
.withDetectionAttributes("ALL");
mAmazonRekognitionClient.indexFaces(indexFacesRequest);
Here is my iOS code to access Rekognition:
func uploadToCollection(img: UIImage)
{
let myIdentityPoolId="us-east-2:xbxfxexf-x5x5-xax7-x9xf-x5x0xexfx1xb"
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast2, identityPoolId: myIdentityPoolId)
//store photo in s3()
let configuration = AWSServiceConfiguration(region: .USEast2, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
rekognitionClient = AWSRekognition.default()
guard let request = AWSRekognitionIndexFacesRequest() else
{
puts("Unable to initialize AWSRekognitionindexFaceRequest.")
return
}
var go=false
request.collectionId = "i_faces" + self.firebaseID.lowercased() //here iosCollection will be replaced by firebase Current UserID
request.detectionAttributes = ["ALL", "DEFAULT"]
request.externalImageId = self.UUID //this should be mUUID, passed as parameter to this function
let sourceImage = img
let image = AWSRekognitionImage()
image!.bytes = sourceImage.jpegData(compressionQuality: 0.7)
request.image = image
self.rekognitionClient.indexFaces(request) { (response:AWSRekognitionIndexFacesResponse?, error:Error?) in
if error == nil
{
print("Upload to Collection Complete")
}
go=true
return
}
while(go==false){}
}
Create a collection and added images to the collection and create an index. I suspect few things in your setup and code.
1) The Identity Pool Id, AWS Region used across iOS and Android
2) The name of the collection used (pay attention to the delimiters used in the collection name)
Android:
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(appContext, "MyPoolID", Regions.US_EAST_1);
public void searchFacesByImage() {
Image source = new Image().withS3Object(new S3Object().withBucket("us-east-1-bucket").withName("ms.jpg"));
Image ms2 = new Image().withS3Object(new S3Object().withBucket("us-east-1-bucket").withName("ms-2.jpg"));
Image ms3 = new Image().withS3Object(new S3Object().withBucket("us-east-1-bucket").withName("ms-3.jpg"));
Image ms4 = new Image().withS3Object(new S3Object().withBucket("us-east-1-bucket").withName("ms-4.jpg"));
String collectionId = "MyCollectionID";
AmazonRekognitionClient client = new AmazonRekognitionClient(credentialsProvider);
try {
System.out.println("Creating collection: " + collectionId );
CreateCollectionRequest request = new CreateCollectionRequest().withCollectionId(collectionId);
CreateCollectionResult createCollectionResult = client.createCollection(request);
System.out.println("CollectionArn : " + createCollectionResult.getCollectionArn());
System.out.println("Status code : " + createCollectionResult.getStatusCode().toString());
} catch (Exception ex) {
ex.printStackTrace();
}
IndexFacesRequest indexFacesRequest = new IndexFacesRequest();
indexFacesRequest.setImage(source);
indexFacesRequest.setCollectionId(collectionId);
client.indexFaces(indexFacesRequest);
indexFacesRequest = new IndexFacesRequest();
indexFacesRequest.setImage(ms2);
indexFacesRequest.setCollectionId(collectionId);
client.indexFaces(indexFacesRequest);
indexFacesRequest = new IndexFacesRequest();
indexFacesRequest.setImage(ms4);
indexFacesRequest.setCollectionId(collectionId);
client.indexFaces(indexFacesRequest);
SearchFacesByImageRequest searchFacesByImageRequest = new SearchFacesByImageRequest();
searchFacesByImageRequest
.withCollectionId(collectionId)
.withImage(ms3)
.withFaceMatchThreshold(80F);
SearchFacesByImageResult searchFacesByImageResult =
client.searchFacesByImage(searchFacesByImageRequest);
List <FaceMatch> faceImageMatches = searchFacesByImageResult.getFaceMatches();
for (FaceMatch face: faceImageMatches) {
Log.d(TAG, face.toString());
}
}
iOS:
Create the Cognito Credentials Provider
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 identityPoolId: #"MyPoolID"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
Use the same Identity Pool Id and Region (us-east-1).
func faceIndexNoFacesSearch() {
let rekognition = AWSRekognition.default()
let faceRequest = AWSRekognitionSearchFacesByImageRequest()
do {
let image = AWSRekognitionImage()
image?.s3Object = AWSRekognitionS3Object()
image?.s3Object?.bucket = "us-east-1-bucket"
image?.s3Object?.name = "ms-2.jpg"
faceRequest!.image = image
faceRequest!.collectionId = "MyCollectionID"
rekognition.searchFaces(byImage: faceRequest!).continueWith { (response) -> Any? in
XCTAssertNil(response.error)
XCTAssertNotNil(response.result)
if let result = response.result {
XCTAssertNotNil(result.faceMatches)
}
return nil
}.waitUntilFinished()
} catch {
print("exception")
}
}
Please post questions in the comment and we can discuss there.
Ok so the problem turned out to be much different and solution was rather very simple. I posted another question regarding the same problem when I found it was a bit different and I have posted an answer as well.
Here it is:
https://stackoverflow.com/a/53128777/4395264

as3 air Upload issue with Android Upload file more than 400 KB

i am trying to upload a zip file using FTP, on Android when the file size less than 400 KB it is uploaded correctly, when it is more than 400 KB only 414 KB got uploaded and the result file is corrupted.
I tried same code from Windows and it is working with all sizes.
here is my code:
public function uploadZipFile() {
//Socket instance which will be used to connect to ftp server
s.addEventListener(IOErrorEvent.IO_ERROR,onIOERR);
s.addEventListener(ProgressEvent.SOCKET_DATA, onReturnData);
s.addEventListener(Event.CONNECT, onConnectHandler);
s.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
//
//Socket instance which will be used to connect to receive data sent by ftp server
r.addEventListener(ProgressEvent.SOCKET_DATA, onServData);
r.addEventListener(Event.CONNECT, onPasvConn);
r.addEventListener(IOErrorEvent.IO_ERROR,onIOERR);
dtimer = new Timer(10,1);
dtimer.addEventListener(TimerEvent.TIMER_COMPLETE,function(){checkForStream();});
this.addEventListener('dataReceived',onDataReceived);
var file:File = new File("XXX.zip");
initUpload(file)
}
private function onReturnData(evt:ProgressEvent)
{
var d = s.readUTFBytes(s.bytesAvailable);
trace(d);
//check here for complete list of return codes and their meaning
//- http://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
// the return message will have a 3 digit return code followed by a space and related message
// if the 3 digit return code is followed by "-" the it will be a multiline message
//-wait until the line with 3 digit code followed by space is delivered
if(d.indexOf("220 ")>-1){
//connected to ftp server send user name to server
s.writeUTFBytes("USER "+ftp_username+"\n");
s.flush()
}
if(d.indexOf("331 ")>-1){
//Username accepted now send password to server
s.writeUTFBytes("PASS "+ftp_password+"\n");
s.flush()
}
if (d.indexOf("230") > -1 && d.indexOf("OK.") > -1)
{
//Password accepted - lets enter passive mode and retrieve a list of files from a directory
//first enter passive mode
trace("Log in successful!");
s.writeUTFBytes("PASV \n");
s.flush();
}
var a = d.indexOf('227');
if (a > -1)
{
//Entering passive mode message will be returned along with it details of ip and port address will be returned
//-we have to connect to that address to receive the data
//format of the message will be: 227 Entering Passive Mode (209,190,85,253,148,206)
//the data inside brackets is the ip and port address, first four numbers represent IP and last 2 PORT
//the port value have to be calculated by multiplying the 5th number with 256 and adding the 6th number to it
//here in this example IP is 209.190.85.253 , PORT is (148*256)+206 = 38094
var st = d.indexOf("(",a);
var en = d.indexOf(")",a);
var str;
str = d.substring(st + 1,en);
var a2 = str.split(",");
var p1 = a2.pop();
var p2 = a2.pop();
var ip:String = a2.join(".");
var port:int=(p2*256)+(p1*1);
r.connect(ip, port);
}
if(d.indexOf("226 ")>-1){
//Data Transfer completely lets disconnect from server
if (process=='download')
{
trace("DOWNLOAD_COMPLETE");
}
if (process=='upload')
{
trace("UPLOAD_COMPLETE");
informServer();
}
dispatchEvent(new Event("dataReceived"))
}
if(d.indexOf("221 ")>-1){
//LOGGED OUT from server
}
if (d.indexOf("150 ") > -1)
{
if (process == 'upload')
{
//Once data connection is established we can start sending the data to the server
startSendingData();
}
}
}
private function onConnectHandler(evt:Event)
{
trace("CONNECTED TO FTP SERVER");
//Client has connected to ftp server
//you can also send multiple commands at same time like below or send step by step based on return code
//-!
//s.writeUTFBytes("USER username\n");
//s.writeUTFBytes("PASS password\n");
//s.flush();
}//
private function onPasvConn(evt:Event):void
{
trace("CONNECTED TO DATA PORT");
//Now send LIST command to retrieve directory listings
if (process == 'getDirList')
{
//To retrive directory listings send following command
s.writeUTFBytes("LIST "+remoteFolderStr+"\n");
}
else if (process=='download')
{
//To Download a file send following command
//RETR is the command followed by a space and path to file in remote server
s.writeUTFBytes("RETR "+remoteFolderStr+"/"+remoteFile+"\n");
}
else if (process=='upload')
{
//To Upload a file send following command
//STOR is the command followed by a space and path wher to store the file in remote server
//-with the name of the file to be saved as..you can provide any name with extension
s.writeUTFBytes("STOR /"+localFile.name+"\n");
}
s.flush();
}
private function onServData(evt:ProgressEvent):void
{
//DATA RECEIVED FROM SERVER THRO DATA PORT
var d = r.readUTFBytes(r.bytesAvailable);
if (process == 'getDirList')
{
d = r.readUTFBytes(r.bytesAvailable);
trace(d);
}
else if (process=='download')
{
//As the data connection is established start writing the data to the fileStream
fileData = new ByteArray();//temporary bytearray object to write the incoming data
r.readBytes(fileData, 0, r.bytesAvailable);//write data to the temp bytearray
fileStream.writeBytes(fileData, 0, fileData.bytesAvailable);//now write the bytearray to file stream
//instead you can directly write the data to file stream drom socket
}
}
private function onIOERR(evt:IOErrorEvent):void
{
trace(evt.errorID+":"+evt.text);
}
private function checkForStream():void
{
//this function is used to check if the incoming data is fully written to the filestream and then close the filestream
//-even if the ftp server dispatches that the file has been transfered...you application cn be still writing them to the filestream
if(!r.connected){
fileStream.close()
}else{
//if the file is still been writing restart the timer
dtimer.reset()
dtimer.start()
}
}
//
public function initUpload(fileToUpload:File):void
{
//called when upload event is triggered
localFile = fileToUpload;
if (localFile.exists)
{
// this.remoteFolderStr=remote_folder.text
startUploadProcess();
}
}
private function startUploadProcess():void
{
//create and open a fileStream
fileStream=new FileStream();
fileStream.open(localFile, FileMode.READ);
process = "upload";
fileData = new ByteArray();
//You need to pass this command 'TYPE I' to set data transfer mode as binary
s.writeUTFBytes("TYPE I\n");
s.writeUTFBytes("PASV \n");
s.flush();
}
private function startDownloadProcess():void
{
localFile = localFolder.resolvePath(remoteFile);
fileStream=new FileStream();
fileStream.open(localFile, FileMode.WRITE);
process = "download";
fileData = new ByteArray();
s.writeUTFBytes("TYPE I\n");
s.writeUTFBytes("PASV \n");
s.flush();
}
private function startSendingData():void
{
interval = setInterval(sendData,300);
}
private function sendData():void
{
//file to be uploaded is sent as binary data
if (fileStream.bytesAvailable <= 0)
{
clearInterval(interval);
r.close();
return;
}
if (fileStream.bytesAvailable < bufferSize)
{
bufferSize = fileStream.bytesAvailable;
}
var ba:ByteArray = new ByteArray();
fileStream.readBytes(ba, 0, bufferSize);
r.writeBytes(ba, 0, ba.bytesAvailable);
r.flush();
}
private function onDataReceived(evt:Event):void
{
if(process=='download'){
dtimer.start();
}
}
If anyone have this issue, i solved it by using small bufferSize, i set it to 100KB,
i found it is attempt to close the connection before all data is sent when the buffer is big.
You can add event OutputProgressEvent.OUTPUT_PROGRESS to check the number of bytes that has been written in the dataChannelConnection.

air for android - Cant upload to FTP

I'm trying to upload a simple text file to ftp, the code works on the pc.
On android the app connects successfully to the ftp but when I try to upload the file I get "2031:Error #2031: Socket Error."
Any ideas?
The code (from http://suzhiyam.wordpress.com/2011/04/) is:
import flash.events.ProgressEvent;
import flash.events.Event;
import flash.net.Socket;
import flash.events.IOErrorEvent;
import flash.errors.IOError;
import flash.filesystem.FileStream;
import flash.filesystem.File;
import flash.utils.ByteArray;
import flash.events.MouseEvent;
msg.text="Wait! Connecting to ftp server!"
//
var ftp_host:String = "*"; //FTP settings are correct in the original code...
var ftp_port:Number = 21;
var ftp_username:String = "*";
var ftp_password:String = "*";
//
//in this demo we will be manually entering the remote servers folder from which upload or download should happen
var remoteFolderStr:String;
var localFolderStr:String;
var remoteFile:String;
//Socket instance which will be used to connect to ftp server
var s = new Socket(ftp_host,ftp_port);
s.addEventListener(IOErrorEvent.IO_ERROR,onIOERR);
s.addEventListener(ProgressEvent.SOCKET_DATA, onReturnData);
s.addEventListener(Event.CONNECT, onConnectHandler);
//
//Socket instance which will be used to connect to receive data sent by ftp server
var r:Socket = new Socket();
r.addEventListener(ProgressEvent.SOCKET_DATA, onServData);
r.addEventListener(Event.CONNECT, onPasvConn);
r.addEventListener(IOErrorEvent.IO_ERROR,onIOERR);
//For every command the client sends to ftp server the server returns message with return codes
function onReturnData(evt:ProgressEvent)
{
var d = s.readUTFBytes(s.bytesAvailable);
trace(d);
//check here for complete list of return codes and their meaning
//- http://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
// the return message will have a 3 digit return code followed by a space and related message
// if the 3 digit return code is followed by "-" the it will be a multiline message
//-wait until the line with 3 digit code followed by space is delivered
if (d.indexOf("220 ") > -1)
{
msg.text="Logging in to ftp server!"
//connected to ftp server send user name to server
s.writeUTFBytes("USER "+ftp_username+"\n");
s.flush();
}
if (d.indexOf("331 ") > -1)
{
//Username accepted now send password to server
s.writeUTFBytes("PASS "+ftp_password+"\n");
s.flush();
}
if (d.indexOf("230") > -1 && d.indexOf("OK.") > -1)
{
msg.text="Log in successful!"
//Password accepted - lets enetr passive mode and retrive a list of files from a directory
//first enetr passive mode
//s.writeUTFBytes("PASV \n");
//s.flush();
}
var a = d.indexOf('227');
if (a > -1)
{
//Entering passive mode message will be returned along with it details of ip and port address will be returned
//-we have to connect to that address to receive the data
//format of the message will be: 227 Entering Passive Mode (209,190,85,253,148,206)
//the data inside brackets is the ip and port address, first four numbers represent IP and last 2 PORT
//the port value have to be calculated by multiplying the 5th number with 256 and adding the 6th number to it
//here in this example IP is 209.190.85.253 , PORT is (148*256)+206 = 38094
var st = d.indexOf("(",a);
var en = d.indexOf(")",a);
var str;
str = d.substring(st + 1,en);
var a2 = str.split(",");
var p1 = a2.pop();
var p2 = a2.pop();
var ip:String = a2.join(".");
var port:int=(p2*256)+(p1*1);
r.connect(ip, port);
}
if (d.indexOf("226 ") > -1)
{
//Data Transfer completed
//s.writeUTFBytes("QUIT \n");
//s.flush();
if (process=='download')
{
msg.text="DOWNLOAD_COMPLETE"
}
if (process=='upload')
{
msg.text="UPLOAD_COMPLETE"
}
dispatchEvent(new Event("dataReceived"))
}
if (d.indexOf("221 ") > -1)
{
//LOGGED OUT from server
}
//Response code 150 will be sent by server whenever a data connection is established after we send 'PASV' command
if (d.indexOf("150 ") > -1)
{
if (process == 'upload')
{
//Once data connection is established we can start sending the data to the server
startSendingData();
}
}
}
function onConnectHandler(evt:Event)
{
msg.text="CONNECTED TO FTP SERVER!"
trace("CONNECTED TO FTP SERVER");
//Client has connected to ftp server
}
function onPasvConn(evt:Event):void
{
trace("CONNECTED TO DATA PORT");
//s.writeUTFBytes("LIST /your/folder/path\n");
if (process=='upload')
{
//To Upload a file send following command
//STOR is the command followed by a space and path wher to store the file in remote server
//-with the name of the file to be saved as..you can provide any name with extension
s.writeUTFBytes("STOR /test.txt\n");
}
s.flush();
}
function onServData(evt:ProgressEvent):void
{
//DATA RECEIVED FROM SERVER THRO DATA PORT
}
function onIOERR(evt:IOErrorEvent)
{
trace(evt.errorID+":"+evt.text);
}
//
var process:String = "";// variable to store what action is being performed
var writeToStream:Boolean;//not used here
var localFile:File;//local file which it to be uploaded
var localFolder:File;// local folder to which the downloaded file to be stored
var interval:Number;
var bufferSize:int;
//
BTN_Upload.addEventListener(MouseEvent.CLICK,initUpload);
function initUpload(evt:MouseEvent=null):void
{
//called when upload event is triggered
startUploadProcess();
}
function startUploadProcess():void
{
process = "upload";
//You need to pass this command 'TYPE I' to set data transfer mode as binary
s.writeUTFBytes("TYPE I\n");
s.writeUTFBytes("PASV \n");
s.flush();
}
function startSendingData():void
{
var textToUpload:String = "This is a test";
bufferSize = textToUpload.length;
var ba:ByteArray = new ByteArray();
//Store the info you want to upload in ByteArray HERE
ba.writeMultiByte(textToUpload, "iso-8859-1");
r.writeBytes(ba, 0, ba.bytesAvailable);
r.flush();
}

Adobe AIR SharedObject - Android/iOS - On update not found

As the title states, my user's on iOS and Android are reporting their save data has been deleted when I push an update to the respected storefronts. The game saves and restores data properly on application load and exit. I have not changed any save information locations or package names... Just mere bug fixes, build, push.
Any clarification would be helpful, or proposed redundant data backup scheme's I should pursue to ensure the end-user experience is from henceforth not affected negatively. I would also like to understand better how I can test this as a release package is not allowed to update a market installed application.
var so:SharedObject = SharedObject.getLocal("storage");
var u:User;
if(so.data != null){
u = so.data.user;
}
trace("Loading application...");
if(u != null){
trace("LOADING SAVE DATA");
user = u;
}else{
trace("NO SAVE DATA EXISTS");
user = new User();
}
I have discovered the cause of this issue and it seems that Adobe has identified and fixed the issue as well (as of AIR 3.5). https://bugbase.adobe.com/index.cfm?event=bug&id=3347676
SharedObjects are stored within a directory named according to the SWF used by your application, so if your application is running off "myApp.swf" the SharedObject will be stored in a directory "myApp". If you change the name of this SWF (i.e. the corresponding XML build sheet configuration file for your AIR project) any subsequent builds will store their SharedObjects in a new location.
The issue described in this bug was specifically denoted for iOS, wherein the application was not storing the SharedObject in the corresponding SWF location as described above but in a separate location denoted by the "filename" attribute in your project's XML build sheet.
I have also discovered that Adobe does indeed condone the use of a SharedObject for persistent storage on a mobile platform.
I have developed a simple backup for future version save redundancy in case future updates fail to persist the SharedObject.
/** the last timestamp a deep save was completed */
private var mLastSave:Number = -1;
/**
* save the state of the globals object and all of its
* sub objects.
* #warning
* all objects must implement variables in a "public" state.
* Private variables are not saved within the persistance manager
*/
public function save():void{
var so:SharedObject = SharedObject.getLocal("storage");
so.data.user = user;
so.flush();
saveDeep();
}
/**
* Save the SharedObject to denoted mobile applicationStorageDirectory.
*/
public function saveDeep():void{
// save on first application save or after
// every 5 minutes
if(mLastSave == -1 || mLastSave < getTime() + 300000){
mLastSave = getTime();
var file:File = File.applicationStorageDirectory.resolvePath("userSave");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
var ba:ByteArray = new ByteArray();
ba.writeObject(user);
fileStream.writeBytes(ba);
fileStream.close();
}
}
/**
* Load the application from the SharedObject be default
* if the SharedObject DNE attempt to load from the
* applicationStorageDirectory, if neither exist
* create new User object
*/
public function load():void{
registerClassAlias("user", User);
// Create/read a shared-object named "userData"
var so:SharedObject = SharedObject.getLocal("storage");
var u:User;
if(so.data != null){
u = so.data.user;
}
trace("Loading application...");
if(u != null){
trace("LOADING SAVE DATA");
user = u;
}else{
trace("NO SAVE DATA EXISTS");
var file:File = File.applicationStorageDirectory.resolvePath("userSave");
if(file.exists){
trace("Found userSave backup -attempting to load");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var ba:ByteArray = new ByteArray();
fileStream.readBytes(ba);
fileStream.close();
try{
user = (ba.readObject() as User);
}catch( e : EOFError ){
trace("SharedObject did not exist, attempted userSave load, failed");
}
}else{
user = new User();
trace("created New user...");
}
}
}

Categories

Resources