Load and reload external SWF in AIR for iOS - ios

I found several info on how to load one or more external SWF files, packaged with my AIR iOS App, the actual working code is:
var myUrlRequest:URLRequest = new URLRequest(mySWF);
var myLoaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
var loader: Loader = new Loader();
loader.load(myUrlRequest, myLoaderContext);
Object(root).MK.addChild(loader)
It works on Android devices and on Windows PC, but on iOS it loads the external SWFs only the first time. In my project I have several buttons that loads an external SWF, but each button works only the first time.
Any idea? It seems very unuseful if I can't reload an SWF.

If you can't load something a second time, perhaps it would be best to simply cache it and make a point of only loading it once?

A good way to handle this would be to load the SWF files into separate movieclips the first time and then when needing to "load" them anytime after that, just show those movieclips that already have the SWF files loaded in them.

You can't load a SWF file that contains any ActionScript ByteCode (ABC) then unload it and reload it on iOS. If you attempt to do this, the runtime throws error 3764.

I had problems loading SWF's even without code a second time. The solution I found depended on whether the code was from the application area (packaged with the app) or loaded externally (either from the web or downloaded into the caches folder).
I wrote an extended post about here, if you're interested: http://www.eqsim.com/blog/?p=400
In a nutshell, here is my code for setting the path:
var moduleDirectoryPath = "/modules/";
if (externalContent == FROM_CACHE) {
moduleDirectoryPath = File.cacheDirectory.url + moduleDirectoryPath;
} else if (externalContent == FROM_WEB) {
moduleDirectoryPath = "http://our-online-content.com" + moduleDirectoryPath;
}
then here is my code for preparing the path, if the SWF is from the app area or otherwise (cache or web):
if (loadFromApp) {
path = moduleDirectoryPath + module_folder + "/" + module + "?nf="+getTimer();
} else {
path = moduleDirectoryPath + module_folder + "/" + module;
}
Finally, my loading statements:
request = new URLRequest(path);
request.cacheResponse = false;
request.useCache = false;
_lc = new LoaderContext(false, ApplicationDomain.currentDomain, null);
moduleLoader.load(request, _lc);
and now I can load SWF's and reload them (more importantly). Of course the SWF's do not have bytecode in them.

Related

How to populate Documents folder at build time

I have an NativeScript 6.8 Javascript app that downloads newer data files. I'm discovering that on iOS I cannot create files within the app folder. (At least, in release builds; in debug builds I can.) I can change my code to read data files from the Documents folder, but how can I pre-populate the Documents folder at build time with the original data files? I'd rather not copy all the data files at run time.
Or, have I misinterpreted the restriction that files cannot be created in the app folder (or subfolders) in iOS release builds?
Live-updating files on iOS is more involved than one might expect. So, yes, you need to access the live-updated files from the Documents folder, not back the files up to iCloud, and handle numerous timing conditions, such as the live-update running just before what would seem to be the initial copy of the file to the Documents folder (seems unlikely, but I've seen it happen while testing).
I've included the function I developed, below. For context, when I find a file online to be live-updated, I use an appSetting to save the file's date as a string (storing as a value loses precision).
The function isn't perfect, but for now, it gets the job done. I call this from app.js in a NativeScript 6.8 JavaScript project.
/**
* Copy files in app/files folder to Documents folder so they can be updated
*/
async function copyFilesToDocuments() {
let filesCopied = appSettings.getBoolean("copyFilesToDocuments", false);
if (!filesCopied) { // only copy files on first invocation
let filesFolder = fs.knownFolders.currentApp().getFolder("files"); // Folder object
let documentsFolder = fs.knownFolders.documents(); // Folder object
let fileEntities = await filesFolder.getEntities();
for (entity of fileEntities) {
let sourceFile = fs.File.fromPath(entity.path);
let targetFilePath = fs.path.join(documentsFolder.path, entity.name);
let targetDate = parseInt(appSettings.getString(entity.name, "0"), 10); // live-update date or 0
if (fs.Folder.exists(targetFilePath) && targetDate > global.dataDate ) { // if file has been live-updated
console.log("app.js copyFilesToDocuments: file '" + entity.name + "' skipped to avoid overwrite. ");
continue; // don't overwrite newer file
}
appSettings.remove(entity.name); // remove any live-update timestamp
let targetFile = fs.File.fromPath(targetFilePath);
let content = await sourceFile.read();
try {
await targetFile.write(content);
if (platform.isIOS) {
// Prevent file from being backed up to iCloud
// See https://stackoverflow.com/questions/58363089/using-nsurlisexcludedfrombackupkey-in-nativescript
// See https://stackoverflow.com/questions/26080120/cfurlcopyresourcepropertyforkey-failed-because-passed-url-no-scheme
NSURL.fileURLWithPath(targetFilePath).setResourceValueForKeyError(true, NSURLIsExcludedFromBackupKey);
}
// console.log("app.js copyFilesToDocuments file copied: " + entity.name);
} catch(e) {
console.warn("app.js copyFilesToDocuments error: " + e);
//TODO: app will fail at this point with some files not found :-(
} // end catch
} // end for
appSettings.setBoolean("copyFilesToDocuments", true);
} // end files not yet copied
} // end copyFilesToDocuments

SWF fonts loading in AOT mode (IOS Ad-hoc) - ApplicationDomain.hasDefinition() returns false

I have lots of SWF Fonts, which are dynamically loaded in my Desktop/Android app. In IOS, as we know, it's quite different, so I plan to package them with my app.
However, I'm trying to load and instanciate them, and I'm stuck for months now. I managed to retrieve classes' names, using SWFExplorer here http://code.google.com/p/swfexplorer/. I tried to get these names with getQualifiedDefinitionNames() but it returns null in AOT mode.
After this, I have to instanciate these classes. And that's where I'm stuck:
//SWF chargé, on enregistre les fonts grâce aux definitions récupérées
for(var i:int = 0; i < _definitionNames.length; i++)
{
trace("ApplcationDomain has " + _definitionNames[i] + " ? " + ApplicationDomain.currentDomain.hasDefinition(_definitionNames[i]));
var fontClass:Class = ApplicationDomain.currentDomain.getDefinition(_definitionNames[i]) as Class;
var font:Font = new fontClass() as Font;
if (font && font.fontName)...
It always output FALSE on my IOS device where my Android or Desktop versions output TRUE.
I tried with
ApplicationDomain.currentDomain.getDefinition() or e.currentTarget.e.currentTarget.applicationDomai.getDefintion() but didin't manage to load my fonts.
Any help would be GRANTLY appreciated, thanks :)

How to implement IndexDB in IOS

I am developing a mobile application using phonegap, Initially I have developed using WEBSQL but now I m planning to move it on INDEXDB. The problem is it does not have direct support on IOS , so on doing much R&D I came to know using IndexedDB Polyfil we can implement it on IOS too
http://blog.nparashuram.com/2012/10/indexeddb-example-on-cordova-phonegap.html
http://nparashuram.com/IndexedDBShim/
Can some please help me how to implement this as there are not enough documentation for this and I cannot figure out a any other solution / api except this
I have tested this on safari 5.1.7
Below is my code and Error Image
var request1 = indexedDB.open(dbName, 5);
request1.onsuccess = function (evt) {
db = request1.result;
var transaction = db.transaction(["AcceptedOrders"], "readwrite");
var objectStore = transaction.objectStore("AcceptedOrders");
for (var i in data) {
var request = objectStore.add(data[i]);
request.onsuccess = function (event) {
// alert("am again inserted")
// event.target.result == customerData[i].ssn;
};
}
};
request1.onerror = function (evt) {
alert("IndexedDB error: " + evt.target.errorCode);
};
Error Image
One blind guess
Maybe your dbName contains illegal characters for WebSQL database names. The polyfill doesn't translate your database names in any kind. So if you create a database called my-test, it would try to create a WebSQL database with the name my-test. This name is acceptable for an IndexedDB database, but in WebSQL you'll get in trouble because of the - character. So your database name has to match both, the IndexedDB and the WebSQL name conventions.
... otherwise use the debugger
You could set a break point onto your alert(...); line and use the debugger to look inside the evt object. This way you may get either more information about the error itself or more information to share with us.
To do so, enable the development menu in the Safari advanced settings, hit F10 and go to Developer > Start debugging JavaScript (something like that, my Safari is in a different language). Now open then "Scripts" tab in the developer window, select your script and set the break point by clicking on the line number. Reload the page and it should stop right in your error callback, where you can inspect the evt object.
If this doesn't help, you could get the non-minified version of the polyfill and try set some breakpoints around their open function to find the origin of this error.
You could try my open source library https://bitbucket.org/ytkyaw/ydn-db/wiki/Home. It works on iOS and Android.

How to cache many images(in loop) properly using forge.file.cacheURL?

I have a list of products that I download as json file from server. Each item contains a link to the image stored on server.
Now I want to be able to see the products when offline, so I store downloaded json file into forge.prefs http://docs.trigger.io/en/v1.3/modules/prefs.html and pull it out to display items on screen. It works nice but I also need to store images localy to be displayed correctly.
To achive this, I'm trying to use forge.file.cacheURL http://docs.trigger.io/en/v1.3/features/cache.html but can't handle the correct order of operations. To cache images I run the json file and for each line I call forge.file.cacheURL and store the url back to JSON item. But here is the problem as forge.file.cacheURL runs asynchronously so my loop running over the items and gathering the local images finishes and my code continues to display images(view items) but meantime the forge.file.cacheURL still gathers and caches the images because its asynchronous operation. I need somehow to detect that last item is being cached and then refresh the view on screen to use correct image urls ... or something else that will lead to what I need.
Hopefully you understand the concept. How should I handle this properly ?
Since v1.4.26 you've been able to permanently store images (see http://docs.trigger.io/en/v1.4/release-notes.html#v1-4-26), rather than just cache them. Depending on your needs, that might be a better option than forge.file.cacheURL and forge.file.isFile.
I don't follow exactly the situation you describe, but something like this will let you wait for several asynchronous things to finish before doing something:
// e.g.
var jsonCache = {
one: "http://example.com/one.jpg",
two: "http://example.com/two.jpg",
three: "http://example.com/three.jpg"
};
var cacheCount = 0;
for (var name in jsonCache) {
if (jsonCache.hasOwnProperty(name)) {
var imageURL = jsonCache[name];
cacheCount += 1;
forge.file.cacheURL(imageURL, function (file) {
forge.prefs.set(name, file, function () {
cacheCount -= 1; // race condition, but should be fine (!)
if (cacheCount <= 0) {
alert('all cached');
}
});
});
}
}

Actionscript 2.0, simple file input

I'm pretty inexperienced with actionscript, and I'm having the hardest time trying to figure out how to load variables from a file and send it to a dynamic text box.
The content of an external file, "varload.txt", is "name1=John".
Here is actionscript of my flash file:
myVars = new LoadVars();
myVars.onLoad = function(){
trace(this.name1); //prints "John" as expected
myname=this.name1;
}
myVars.sendAndLoad("varload.txt", myVars);
mytextbox.text=myname; //undefined
I'm guessing it's a scope issue, but I can't find much online about global variables in actionscript, so I'm not sure how to fix this.
How do I get mytextbox.text to equal John?
The issue is that onLoad is asynchronous (called once the file has loaded, not immediately).
You'll have to define the text within the onLoad function:
myVars = new LoadVars();
myVars.onLoad = function()
{
mytextbox.text = this.name1;
}
myVars.sendAndLoad("varload.txt", myVars);
With your code, you're trying to set the content of the text box to being data that doesn't exist / hasn't loaded yet.

Resources