Find name of app - actionscript-3

FlashBuilder Flex
In my reboot code, I have the following line:
var file:File = File.applicationDirectory.resolvePath("app:/playerAir.exe");
It works as long as the app's name doesn't change
I want an automated way to find this app's name to change that "playerAir".
The reasons:
If I change the name, I have to change it in the reboot function too
If a client has more than one versions of the file (playerAir.exe, playerAir1.exe, playerAir2.exe) then it'll launch the wrong one.
How could I make it so it changes accordingly to the name the app has?

The code of the reboot function is as follows:
public function Reboot():void ///
{ ///
var nativeProcessStartupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo(); ///
var app:WindowedApplication=WindowedApplication(FlexGlobals.topLevelApplication); ///
var swf:String=stage.loaderInfo.url.substring(0,stage.loaderInfo.url.lastIndexOf("/")+1); ///get swf's path (- *name*.swf)
swf=swf+app.applicationID; ///adds applicationID after the path. ex: app:/ -> becomes -> app:/m7tvPlayerAir
var d:Array = File.applicationDirectory.getDirectoryListing(); ///get all files in the directory
var exe:String; ///the executable (.exe, .app, .dmg) (multiplatform)
for each(var f:File in d){ ///checks all files in the directory
if(f.url.indexOf(swf)==0 && (f.url.indexOf(".dmg") > -1 || f.url.indexOf(".app") > -1 || f.url.indexOf(".exe") > -1)){///if any of them has the same directory and name, and has 1 of the extensions
exe=f.url; ///found the executable
break; ///stops the loop
}///end If
}///end for
trace(exe); ///
if(exe==null){ ///will just close the application if it doesn't find the file
(FlexGlobals.topLevelApplication).exit(); ///
}else{ ///if it did find a file
var file:File = File.applicationDirectory.resolvePath(exe); ///
nativeProcessStartupInfo.executable = file; ///
nativeProcessStartupInfo.workingDirectory = File.documentsDirectory; ///
var process:NativeProcess = new NativeProcess(); ///
(FlexGlobals.topLevelApplication).exit(); ///
process.start(nativeProcessStartupInfo); ///
}///end else
}///end function
(Hey this is Ohciarob, I forgot my password)

You should be able to determine the application name with the url property of the stage's loaderinfo object.
This will point to the swf file being run, which by default will be the same name as the executable.
So, if you know your app has an extension of .exe, this would likely work:
var path:String = stage.loaderInfo.url.replace(".swf",".exe");
var file:File = File.applicationDirectory.resolvePath(path);
If you are running a multi-platform app, you could walk the application directory looking for the appropriate application extension:
//get the swf path minus the 'swf'
var swf:String = stage.loaderInfo.url.substring(0,stage.loaderInfo.url.lastIndexOf(".") + 1);
//get all the files in the application directory
var d = File.applicationDirectory.getDirectoryListing();
//find your executable (this is just a sample of how to do this, ideally you'd have a compile time constant to indicate the extension of your current build)
var exe:String;
for each(var f:File in d){
if(f.url.indexOf(swf) === 0 && (f.url.indexOf(".dmg") > -1 || f.url.indexOf(".app") > -1 || f.url.indexOf(".exe") > -1)){
exe = f.url; //found the executable path
break; //stop the loop
}
}

Related

Move files from applicationStorage to Documents in app

I've got an app that, since 5 years now, that displays an offline map by reading from a folder embed in it ("assets").
Since Android 11, it's impossible to read from ApplicationStorage (Error #3001: File or directory access denied), so I'm trying to copy the folder from applicationStorage to "Documents".
What I did :
source = File.applicationDirectory.resolvePath("assets/maps");
destination = File.documentsDirectory.resolvePath("Documents/www");
source.addEventListener(Event.COMPLETE, onMapCopyComplete);
source.copyToAsync(destination, false);
function onMapCopyComplete(e: Event): void {
source.removeEventListener(Event.COMPLETE, onMapCopyComplete);
log("onMapCopyComplete()");
}
I've got a return onMapCopyComplete() but when I'm looking in InternalStorage/Documents of my phone I've got the folders but all are empty... None of the files were copy..
PrintScreen computer vs phone
To read the files, here's what I'm doing :
function startMapsView()
{
var indexFile:File = File.applicationStorageDirectory.resolvePath("www/index.html");
if (!indexFile.exists)
{
log("startMapsView() Index file not found, Please check www/index.html");
return;
}
// Create StageWebView
stageWebView = new StageWebView(isMobile); // Set to TRUE for System's NativeWebView, FALSE is for AIR's WebView
stageWebView.stage = stage;
stageWebView.viewPort = new Rectangle(0, iOSStatusBarHeight + headerBarHeight, deviceStageSize.width, deviceStageSize.height - (iOSStatusBarHeight + headerBarHeight + footerBarHeight));
stageWebView.addEventListener(flash.events.Event.COMPLETE, onStageWebViewLoaded);
stageWebView.addEventListener(flash.events.ErrorEvent.ERROR, onStageWebViewError);
stageWebView.addEventListener(LocationChangeEvent.LOCATION_CHANGING, onStageWebViewLocationChanging);
// Load Map URL
stageWebView.loadURL(mapsURL);
}
And mapsURL is define by :
function setMapsURL(doNotEnableButtons: Boolean = false): void {
var indexFile: File = File.documentsDirectory.resolvePath("Documents/www/index.html");
trace("indexFile url is = "+indexFile.url);
if (!indexFile.exists) {
log("setMapsURL() Index file not found, Please check www/index.html");
return;
}
var assetsDir: File;
if (!useOnlineMaps) {
assetsDir = new File(destination.resolvePath("index.html").nativePath);
} else {
assetsDir = new File(destination.resolvePath("onlineMaps.html").nativePath);
mySavedData.data.onlineMapChoosen = false;
}
mapsURL = assetsDir.url;
log("setMapsURL() " + mapsURL);
if (!doNotEnableButtons) enableMapButtons();
}

FileReference.save ensuring it has extension

I need to save an XML with some settings and wanted to save them as my own filetype (.genconf for example). When i use..
var f:FileReference = new FileReference();
f.save( MyByteArray);
..I can allow the user to browse to save, but it only uses an extension if they enter in manually (which they definitely wont).
Is there a way to check the filename they enter, and amend/append it before the file is written?
Here's how i did it in the end (with AIR):
//on save clicked
public function export(e:MouseEvent){
var file:File = File.desktopDirectory;
file.browseForSave("Save");
file.addEventListener(Event.SELECT, onSaveSelect);
}
public function onSaveSelect(e:Event){
//create XML stuff here
var config:XML = new XML(<config />)
// compressing before saving
var bytes:ByteArray = new ByteArray();
bytes.writeUTFBytes( config );
bytes.compress();
//get browse location
var saveFile:File = File(e.target);
var directory:String = saveFile.url;
//check if by miracle they put the extension in, then add it
if(directory.indexOf(".genconf ") == -1){
directory += ".genconf ";
}
//use the new path with the extension
var file:File = new File();
file = file.resolvePath(directory);
var fileStream:FileStream = new FileStream();
fileStream.addEventListener(Event.CLOSE, onClose);
fileStream.openAsync(file, FileMode.WRITE);
fileStream.writeBytes(bytes);
fileStream.close();
}
I think that for Flash security reason you can not force the file extension in any way, in addition the file name typed by user is a read-only information so you can not modify it.
So for your case, you want to save files with the .genconf extension, I think that you can :
Request the file name to your user, before showing the save dialog, and then add the extension to have the default file name for the save dialog.
OR
Fix the default file name with your extension using time-stamp, randomized name, ... and demand to your user to save the file directly without editing the name.
In all cases, you will get a code like this :
const extension:String = '.genconf';
var file_ref:FileReference = new FileReference()
file_ref.save('your_data', 'default_file_name' + extension);
Hope that can help.

Run an AS3 function only once

I'm making an AIR app and I would like to know if it's possible to run a function only once ?
If the user reboot his device and launch the app, the function won't be trigger again.
Thank you for your answers,
Since you're using adobe AIR, you have a few options.
Write a file that contains your save data.
Using AIR you can write a data file to the user's machine. This is more permanent than SharedObject's, which for various reasons can not work or persist long term.
You can actually serialize entire classes for easy retrieval of complex objects.
Here is an example of a class that managers a save file (for preferences or a game save etc):
package
{
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;
import flash.utils.Dictionary;
import flash.net.registerClassAlias;
public class SaveData
{
//a list of any vars you want to save.
public var firstRun:Boolean = true;
public var someVar:int = 1;
public var anotherVar:Dictionary;
//the file for the user save data
public static function getFile():File {
return File.applicationStorageDirectory.resolvePath("saveFile.data");
}
public static function loadFile():SaveData {
registerClassAlias("flash.utils.Dictionary", Dictionary); //you need to register any non-native classes you want to save
registerClassAlias("saveData", SaveData);
var data:SaveData
//check for a default save file in the application directory (optional, but sometimes it's nice to bundle a default with your application before the user saves their own data
var f:File = new File("app:/saveFile.data");
if(f.exists){
data = loadFromFile(f);
}else {
trace("Default File Doesn't Exist");
}
//check the user storage directory for a save file, and see if it's newer than the one in the application directory
var userFile:File = getFile();
if (userFile.exists) {
if (f.exists && f.modificationDate.time < userFile.modificationDate.time) {
trace("Local File is newer, load it");
data = loadFromFile(userFile);
}else {
trace("Default File is newer");
}
}else {
trace("Save File DOESN'T EXIST YET");
}
if (!data) {
//data didn't load, let's create a new save file
data = new SaveData();
saveToFile(data);
}
saveData = data; //assing to main static accessible var
return data;
}
private static function loadFromFile(f:File):SaveData {
var d:SaveData;
try{
var stream:FileStream = new FileStream();
stream.open(f, FileMode.READ);
d = stream.readObject() as SaveData;
stream.close();
trace("DATA LOADED: " + f.nativePath);
return d;
}catch (err:Error) {
trace("Error Loading Save Data: " + f.nativePath);
}
return null;
}
public static function saveToFile(saveData:SaveData):void {
var fileStream:FileStream = new FileStream();
fileStream.open(getFile(), FileMode.WRITE);
fileStream.writeObject(saveData);
fileStream.close();
}
}
}
Then to use it:
var saveData:SaveData = SaveData.loadFile();
if(saveData.firstRun){
//do you first run code
//now set first run to false
saveData.firstRun = false;
SaveData.saveFile(saveData);
}
use a SharedObject. There is another answer covering this, but since no example was given I'll give one:
var mySO:SharedObject = SharedObject.getLocal("yourAppNameHere");
if(mySO.data.hasHadFirstRun){
//the cookie exists
}else{
//the cookie hasn't indicated there has been a first run yet, so do whatever you need to do
//some code
mySO.data.hasHadFirstRun = true; //now that you've done whatever on the first run, let's save the cookie
mySO.data.flush(); //save (though it will save automatically I believe when you close the application
}
use SQLite.
AIR can create and read SQLite databases, if your application has a need to store other data that would make sense to live in a table structure, it might make sense for you to add on a table for storing user preferences and things like a first run flag - if you wouldn't use the database for anything else though, it would definitely be over-kill.
Find out more about SQLite in AIR here:
http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118666ade46-7d49.html

Zip a folder in as3 Adobe AIR

I have created an Air app that after user interaction will creat a folder with bmp's, xml and text doc's.
All works apart from making the final zip which needs to be automatic.
I have been looking for a solution to this but cant find it.
Perhaps I am just not seeing it, and if so, can someone show me please.
My original posting on this is here ---
zip many files with Air as3 flash
The closest thing I have found was this one --- zip a folder using fzip
But for some reason my coment was deleted which was --
I like this. It is the closest I have come to a working solution to my own problem. That said, I tested this and it works nicely as is. Can this script be moded to run without interaction??? I am in need of it for a program that I have written. ANY asistance is welcom........ apart from just pointing me to Adobe referance as it dose not have anything like what I need. (well that I can see or find)
So now I am re-asking the comunity.
For some reason it will work with manual selection and manual save-to, but not aotonomusly.
There must be a workround to this even if it requires another full page of script.
====================================================================
UPDATE:
For closing this off, I have finally got my solution.
You can find it here. "zip file contents have no data".
Hope that my problem can help someone in the future.
Try using the as3 commons zip library.
http://www.as3commons.org/as3-commons-zip/index.html
In order to do this you're going to need to load your directory, loop through all its contents and load each asset.
This code snippet includes a bulk loader to handle that for you.
warning
I pulled most of this code out of a project where I was doing something similar but I have not tested it as is. There may be some syntax errors!
private var zip:Zip;
zip = new Zip();
zip.addEventListener(IOErrorEvent.IO_ERROR, this.createNewZip); //creates a new zip
zip.addEventListener(Event.COMPLETE, handleZipLoaded); //loads the current zip, this is not shown here
zip.load(new URLRequest(File.applicationStorageDirectory.resolvePath("myZip.zip").url)); //path to your zip file
Method to create your new zip file
private function createNewZip(e:IOErrorEvent):void{
trace("no zip");
var stream:FileStream = new FileStream();
stream.open(File.applicationStorageDirectory.resolvePath("myZip.zip"), FileMode.WRITE);
zip.serialize(stream);
stream.close();
}
You can use this to add all items in a directory to your zip file.
private function addDirToZip():void{
var f:File = File.resolvePath("Your Dir");
//this will be called when your directory listing has loaded
f.addEventListener(FileListEvent.DIRECTORY_LISTING, handleDirLoaded);
//you can also get the dir listing inline and not use a listener
//doing it async will prevent ui lock
f.getDirectoryListingAsync();
}
Next your going to need to load all of the files
protected function handleDirLoaded(e:FileListEvent):void{
loadExternal = new Vector.<File>; //vector used to keep a handle on all files
e.target.removeEventListener(FileListEvent.DIRECTORY_LISTING, handleDirLoaded);
for(var i:int = 0 ; i < files.length ; i++){
var f:File = files[i] as File;
if(f.extension == "File Types you want"){ //you can do some file type checking here
loadExternal.push(f);
}
}
//start loading in the files
loadFile();
}
This will go through the loadExternal vector and load all files
private function loadFile():void{
currentFile = loadExternal.shift(); //returns the first item off the array
//load the file
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, handleLoaded);
l.load(new URLRequest(currentFile.url));
}
Once each item is loaded you can store it for addition into the zip
private function handleLoaded(e:Event):void{
var l:Loader = e.target.loader as Loader;
l.contentLoaderInfo.removeEventListener(Event.COMPLETE, handleLoaded);
//storing everything in a dictionary
assets[currentFile.name] = l.content;
//if we still have items to load go and do it all again
if(loadExternal.length != 0){
loadFile();
} else {
//now all files are loaded so lets add them to the zip
addAssetsToZip();
}
}
This is where all the loaded files actually get put into the zip and it is saved
private funcion addAssetsToZip():void{
for(var fileName:String in assets){
var ba:ByteArray = new ByteArray(); //going to write this to the zip
//make an object that holds the data and filename
var data:Object = {};
data.name = fileName;
data.content = assets[fileName];
ba.writeObject(data);
//write this file to the zip
zip.addFile(key, ba, false);
}
//and finally save everything out
zip.close();
var stream:FileStream = new FileStream();
stream.open(File.applicationStorageDirectory.resolvePath("myZip.zip"), FileMode.WRITE);
zip.serialize(stream);
stream.close();
}

Recursive Folder/Directory Copy with AS3 /Air

Is it possible to use pause/resume function to this??
source.copyTo( destination );
It would be great if you can send it at the earliest.
I found one solution here CookBook from Adobe
private function copyInto(directoryToCopy:File, locationCopyingTo:File):void
{
var directory:Array = directoryToCopy.getDirectoryListing();
for each (var f:File in directory)
{
if (f.isDirectory)
copyInto(f, locationCopyingTo.resolvePath(f.name));
else
f.copyTo(locationCopyingTo.resolvePath(f.name), true);
}
}
Or you could just use the File.copyTo() method:
var source:File = new File();
source.resolvePath( 'sourceFolder' );
var destination:File = new File();
destination.resolvePath( 'destinationFolder' );
source.copyTo( destination );
If the directories are large and you don't want your app to be stuck waiting for the copy, you can use copyToAsync, which will cause the source file to dispatch Event.COMPLETE when the job's done.
Here is the modified code from above if anyone wants to copy the entire directory; empty folders and all. Notice the "copyEmptyFolders" parameter to be used in the arguments.
//Recursivley copies directory.
private static function copyInto(directoryToCopy:File, locationCopyingTo:File, copyEmptyFolders:Boolean=true):void
{
var directory:Array = directoryToCopy.getDirectoryListing();
for each (var f:File in directory)
{
if (f.isDirectory)
{
// Copies a folder whether it is empty or not.
if( copyEmptyFolders ) f.copyTo(locationCopyingTo.resolvePath(f.name), true);
// Recurse thru folder.
copyInto(f, locationCopyingTo.resolvePath(f.name));
}
else
f.copyTo(locationCopyingTo.resolvePath(f.name), true);
}
}