Search Unity

[Flash] Browser JavaScript Communication Example

Discussion in 'Flash' started by catburton, May 14, 2012.

  1. catburton

    catburton

    Joined:
    Mar 29, 2011
    Posts:
    43
    This example shows how AS3 code can communicate JavaScript in the browser. This example makes use of the ExternalInterface ActionScript class.

    When run, BrowserCommunicator.TestCommunication() will register a callback that the browser JavaScript can then call. The ActionScript will then call out to the browser JavaScript, causing an alert popup to be displayed. The exposed ActionScript function will then be invoked by the JavaScript, completing the two-way communication test.


    Required JavaScript

    The following JavaScript needs to be added to the html page that serves the Unity published SWF. It creates the function which will be called from ActionScript:

    Code (csharp):
    1. <script type="text/javascript">
    2.  
    3. function calledFromActionScript()
    4. {
    5.     alert("ActionScript called Javascript function")
    6.  
    7.     var obj = swfobject.getObjectById("unityPlayer");
    8.     if (obj)
    9.     {
    10.         obj.callFromJavascript();
    11.     }
    12. }
    13.  
    14. </script>

    BrowserCommunicator.as (and matching C# class)

    Code (csharp):
    1. package
    2. {
    3.     import flash.external.ExternalInterface;
    4.     import flash.system.Security;
    5.  
    6.     public class BrowserCommunicator
    7.     {
    8.         //Exposed so that it can be called from the browser JavaScript.
    9.         public static function callFromJavascript() : void
    10.         {
    11.             trace("Javascript successfully called ActionScript function.");
    12.         }
    13.  
    14.         //Sets up an ExternalInterface callback and calls a Javascript function.
    15.         public static function TestCommunication() : void
    16.         {
    17.             if (ExternalInterface.available)
    18.             {
    19.                 try
    20.                 {
    21.                     ExternalInterface.addCallback("callFromJavascript", callFromJavascript);
    22.                 }
    23.                 catch (error:SecurityError)
    24.                 {
    25.                     trace("A SecurityError occurred: " + error.message);
    26.                 }
    27.                 catch (error:Error)
    28.                 {
    29.                     trace("An Error occurred: " + error.message);
    30.                 }
    31.  
    32.                 ExternalInterface.call('calledFromActionScript');
    33.             }
    34.             else
    35.             {
    36.                 trace("External interface not available");
    37.             }
    38.         }
    39.     }
    40. }

    C# Dummy Implementation:

    Code (csharp):
    1. [NotConverted]
    2. [NotRenamed]
    3. public class BrowserCommunicator
    4. {
    5.    [NotRenamed]
    6.    public static void TestCommunication()
    7.    {
    8.    }
    9. }

    This two-way communication test then can be run by calling BrowserCommunicator.TestCommunication().


    The usual Flash security sandbox restrictions will apply with this example. To run this locally, either host from localhost or ensure that your SWF's parent directory is added to the trusted locations for the Flash Player debugger.


    As with other documentation regarding Flash export, this example is subject to change.
     
  2. vikvin

    vikvin

    Joined:
    Feb 20, 2012
    Posts:
    7
    Thanks catburton . This worked great. But still one step is missing. How do I call the Unity API from Action Script file. For example in the below code


    Code (csharp):
    1.  
    2. public class BrowserCommunicator
    3.  
    4.     {
    5.  
    6.         //Exposed so that it can be called from the browser JavaScript.
    7.  
    8.         public static function callFromJavascript() : void
    9.  
    10.         {
    11.  
    12.             trace("Javascript successfully called ActionScript function.");
    13.            // I NEED TO CALL APPLICATION.LOADLEVEL(1);   HERE. HOW DO I DO THAT?
    14.  
    15.         }
    I need to call Application.LoadLevel(1); within the BrowserCommunicator.as file. How do I do that. I tried implementing the code in the BrowserCommunicator.cs file, but that did not work.


    Do I need to use SendMessage? If so, how do I get the UnityLoader here?


    Please help.
     
    Last edited: May 17, 2012
  3. catburton

    catburton

    Joined:
    Mar 29, 2011
    Posts:
    43
    The best way to do this would be to create some helper C#/JS code to do the level load for you. Then you can call that method from your ActionScript. Make sure you add the [NotRenamed] attribute to your functions so that they remain named the same when converted to AS3. e.g.:

    (Edit: Be sure to not use the NotConverted attribute on the HelperFunctions class, as this prevents it from being converted to AS3)

    Code (csharp):
    1.  
    2. [NotRenamed]
    3. public class HelperFunctions
    4. {
    5.     [NotRenamed]
    6.     public static void LoadLevel(int level)
    7.     {
    8.         Application.LoadLevel(level);
    9.     }
    10. }
    11.  
    Then from your AS3 you can call:

    Code (csharp):
    1.  
    2. HelperFunctions.LoadLevel(1);
    3.  

    Edit: Make sure to import the converted HelperFunctions class when you wish to use it in AS3:
    Code (csharp):
    1.  
    2. import global.HelperFunctions;
    3.  
     
    Last edited: May 18, 2012
  4. vikvin

    vikvin

    Joined:
    Feb 20, 2012
    Posts:
    7
    Cat,
    Do I need any other import statement in BrowserCommunicator.as file, so that actionscript can see the c# HelperFunctions class.

    Now I am getting an error
    col: 3 Error: Access of undefined property HelperFunctions.
    HelperFunctions.LoadLevel(1);
    ^


    I searched around, couldn't find an answer.

    Thanks for your help. Apologize for asking basic questions, I am brand new to Unity3D.


    BrowserCommunicator.as (inside ActionScript folder)
    Code (csharp):
    1.  
    2. package
    3.  
    4. {
    5.  
    6.     import com.unity.*;
    7.  
    8.     import flash.external.ExternalInterface;
    9.  
    10.     import flash.system.Security;
    11.  
    12.  
    13.     public class BrowserCommunicator
    14.  
    15.     {
    16.  
    17.         //Exposed so that it can be called from the browser JavaScript.
    18.  
    19.         public static function callFromJavascript() : void
    20.  
    21.         {
    22.  
    23.             trace("Javascript successfully called ActionScript function.");
    24.  
    25.         HelperFunctions.LoadLevel(1);
    26.  
    27.         }
    28.  
    29.  

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4.  
    5. [B]HelperFunctions.cs file[/B]
    6. [NotConverted]
    7. [NotRenamed]
    8. public class HelperFunctions{
    9.     [NotRenamed]
    10.     public static void LoadLevel(int level)
    11.     {
    12.         Application.LoadLevel(level);
    13.     }
    14. }
    15.  
    16.  
     
  5. catburton

    catburton

    Joined:
    Mar 29, 2011
    Posts:
    43
    Remove the [NotConverted] attribute from your HelperFunctions class. This attribute prevents the class from being converted to AS3, which is why it can't be found.

    Also, you're correct regarding the import statement. When your C# class is converted to AS3 it is put within the "global" package. Make sure you import the converted HelperFunctions class in your AS3 file:

    Code (csharp):
    1. import global.HelperFunctions;
    Those two changes should fix your errors. :)
     
  6. vikvin

    vikvin

    Joined:
    Feb 20, 2012
    Posts:
    7
    Cat, Thanks a bunch. It worked fine.
     
  7. northman

    northman

    Joined:
    Feb 28, 2008
    Posts:
    144
    Excuse me, I did not understand about Flash programming.
    I would like to know need I compile the .as file (BrowserCommunicator.as) to binary file and put into Unity3D folder?
    or I can just put the .as source code with Unity3D source code together, correct?

    Please give me the demo project URL, I want download it and test.
    Thanks,

    Shawn Z.
     
  8. catburton

    catburton

    Joined:
    Mar 29, 2011
    Posts:
    43
    Hi Shawn,

    You can just put the BrowserCommunicator.as file in an ActionScript folder in your Unity project.

    I don't have this one as a demo project at present, although you only need the two source files in your Unity project and the short javascript snippet added to the html page. You should be able to use them exactly as they appear in the first post.

    Cheers,
    Cat
     
  9. byocode

    byocode

    Joined:
    Jun 7, 2012
    Posts:
    7
    Hello Cat,

    Thanks for starting this post, I found it very helpful.

    I have created an external AS3 project in FlashDevelop, and then I load the Unity file similar to the method used in the Simple Loader forum. Then I also used your method (in this forum) to basically create stubs in Unity, and then over-ride the class in my external AS3 project, which works fine. I prefer this over the simple loader since my Unity code can treat my AS classes like any other Unity class.

    The problem I’m having is the following – I have created a HelperFunctions Unity class like the one above, which I want to call from my external AS project, similar to the
    Code (csharp):
    1. HelperFunctions.LoadLevel(1)
    . But in FlashDevelop I can’t use the
    Code (csharp):
    1. import global.HelperFunctions;
    because flash develop does not recognize this class.

    Note that in Flash Develop, I copied the UnityShared.swc file to the libs folder, and after adding that to my libraries the Unity files are found. But, unlike UnityShared.swc, if I try to add the SWF file I built in Unity, and add it as a library, FlashDevelop cannot see any of the global.* classes. Would you know why this is the case? Are the files in my Unity-built-swf file hidden? Flash-Develop can’t see the ‘Classes’ folder in my Unity-generated-swf file, but it can see them in UnityShared.swc.

    Since I Flash Develop fails to see my Unity SWF file, even though I have added it as a library the same way I did for UnityShared.swc, the compiler does not see the
    Code (csharp):
    1. global.HelperFunctions
    class.

    This is probably is a very simple thing I’m missing - sorry if this is a basic question.

    Thanks,
    BYO Code (and Beer too)
     
  10. catburton

    catburton

    Joined:
    Mar 29, 2011
    Posts:
    43
    If you want to call methods in your Unity published swf from a preloader, you can do so by calling sendMessage on your loaded unity content from AS3. E.g:

    Code (csharp):
    1. unityContentLoader.unityContent.sendMessage("Main Camera","SetResponder",{responder:this});
    There's a full example of how to do this in the preloader demo.
     
  11. byocode

    byocode

    Joined:
    Jun 7, 2012
    Posts:
    7
    Hi Cat,

    Thanks. I am aware of sendMessage, in fact that is how I currently communicate with Unity, and like the demo I pass the reference of the AS class to Unity, and the Unity instance back to AS.

    But I was hoping though that instead of using sendMessage I could instead make the FlashDevelop compiler aware of the Unity SWF so that when I compile in FlashDevelop it could see the AS classes generated by Unity, and hence I would be able to call them directly. Otherwise, if I use SendMessage, then, as you know, my Unity class must extend MonoBehaviour, it must be attached to a gameobject, and the performance hit of calling sendMessage would be higher than a direct call. But I suppose since I want to call Unity from a preloader, then sendMessage will have to do ;)

    Thanks again, just wondering if it was possible.
     
  12. northman

    northman

    Joined:
    Feb 28, 2008
    Posts:
    144
    Hi Cat.

    I want make a simple demo let HTML js call unity flash function with parameters.
    the screen like this:


    I use your framework, the following is my changed and plus:
    First, for the HTML:
    Code (csharp):
    1.  
    2. <script type="text/javascript">
    3. function calledFromActionScript()
    4. {
    5.     alert("ActionScript called Javascript function")
    6.     var obj = swfobject.getObjectById("unityPlayer");
    7.     if (obj)
    8.     {
    9.         obj.callCS('call from js');
    10.     }
    11. }
    12. </script>
    13.  
    and
    Code (csharp):
    1.  
    2. <input type="button" onblur="calledFromActionScript()" value="Call CS" />
    3.  
    Second, for the BrowserCommunicator.as:
    Code (csharp):
    1.  
    2. package
    3. {
    4.     import flash.external.ExternalInterface;
    5.     import flash.system.Security;
    6.     import global.iatHTML;   //my class
    7.  
    8.     public class BrowserCommunicator
    9.     {
    10.         //my function
    11.         public static function callCS(val:string): void
    12.         {
    13.             iatHTML.callCS(val);
    14.         }
    15.  
    16.         //Exposed so that it can be called from the browser JavaScript.
    17.         public static function callFromJavascript() : void
    18.  
    19.         {
    20.           // your codes.....
    21.  
    22.  
    Third, for the BrowserCommunicator.cs, I change nothing.

    The last thing is my C# class [iatHTML.cs]
    Code (csharp):
    1.  
    2. [NotRenamed]
    3. public class iatHTML : MonoBehaviour {
    4.    
    5.     private static string stat = "";
    6.     private bool available = false;
    7.    
    8.     //
    9.     private void OnGUI()
    10.     {
    11.         GUI.Box (new Rect(0, 0, Screen.width, 30), "Interactive with HTML");
    12.         if(GUI.Button (new Rect(10, 40, 100, 30), "call HTML js"))
    13.         {
    14.             //BrowserCommunicator.TestCommunication();
    15.             callJS("alert", "abc");
    16.         }
    17.         //if(stat != "")
    18.         //{
    19.             GUI.Box (new Rect(120, 40, 100, 30), "JS send:" + stat);   
    20.         //}
    21.     }
    22.    
    23.     // Use this for initialization
    24.     void Start () {
    25.         ActionScript.Import("flash.external.ExternalInterface");
    26.         available = ActionScript.Expression<bool>("ExternalInterface.available");
    27.     }
    28.    
    29.     //call HTML js function
    30.     public void callJS(string func, string parm)
    31.     {
    32.         if(available){
    33.             var functionName = func;
    34.             var arg0 = parm;
    35.             ActionScript.Statement("ExternalInterface.call({0},{1});", functionName,arg0);
    36.         }else{
    37.             Debug.Log("ExternalInterface not available");  
    38.         }
    39.     }
    40.    
    41.     //Message receiver --->[Here is the problem, why the function was not be called?]<----
    42.     [NotRenamed]
    43.     public static void callCS(string s)
    44.     {
    45.         stat = s;
    46.     }
    47.  
    In the last code I put. I do not know why my function [ callCS(string s) ] was not be called by AS.
    or maybe something wrong in my BrowserCommunicator.cs or BrowserCommunicator.as ?
    If possible, please help.

    Thanks

    Shawn Z
     
  13. catburton

    catburton

    Joined:
    Mar 29, 2011
    Posts:
    43
    Hi Shawn,

    Looking at your example, I don't think you added the ExternalInterface callback for your CallCS function (unless you missed that when pasting your code).

    If you're using the code I originally posted, you'll need to set up the callback in the TestConnection method in BrowserCommunicator.as. You can refer to how the callFromJavascript callback was set up. You'll then need to make sure this function is called in the Start method of iatHTML.

    Hope that helps,
    Cat
     
  14. catburton

    catburton

    Joined:
    Mar 29, 2011
    Posts:
    43
  15. Miyavi

    Miyavi

    Joined:
    Mar 10, 2012
    Posts:
    58
    Just asking.

    Is there any way to use the sendMessage function (or some workaround) like we did to execute a function from Unity in flash in another thread in here?

    I currently have three buttons, with tell Unity what model to show. These models are shown or hidden depending on a variable passed in a function.
    Now, I want a new flash window to pop up with the Unity content, but it seems it only works with adobe AIR projects, and not with AS3 one, so my code wouldn't work for AIR.

    So... instead of that, I make the unity content to load in a browser, but I can't send the variable to the function so the correct model loads, and there's always a defult one which loads.

    EDIT:
    Okay, just found out in this thread that sendMessage should be working. I just don't know why mine doesn't :(

    EDIT2:
    Okay, on the onGameLoaded function, I have the code which creates the buttons and this code too:
    Code (csharp):
    1. _unity_loader = loader.content as
    2. _unity_loader.setContentHost(this);
    Now, the button has a Click event associated, which has this, basically:
    Code (csharp):
    1. addChild(loader.content);      
    2. _unity_loader.sendMessage("Simulator", "SetModel", {foo:2});
    3. //navigateToURL(new URLRequest("../src/p_rotation.html"), "_blank");
    I'm using here just the flash version, although it would be the same if the "navigateToUrl" line was uncommented.

    Now, here's what happens:
    I run the project, the three buttons load.
    I click on the first button.
    Unity content starts to load up, and within seconds, shows up.
    It loads with the default model, not the one which was supposed to come from the foo variable.
    I click on the button again, and the new model loads correctly.

    So.. this leads me to think that it's not done loading until the unity content has been shown up in the screen, and therefore, it tries to send a message for the first time, with no success.

    Is there anything to delay the execution on sendMessage, until the content has been shown?

    EDIT3:

    Yeah, it's exactly what I was thinking.
    Here are the traces from FlashDevelop:
    Code (csharp):
    1. unityInitStart
    2. false <==== Just assigned a boolean to my sendMessage button, and set a trace. It returns false the first time I click it.
    3. PlayerConnection::Initialize
    4. PlayerConnection constructor
    5. Initialize engine version: 3.5.2f2
    6. MolehillGfxDevice:DirectX9 (Direct blitting)
    7. unityInitComplete
    It seems it's all due to the "addChild" function.
    I'm trying to execute it, but to leave the content invisible until I click on the button.

    EDIT4:
    Using a timer, I've managed to execute the sendMessage function after the Unity Content has been fully loaded and shown in the screen.
    Now let's see what's up if I do the same in the browser.. :s
     
    Last edited: Jul 30, 2012
  16. laurent-clave

    laurent-clave

    Joined:
    Jul 18, 2011
    Posts:
    280
    Hi,

    I upgraded your example, to send arguments and retrieve the javascript response

    BrowerCommunicator.as

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Flash;
    4.  
    5. [NotConverted]
    6. [NotRenamed]
    7. public class BrowserCommunicator {
    8.    
    9.     [NotRenamed]
    10.     public bool isDone = false;
    11.    
    12.     [NotRenamed]
    13.     public string returnedData;
    14.    
    15.     [NotRenamed]
    16.     public string currentError;
    17.    
    18.     [NotRenamed]
    19.     public void callFromUnity(string methodName, string arg){
    20.         #if UNITY_EDITOR
    21.         Debug.Log("CallFromUnity");
    22.         #endif
    23.     }
    24.    
    25. }
    26.  
    BrowserCommunicator.as

    Code (csharp):
    1.  
    2. package
    3. {
    4.     import flash.external.ExternalInterface;
    5.     import flash.system.Security;
    6.    
    7.    
    8.     public class BrowserCommunicator
    9.     {
    10.         public var isDone:Boolean=false;
    11.         public var returnedData:String;
    12.         public var currentError:String;
    13.        
    14.         public function callFromJavascript(returnedData:String) : void {
    15.            this.isDone=true;
    16.            this.returnedData = returnedData;
    17.         }
    18.  
    19.         public function callFromUnity(methodName:String, arg:String) : void{
    20.             if (ExternalInterface.available)
    21.             {
    22.                 try{
    23.                     ExternalInterface.addCallback("callFromJavascript", callFromJavascript);
    24.                 }
    25.                 catch (error : SecurityError){
    26.                     currentError = "A SecurityError occurred: " + error.message;
    27.                 }
    28.                 catch (error : Error){
    29.                     currentError = "An Error occurred: " + error.message;
    30.                 }
    31.  
    32.                 ExternalInterface.call(methodName, arg);
    33.             }else{
    34.                 currentError = "External interface not available";
    35.             }
    36.         }
    37.     }
    38. }
    39.  
    currentError recovers errors. We can still improve error handling easily.

    Main.cs in gameObject
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Main : MonoBehaviour {
    6.    
    7.     public GUIText infoText;
    8.    
    9.     IEnumerator Start(){
    10.        
    11.         BrowserCommunicator bc = new BrowserCommunicator();
    12.         // Send data
    13.         bc.callFromUnity("testMethod", "hello ! argument work");
    14.         // Wait
    15.         while(!bc.isDone)yield return null;
    16.         // Get response
    17.         infoText.text = bc.returnedData;
    18.        
    19.     }
    20.  
    21.    
    22. }
    23.  
    The js in html page

    Code (csharp):
    1.  
    2. function testMethod(arg){
    3.     var obj = swfobject.getObjectById("unityPlayer");
    4.  
    5.     if (obj){
    6.         obj.callFromJavascript("response ok ! arg = "+arg);
    7.     }
    8. }
    9.  
    Result :


    Sources
     
    Last edited: Oct 4, 2012
  17. RyuMaster

    RyuMaster

    Joined:
    Sep 13, 2010
    Posts:
    468
    I have tried using example, but I always get:

    Object doesn't support property or method 'callFromJavascript'

    error inside html. I'm using default html builded by unity. What might be the case?
     
    Last edited: Oct 13, 2012
  18. manuelv

    manuelv

    Joined:
    Feb 24, 2012
    Posts:
    14
    Ok with Unity 4.0.0b7
     
  19. mboog12

    mboog12

    Joined:
    Oct 4, 2011
    Posts:
    91
    it's excellent. muchos gracias for such a useful thread!
     
  20. FlowWolf

    FlowWolf

    Joined:
    Nov 8, 2012
    Posts:
    12
    Wow,Excellent work.I think it's very useful .With your framework,we can make web game without player downloading unity-player plugin.
    And,ask a weakly question:where should I put my ActionScript?In Editor or the published html's folder?
    Appreciate For Any God's Answer~
     
  21. laurent-clave

    laurent-clave

    Joined:
    Jul 18, 2011
    Posts:
    280
    In the editor;)
     
  22. Le-nain

    Le-nain

    Joined:
    Nov 26, 2012
    Posts:
    62
    Hi Cat,

    I'm really struggling working my way through this.
    I first made my own copy from your example, and couldn't make it work. Then I even used your example as is, and it's still not working!
    The AS to JS part works like a charm (getting the alert popup), but even when using your exact code the trace in the AS file is never being called!

    For some more context, I'm using the Flash Debug version (usual Debug.Log() from Unity are displayed in my flashlog.txt) and I already ran into the security violation and thus added my build folder to the trusted sites.

    I'm not copying my code, as I said I copied/pasted yours. for what it's worth, I placed my BrowserCommunicator.as in a ActionScript folder, and my BrowserCommunicator.cs in a Scripts folder.

    I really need to debug this soon, do you have any idea of where it comes from?

    EDIT: It appears that trying this locally on my computer was the cause of the problem. As soon as I tested it from a server, it worked. Still don't really understand why (as I handled the Security violation), but at least it does its job!
     
    Last edited: Feb 28, 2013
  23. v16Studios

    v16Studios

    Joined:
    Mar 1, 2013
    Posts:
    9
    Hi!

    Below is my implementation of a simple browser <-> flash api. This all-in-one class replicates a basic version of the ExternalCall and SendMessage systems present in the Web Player. To use attach it to a game object then make your ExternalCalls via BrowserComms rather than Application. It then doesn't matter if you build for Flash or Webplayer, ExternalCall and SendMessage should behave the same.

    The only limitation currently is that SendMessage requires a Class name as the first argument rather than a GameObject name to work (this is because, as far as I can tell at least, GameObjects don't get converted to easily callable classes in actionsctipt). Although it could probably be extended quite easily to cope with this.

    Code (csharp):
    1.  
    2. // Browser Communication Class
    3. // All-in-one class for replicating ExternalCall and SendMessage for simultaneous Flash and Webplayer Builds.
    4. //
    5. // History
    6. // v1.00 - 01/03/2013 - Initial Release.
    7. //
    8.  
    9. using UnityEngine;
    10. using System.Collections;
    11. using UnityEngine.Flash;
    12.  
    13. public class BrowserComms : MonoBehaviour {
    14.    
    15.     public static bool available = false;
    16.    
    17.     public static void ExternalCall(string method, params object[] args)
    18.     {
    19. #if UNITY_FLASH  !UNITY_EDITOR
    20.         available = ActionScript.Expression<bool>("ExternalInterface.available");
    21.         if(available){
    22.             ActionScript.Statement("var argArr:Array = new Array({0});", method);
    23.             for(int i = 0; i < args.Length; i++)
    24.             {
    25.                 ActionScript.Statement("argArr.push({0});", args[i]);
    26.             }
    27.             ActionScript.Statement("ExternalInterface.call.apply(null, argArr);");
    28.         }
    29.         else{
    30.             Debug.Log("No External Interface available.");
    31.         }
    32. #else
    33.         Application.ExternalCall(method, args);
    34. #endif
    35.     }
    36.  
    37. #if UNITY_FLASH  !UNITY_EDITOR
    38.     [NotRenamed]
    39.     public static void SendMessage( string _class, string _method, string _args)
    40.     {
    41.         ActionScript.Import("flash.utils.getDefinitionByName");
    42.         ActionScript.Statement("var classRef:Class = getDefinitionByName(\"global.\"+{0}) as Class;", _class);
    43.         ActionScript.Statement("var classInstance:* = new classRef();");
    44.         if(_args != "") {
    45.             ActionScript.Statement("classInstance[{0}+'_'+{1}+'_String']({2});", _class, _method, _args);
    46.         }
    47.         else {
    48.             ActionScript.Statement("classInstance[{0}+'_'+{1}]();", _class, _method);
    49.         }
    50.     }
    51. #endif
    52.    
    53.     void Start () {
    54. #if UNITY_FLASH  !UNITY_EDITOR
    55.         ActionScript.Import("flash.external.ExternalInterface");
    56.         available = ActionScript.Expression<bool>("ExternalInterface.available");
    57.         if(available){
    58.             ActionScript.Statement("ExternalInterface.addCallback('SendMessage', SendMessage);");
    59.         }
    60.         else{
    61.             Debug.Log("No External Interface available.");
    62.         }
    63. #endif
    64.     }
    65.  
    66. }
    67.  

    On the browser side you can grab a reference to the player object (either webplayer or flash) and then use the same SendMessage code to call SendMessage back to Unity regardless of player type. e.g (assuming u is an instance of UnityObject2 as per the default exported code):

    Code (csharp):
    1.  
    2. <script type="text/javascript">
    3.     function GetUnity() {
    4.         var uO;
    5.         uO = u.getUnity();
    6.         if (uO == null)
    7.         {
    8.             uO = swfobject.getObjectById("unityPlayer");
    9.             if(uO == undefined) { uO = null; }
    10.         }
    11.         return uO;
    12.     }
    13.  
    14.     var unity = GetUnity();
    15.     if(unity != null) {
    16.         unity.SendMessage("MyClass", "MyMethod", "args");
    17.     }
    18. </script>
    19.  
    No need for separate definitions/methods to handle browser communication for different builds :)
     
    Last edited: Mar 8, 2013
  24. Selvaya

    Selvaya

    Joined:
    Mar 15, 2013
    Posts:
    5
    Hi! I just try your method v16Studios and i get this error

    I just copy&paste to try it, and only change

    to

    it has to make reference to a javascript class in the unity processed as swf, or it has to be to a *.as file because the flash build and so on?

    I just want to do something like the old
    var objUnity;
    objUnity = GetUnity();
    objUnity.SendMessage("namegameobject", "function", "args");

    to pass some data from javascript to the unity object, but with the unityobject built in flash, and i'm a bit desperated now because it just doesn't work anyway... :(
     
  25. v16Studios

    v16Studios

    Joined:
    Mar 1, 2013
    Posts:
    9
    Hi!

    As I mentioned, the first argument in the SendMessage has to be a Class rather than a game object due to the way class names are converted to actionscript... We're kind of emulating the functionality of SendMessage by writing our own version as there isn't a Flash equivalent which automatically looks for a game object. One way to enhance the function might be to try and Find() a game object named in the first argument and then call the function on it if it returns something that isn't null, otherwise try and call the class function directly.

    Hope that helps!

    Update: Also! Don't forget to include the swfobject.js file in your webpage and initialise/register the flash object properly otherwise you won't be able to call .SendMessage() from the web page javascript in the first place... That's what your first error message could be pertaining to.
     
    Last edited: Apr 22, 2013
  26. Joe ByDesign

    Joe ByDesign

    Joined:
    Oct 13, 2005
    Posts:
    841
    Ok, have 2 BrowserCommunicator classes, 1 .cs 1 .as and set up very similar, callbacks are registered communication between Javascript<->UnityFlash is working. That's the good news.

    The problem is, we want to use SendMessage in both the .cs and .as classes…

    So for example, when a user clicks something on the html page, it sends a message to the .as file (via the callback) and a method on the .as called, and that method needs to be able to component.SendMessage to another object in Unity scene.

    Is that even possible?

    If yes, how? What is the action script syntax for component.SendMessage?

    Else, if not why not?
     
  27. RalphH

    RalphH

    Administrator

    Joined:
    Dec 22, 2011
    Posts:
    592
    Yes, that is possible. The unitycontent that you can access in the unityloader has a method; sendMessage(objectPath:String, methodName:String, value:Object):Boolean.
     
  28. Joe ByDesign

    Joe ByDesign

    Joined:
    Oct 13, 2005
    Posts:
    841
    I think you misunderstand; not referring to the loader, but the ActionScript classes that receive input from the browser (using yeah sendMessage).

    So BrowserEvent->Flash->(ActionScript)Unity class SendMessage to other Unity components.

    Same setup illustrated here: http://docs.unity3d.com/Documentation/Manual/flash-embeddingapi.html

    We hacked around it by checking Temp folder for converted classes with same SendMessage calls and then using the same reference names, but yeah seems… hacky :p
    (which, in a word, pretty much sums up UnityFlash!)
     
  29. RalphH

    RalphH

    Administrator

    Joined:
    Dec 22, 2011
    Posts:
    592
    Can you show an example of your 'hack'. I'm not exactly following what you mean by the descriptions you are posting.
     
  30. rohKan

    rohKan

    Joined:
    Sep 24, 2012
    Posts:
    8
    Hi, Northman.

    Did u finally find a solution to this problem? I am trying to cal a unity function from actionscript in the similar fashion but i get "Call to possibly undefined method MyClass_Constructor" . :( Please let me know if u have found a workaround for calling Unity functions from Actionscript.
     
  31. jGate99

    jGate99

    Joined:
    Oct 22, 2013
    Posts:
    1,945
    Hi, im having trouble understanding and implementing the JS to Unity-exported-swf communicaiton ! Can you please send me a simple project file so i know what is going on? Thanks
     
  32. payalsharma9988

    payalsharma9988

    Joined:
    Oct 31, 2013
    Posts:
    24
    Thanks catburton these scripts are doing work properly :)
     
  33. nicepainkiller

    nicepainkiller

    Joined:
    Feb 28, 2014
    Posts:
    4
    hi. rohKan ,I met the same problem with you. Your problem is finally solved? You can share your code? My e-mail: 275727971@qq.com

    Thanks,
     
  34. masha_mustakim

    masha_mustakim

    Joined:
    May 21, 2014
    Posts:
    6
    Hi,

    I downloaded two projects uploaded here and compiled them. But, none is working. Please help! I am using unity 4.3.4