How not to hate SWF libraries

I have been playing with JSFL quite a bit recently and this little known technique may save you a a lot of time while working with SWF libraries. One thing I hate about Flash is linking library assets to classes. Actually I think linking library assets to already existing Classes is not a very good programming technique. Instead I always make sure they are anonymous classes generated at compile time.

Anyway I am getting side tracked. The process in either case to do this is really, really, really tedious and on a few occasions now I have been whinging to the guys at Adobe about this and how hopeless it is. But after many years it's still just the same and lame.

You might ask why not use SWCs to manage library assets? Problem I have with SWCs is if you use them for all the assets in your project then your compile times will eventually go through the roof! This is something which your team could waste days or even weeks of time especially in longer production phases.

This said I still want a process where I can load assets from a SWF library with some kind of strict type safety and have not just rely on resolving library assets at runtime. This could allow for you to be aware that a library asset is missing before compiling.

Creating a bulletproof utility to map existing classes to your library assets would be quite difficult to setup. So instead I have written something simple (initially) which allows for you to automatically set library assets to be exported with linkage ids. This works by basically using the library name as the linkage id for an asset and iterating through selected library assets.

  1.  
  2. var packageName=prompt("Library package name","com.library.display");
  3.  
  4. var selItems = fl.getDocumentDOM().library.getSelectedItems();
  5.  
  6. for(var i =0; i<selItems.length; i++){
  7. item = selItems[i];
  8.  
  9. var className=item.name;
  10.  
  11. var sliceIndex=className.lastIndexOf("/");
  12. className.slice(sliceIndex+1,className.length);
  13.  
  14. className = className.split(" ").join("");
  15.  
  16. var dotIndex=className.lastIndexOf(".");
  17. if(dotIndex!=-1) className=className.slice(0,dotIndex);
  18.  
  19. item.linkageExportForAS = true;
  20. item.linkageExportInFirstFrame = true;
  21. item.linkageClassName = packageName+"."+className;
  22.  
  23. fl.outputPanel.trace(item.linkageClassName);
  24. }
  25.  
  26. alert("Exported complete!");
  27.  

Although this saves quite a bit of time it's still kinda annoying, I would have to copy and paste linkage ids from the woeful Flash IDE library and I would not get any intellisense from FlashBuilder or FDT.

Although we can take this same idea a bit further to accommodate better support for intellisense with library assets from a SWF library with FlashBuilder or FDT. Although it's important and maybe obvious this technique will require loading the SWF library assets into the parent applicationDomain by just using a Loader instance. Next by using JSFL you can create classes automatically based on the library items type. Here I am probably achieving this by an unintended use of the save function from the outputPanel but it allows for you to write classes and then save them into a particular folder.

  1.  
  2. fl.outputPanel.clear();
  3. fl.outputPanel.trace(templateClass);
  4. fl.outputPanel.save(saveLocation+folderPath+"LibraryLinkageReferences.as");
  5.  

I only set this JSFL up for Buttons, MovieClips and Bitmaps but this could be extended to work with other types. The JSFL to do this looks like :

  1.  
  2. var saveLocation=fl.browseForFolderURL("Save classes location");
  3. var packageName=prompt("Package name","com.library.display");
  4. var folderPath = packageName.split(".").join("/")+"/";
  5.  
  6. FLfile.createFolder(saveLocation+folderPath);
  7.  
  8. var selItems=fl.getDocumentDOM().library.getSelectedItems();
  9.  
  10. for (var i =0; i< selItems.length; i++) {
  11. item= selItems[i];
  12.  
  13. var className=item.name;
  14.  
  15. var sliceIndex=className.lastIndexOf("/");
  16. className.slice(sliceIndex+1,className.length);
  17.  
  18. className = className.split(" ").join("");
  19.  
  20. var dotIndex=className.lastIndexOf(".");
  21. if(dotIndex!=-1) className=className.slice(0,dotIndex);
  22.  
  23. item.linkageExportForAS = true;
  24. item.linkageExportInFirstFrame = true;
  25. item.linkageClassName = packageName+"."+className;
  26.  
  27. var templateClass='package '+packageName+' {
  28. classImports
  29. public class className extends baseClassName {
  30. public function className() {
  31. classConstructor
  32. }
  33. }
  34. }';
  35.  
  36. var linkageName=item.linkageClassName;
  37.  
  38. var className=item.name;
  39.  
  40. var sliceIndex=className.lastIndexOf("/");
  41. className.slice(sliceIndex+1,className.length);
  42.  
  43. className = className.split(" ").join("");
  44.  
  45. var dotIndex=className.lastIndexOf(".");
  46. if(dotIndex!=-1) className=className.slice(0,dotIndex);
  47.  
  48. className = className.substr(0, 1).toUpperCase()+className.substr(1, className.length-1);
  49.  
  50. var baseClassName=item.linkageBaseClass;
  51. var classConstructor='addChild(new (getDefinitionByName("linkageName"))());';
  52. var classImports = ' import flash.utils.getDefinitionByName;\n';
  53.  
  54. switch (item.itemType) {
  55. case "bitmap" :
  56. baseClassName="flash.display.Bitmap";
  57. classConstructor='super(new (getDefinitionByName("linkageName"))(0, 0));';
  58. break;
  59. case "movieclip" :
  60. baseClassName="flash.display.MovieClip";
  61. break;
  62. case "button" :
  63. baseClassName="flash.display.SimpleButton";
  64. break;
  65. }
  66.  
  67. classImports+=' import '+baseClassName+';';
  68.  
  69. templateClass=templateClass.replace(/className/g,className);
  70. templateClass=templateClass.replace(/classImports/g,classImports);
  71. templateClass=templateClass.replace(/classConstructor/g,classConstructor);
  72. templateClass=templateClass.replace(/baseClassName/g,baseClassName);
  73. templateClass=templateClass.replace(/linkageName/g,linkageName);
  74.  
  75. fl.outputPanel.clear();
  76. fl.outputPanel.trace(templateClass);
  77. fl.outputPanel.save(saveLocation+folderPath+className+".as");
  78. fl.outputPanel.clear();
  79. }
  80.  

Though if you don't like using this approach of creating stub classes for retrieving library assets from a SWF library then there is one last technique using JSFL which you can use whilst still having some ability to use intellisense. Like I mentioned before the most annoying part of working with SWF library assets is not having intellisense. We could then instead of creating classes as a reference to the library SWF class, automatically create a single LibraryLinkageReferences class which contains static constants which are references to the library linkage ids.

  1.  
  2. var saveLocation=fl.browseForFolderURL("Save class location");
  3. var libraryPackageName=prompt("Library package name","library");
  4. var classPackageName=prompt("Class package name","com.library.display");
  5.  
  6. var folderPath = classPackageName.split(".").join("/")+"/";
  7. var templateClass = 'package '+classPackageName+' {\n public class LibraryLinkageReference{\n';
  8.  
  9. FLfile.createFolder(saveLocation+folderPath);
  10.  
  11. var selItems =fl.getDocumentDOM().library.getSelectedItems();
  12.  
  13. for (var i =0; i< selItems.length; i++) {
  14. item= selItems[i];
  15.  
  16. var className=item.name;
  17.  
  18. var sliceIndex=className.lastIndexOf("/");
  19. className.slice(sliceIndex+1,className.length);
  20.  
  21. className = className.split(" ").join("");
  22.  
  23. var dotIndex=className.lastIndexOf(".");
  24. if(dotIndex!=-1) className=className.slice(0,dotIndex);
  25.  
  26. className = className.substr(0, 1).toUpperCase()+className.substr(1, className.length-1);
  27.  
  28. item.linkageExportForAS = true;
  29. item.linkageExportInFirstFrame = true;
  30. item.linkageClassName = libraryPackageName+"."+className;
  31.  
  32. templateClass+="public static const "+className.toUpperCase()+":String = \""+item.linkageClassName+"\";\n";
  33. }
  34.  
  35. templateClass+=' }\n}';
  36.  
  37. fl.outputPanel.clear();
  38. fl.outputPanel.trace(templateClass);
  39. fl.outputPanel.save(saveLocation+folderPath+"LibraryLinkageReferences.as");
  40.  
  41. alert("Exported complete saved to : "+saveLocation+folderPath+"LibraryLinkageReferences.as");
  42.  

Hopefully this is some food for thought or very useful. I know I find these techniques and JSFL scripts very handy :)

Setup Library Linkages
Export Library Classes
Export Library References Class


Previous post ›