I wrote an article about communication between flex and JS. I still remember how I first studied the interaction between the two languages, and my task was almost finished, the company's realspace products have opened JS APIs, but now there are a lot of people using Flex products. They have been requesting to open a flex 3D API for the past few months, and the product has also been launched, if you are interested, you can.
The ghost file contains hands-on scripts, and you test the source code to other people in the team. When flash builderwas introduced, it was a new generation of index.template.html, and you had to modify it by yourself. Isn't it very troublesome? If you need this technology to make your own products, I suggest you take a look at the methods I have come up with, maybe it will help a lot of people!
In a large project or product, it is estimated that there will be many classes created using prototypes in the JS Code, and there are also many functions in the flex end. Our hypothetical scenario is that you are using Flex to create a project, but some functions can only be implemented through JS, So You encapsulate some functions into some JS files using Js, we hope to use the as language to call functions in JS through communication between AS and Js. The JS file has been basically written, but it is inconvenient for teams to collaborate in many places. This article is used to solve this problem.
I. design the code
First, we need to understand that the JS file is loaded into the HTML page after it is started. We can use externalinterface. call ("js method", parameter); Call js method on the flex side, we can use externalinterface. addcallback ("method name publicly available", specific implementation method); to solve the problem of calling the flex method on the JS side.
Now we need to think about: JS has many functions. Do we have to call related methods every time we call the JS function? In this way, the coupling between AS and JS is not too high, it does not conform to the design pattern, and it is very troublesome. In the same way, JS requires callback (commonly used in Event Callback). There are many methods. Do we also need to dynamically register multiple method names on the flex end? Are you not afraid of name conflicts? Therefore, such an implementation is not desirable.
In order to achieve low coupling, I set the communication between AS and js to only have two bridges. As calls to the JS function will always only call the fixed method in Js, the function of JS callback FLEX can only call the unique method dynamically created at the program initialization flex end. In this way, the communication between AS and JS will always only interact with each other through these two methods, so there will not be many problems in the past. But you must ask how to know the difference between the function of this call and that of the next call. What should I do? That is to say, you have done something on the parameter. To put it bluntly, you can use parameters to determine your behavior.
In our flex realspace product, the as call JS function uses var result: Object = externalinterface. call ("Supermap. web. util. applicationmanager. initbridgeflextojs ", object); Supermap. web. util. applicationmanager. initbridgeflextojs is a method in a file on the JS end. The only as channel to access JS, especially the object, is a key-value pair, such:
var realArgument:Array=[strServerUrl.toString()+"$String"]; var array:Object={ action:"FUNCTION", key:this.KEY, functionName:"checkPluginUpdate", isReturn:true, realArgument:realArgument };
The above array is the object I mentioned. The action in it: "function" indicates that I need to call a method, and the key (unique identifier) of the called object is this. key, the method name is checkpluginupdate, there is a returned value, the method parameter is realargument (a special array ).
In fact, these are a bit similar to JSON, which is used to transmit data. One of my custom formats is used to transmit behavior operations. You can define them yourself, anyway, the core is to judge your behavior through parameters, and the method always calls the same one. This is what you designed, but it is a bit difficult to parse!
Ii. Package JS Code
The ghost file is too troublesome. It is expected that the open personnel on the flex end will not be able to see anything about JS. They need to package the JS file into a SWC file and call the JS file in the SWC file to implement the function, it was impossible for me to hear this! However, after studying for a long time, I found that this can be achieved and has its advantages.
First, we need to know how to package JS files into SWC files, create a library project, and put all your JS files in, such:
The project I created is called Bridge, which contains all my Js files and many as files. I carefully found that there is a file next to every JS file... stream. as file, here is the focus. How can we package the JS file into SWC? flex provides a stream method, such as the above applicationmanager. JS file, we create a class applicationmanagerstream inherited from flash. utils. bytearray, the Code is as follows:
Package Supermap. JS {import flash. utils. bytearray;/*** specifies the JS file and packaging method */[embed (Source = "applicationmanager. JS ", mimetype =" application/octet-stream ")] public class applicationmanagerstream extends bytearray {public function applicationmanagerstream () {super ();}}}
To write your corresponding JS file, you must put it in a folder with the package type application/octet-stream. Each JS file is configured with a corresponding as class.
The packaged SWC file is automatically generated.
Now the problem comes again. It's binary. How can we use it? It's not the as class we usually write. Just write a method to reference this package and use it directly.
Therefore, we also need an as class. Here I create includestream. As, the Code is as follows:
Package Supermap {import Supermap. JS. applicationmanagerstream; import Supermap. JS. hashtablestream; import Supermap. JS. scenedivstream; import Supermap. lib_ajax.iserverjava6rstream; import Supermap. lib_ajax.jsstream; import Supermap. lib_ajax.microsoftajaxstream; import Supermap. lib_realspace.realspacestream;/*** this class is mainly used to obtain JS Code in binary form in string form */public class includestream {/*** constructor */Public Function includestream () {}/*** return the string form of the Code in the JS file */Public Function tostring (): String {var microsoftajaxstream: microsoftajaxstream = new microsoftajaxstream (); var jsstream: jsstream = new jsstream (); var streams: streams = new streams (); var realspacestream: realspacestream = new realspacestream (); var hashtablestream: hashtablestream = new hashtablestream (); var applicationmanagerstream: applicationmanagerstream = new applicationmanagerstream (); var scenedivstream: scenedivstream = new scenedivstream (); Return microsoftajaxstream. tostring () + jsstream. tostring () + iserverjava6rstream. tostring () + realspacestream. tostring () + hashtablestream. tostring () + applicationmanagerstream. tostring () + scenedivstream. tostring ();}}}
With this class, we can instantiate an object and use tostring () to obtain all JS Code in string form. This is another problem. We still cannot use it and cannot call it. But package it in this way and reference it to your flex project.
3. Call JS files
First of all, we need to know that as calls JS methods can only call JS methods, that is, JS embedded into the HTML page. Now we only have JavaScript source code in string form, therefore, you need to find a way to convert it into standard JS Code and embed it into the HTML page.
The code at the beginning of your flex project is as follows:
// Initialize parsestringtojs as a string to convert the string to the JS language var STR: String = "function parsestringtojs (STR) {var ohead = document. getelementsbytagname ('head '). item (0); "; STR + =" Var oscript = document. createelement (\ "script \"); "; STR + =" oscript. language = \ "javascript \"; "; STR + =" oscript. type = \ "text/JavaScript \"; "; STR + =" oscript. id = \ "test \"; "; STR + =" oscript. defer = true; "; STR + =" oscript. TEXT = STR; "; STR + =" ohead. appendchild (oscript) ;}"; // call window. eval method externalinterface. call ("eval", STR); var includestream: includestream = new includestream (); // obtain the source code var strey: String = includestream in the string format of Js. tostring (); // use the regular expression to modify the string var CHAR: Regexp = // \\/ g; strey = strey. replace (char, "\\\\"); // generate js api externalinterface. call ("parsestringtojs", strey); // initialize js to call the as entry method initbridgejstoflex. the final implementation of the method is transferred to the method applicationmanager. initbridgejstoflex externalinterface. addcallback ("initbridgejstoflex", applicationmanager. initbridgejstoflex );
The references file is added to the references file. In addition, you can use externalinterface. call directly calls the bridge exposed on the JS end and uses applicationmanager. initbridgejstoflex receives JS callback functions, so that you only need to add the SWC package to use the functions used by Js.
In fact, I don't want to use eval either. Eval is very performance-consuming. I have a source code length of more than 80 thousand. Fortunately, I didn't see a card, and I only used this method, don't beat me with bricks! If you have other solutions, tell me! Hope it will help some people!