Problem accessing ExternalInterface exposed method in Google Chrome
Asked Answered
L

5

6

My simple ActionScript I am trying to use Flash's ExternalInterface to setup a callback so that JavaScript can call a method on my Flash object. Everything works fine in Safari, Firefox and in IE, but I cannot get Chrome working. When I try the code on Chrome, I get the following error:

Uncaught TypeError: Object #<an HTMLObjectElement> has no method 'setText'

Here is the example HTML I am using (again, works fine in Safari, FF and IE)

<html><body>
<div id="mycontent"></div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("http://invincible.dynalias.com:8080/HelloWorld.swf", "mycontent", "400", "420", "9.0.0","expressInstall.swf", {}, {allowScriptAccess:'always'},{id:'hw',name:'hw'});

function getFlash(movieName) {
   return ( navigator.appName.indexOf("Microsoft") != -1) ? window[movieName] : document.getElementById(movieName);
}
</script><p>
  <input type="text" id="exampleText" /> <input type="button" value="Set Text" onclick="getFlash('hw').setText(document.getElementById('exampleText')
.value)" />
</body>
</html>

and here is the ActionScript...

package {
  import flash.display.Sprite;
  import flash.text.TextField;
  import flash.external.ExternalInterface;
  import flash.system.Security;

  public class HelloWorld extends Sprite {

    private var textField:TextField = new TextField();
    public function HelloWorld() {
      Security.allowDomain("*");
      ExternalInterface.addCallback("setText", this.setText);
      textField.text = "Hello, world!";
      addChild(textField);
    }   
    public function setText(text:String):void {
      this.textField.text = text;
    }   
  }
}
Lim answered 17/9, 2009 at 4:36 Comment(6)
Unrelated to your problem, but you should really remove that nasty navigator sniff.Bernadine
Actually, Chrome on my Mac doesn't throw any errors (and seems to set text properly)Bernadine
Your right, it frustratingly works for me on Chromium on my Mac as well. Just not Chrome on WindowsLim
I know it's been a while, but I still have the same problem in Chrome on Windows and I came accross this article. Did you come up with a solution for this?Aposiopesis
No, no one ever came up with a solution.Lim
@Mathias, @rob di marco - i just did! i really don't believe this is anything to do with Chrome at all. I guarantee if you have a large SWF file and a slow network connection you'll see this problem on any browser. see my answerDiannadianne
O
3

I got the same problem, to fire and recieve listener events between javascript and flash.

The solution was to use AC_OETags.js file from Adobe as embedd script instead of JQuery flash. (It is found in the zip file under Client Side detection, Adobe probably have it some other places as well)

The trouble based on a race condition when the flash builds the javascript callbacks in the browser. This is not handeled correctly by a straight embed for some reason.

<div>
<script>
// Major version of Flash required
var requiredMajorVersion = 10;
// Minor version of Flash required
var requiredMinorVersion = 0;

var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
AC_FL_RunContent(
"src", "tagflash",
    "width", "200",
    "height", "200",
    "id", "myTagFlash",
    "quality", "high",
    "bgcolor", "#FFFFFF",
    "name", "myTagFlash",
    "allowScriptAccess","always",
    "type", "application/x-shockwave-flash",
    "pluginspage", "http://www.adobe.com/go/getflashplayer",
    "flashvars", "templateData=theYear:2010&theTagNumber:123"
);
</script>
</div>

Then you can do: (works in IE, FF, Safari, Crome,++)

$("#tagFlash").gotoNewFrame();
Orometer answered 18/4, 2011 at 10:51 Comment(2)
I am sorry, could you please elaborate? You are giving it a src="tagflash", then id and name of "myTagFlash", but in the end you end up calling it via id of "tagFlash" (capital F). You meant to type $("#myTagFlash").gotoNewFrame();, right?Dianthus
"allowScriptAccess","always" NOT "allowScriptAccess","allways"Abundant
D
13

I agree with Robson that it is a race condition, but it's not in 'writing the Flash tag' and adding a timer is not a good solution - in fact its very dangerous.

The problem is that the SWF itself isn't loaded and had a chance to initialize your external interface. For a small SWF in Chrome the timing may be more sensitive than other browers, but the underlying problem isn't specific to Chrome.

What you need to do is this :

In Actionscript

Call this function from your constructor :

public function InitializeExternalInterface():void 
{   
      if (ExternalInterface.available) {

           // register actionscript functions so they can be called by JS   
           ExternalInterface.addCallback("activate", activate);
           Security.allowDomain("www.example.com");     

           // send message to parent page that SWF is loaded and interface active
           trace("External Interface Initialized...");
           ExternalInterface.call("flashInitialized")
      }
      else 
      {
          trace("ERROR: External Interface COULD NOT BE Initialized...");
      } 
}

In your HTML

 <script>

     function flashInitialized() 
     {
         alert("Initialized!");      // remove this obviously!
         $('#Main')[0].activate();   // safe to call Flash now
     }

 </script>

You may find on your local machine that it works without this, but as soon as you add network delays into the equation you'll regret not doing this. An arbitrary timer is a bad idea because you will still get the error on a slow connection. This method lets the page call the flash object at the earliest possible time.


Note: Using jQuery's 'on ready' pattern is NOT a solution to the problem - although at first I mistook it for one.

$(function() 
{
   $('#animation')[0].SetTitle("Hello"); 
} 

Also swfobject's callbackFn is also not a solution becasue that just tells you when the tag is inserted and not when the SWF is loaded.

Diannadianne answered 14/3, 2011 at 2:30 Comment(5)
thanks for the solution even after all this time. After a while i realized that it was not a Chrome specific problem but rather trying to rush the callback just as you mentioned. Thanks for the solution too.Aposiopesis
Hi Simmon, what does this mean $('#Main')[0].activate();? Where is #Main?Lampe
activate() is just the name of the function in the flash movie that has been exposed with ExternalInterface (there is a function activate() not shown here), and Main is the ID of the swf as create by swfobjectDiannadianne
Timers may be a better solution if set up correctly via the ready function. For example, if for some reason Flash is instantiated before the JavaScript functions, then your flashInitialized call will fail. What I do is have a timer on both sides that periodically checks whether the other side is ready, since both sides may have time-consuming initialization routines. Once both sides are ready (i.e. Flash knows that JavaScript knows that Flash is ready), then the communication is allowed.Lalapalooza
I'm using a Flash/JavaScript bridge so Flash can use the browser implementation of WebSockets. The JavaScript must initialize a socket connection manager class before Flash can use it. So by instantiating the JS manager class, then assigning a timer in document ready that checks whether flash's external interface method callback has been added, it can actually notify flash that it's ready and it knows Flash is ready. Flash can then proceed without issues.Lalapalooza
G
3

I was having problems with ExternalInterface and Firefox and Chrome and discovered that the Adobe Script was not writing the Flash tag quickly enough, so when the browser tried to find the addCallback() function it was not there at the time.

Simply putting my Javascript function that calls the Flash created addCallback() in a window.setTimeout() calling solves the problem. Delays less than 200 ms still make the problem to occur.

I didn’t have to use the solution of trying to find if the “length” attribute exists in the document[FlashId] object. Just calling “FlashEmbed = document[FlashId]” worked just fine.

Guilder answered 8/12, 2009 at 14:58 Comment(3)
Interesting, I'll have to try thatLim
sorry @Robson - but this is not a good idea. The race condition is due to the SWF object not being loaded and run and not the tag itself not being written. It could take 10 seconds on a slow connection for a SWF to download and you may never see the problem on your local machine becaues you won't have such network delays. Please see my answer for the best way (I've found) to call Flash at the earliest possible time.Diannadianne
I think we should put a repeat timer in Flash to check if JavaScript is ready or not.Lampe
O
3

I got the same problem, to fire and recieve listener events between javascript and flash.

The solution was to use AC_OETags.js file from Adobe as embedd script instead of JQuery flash. (It is found in the zip file under Client Side detection, Adobe probably have it some other places as well)

The trouble based on a race condition when the flash builds the javascript callbacks in the browser. This is not handeled correctly by a straight embed for some reason.

<div>
<script>
// Major version of Flash required
var requiredMajorVersion = 10;
// Minor version of Flash required
var requiredMinorVersion = 0;

var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion, requiredRevision);
AC_FL_RunContent(
"src", "tagflash",
    "width", "200",
    "height", "200",
    "id", "myTagFlash",
    "quality", "high",
    "bgcolor", "#FFFFFF",
    "name", "myTagFlash",
    "allowScriptAccess","always",
    "type", "application/x-shockwave-flash",
    "pluginspage", "http://www.adobe.com/go/getflashplayer",
    "flashvars", "templateData=theYear:2010&theTagNumber:123"
);
</script>
</div>

Then you can do: (works in IE, FF, Safari, Crome,++)

$("#tagFlash").gotoNewFrame();
Orometer answered 18/4, 2011 at 10:51 Comment(2)
I am sorry, could you please elaborate? You are giving it a src="tagflash", then id and name of "myTagFlash", but in the end you end up calling it via id of "tagFlash" (capital F). You meant to type $("#myTagFlash").gotoNewFrame();, right?Dianthus
"allowScriptAccess","always" NOT "allowScriptAccess","allways"Abundant
L
0

After struggling a lot, I finally decided to use the official solution from Adobe:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html

Search for ExternalInterfaceExample.as.

Lampe answered 24/1, 2012 at 21:55 Comment(0)
T
0

There is a workaround to the problem by disabling Chrome built-in flash plugin:

  1. type the chrome://plugins in the address bar of chrome.
  2. expand the details of plugins by clicking the details on top right corner.
  3. in the entry of "Adobe Flash Player", disabling the first one.

This is not a solution, but shows why this happens on Chrome. Chrome accompany with a built-in flash plugins, that often cause the troubles when we use the ExternalInterface of AS3, it's annoying.

Twill answered 15/8, 2013 at 8:56 Comment(1)
Sometimes, the builtin plugins works. But after Chrome upgraded to new version(such as ver 28),the built-in plugin breaks the ExternalInterface callsTwill

© 2022 - 2024 — McMap. All rights reserved.