Javascript <-> Flash мост
Эта статья описывает, как вызывать из Javascript методы Flash и наоборот.
Используя эти способы, javascript может получить доступ к буферу обмена ОС, хранимым объектам SharedObject, управлять flash-интерфейсами и многое другое.
Какой бы способ коммуникации мы не выбрали, для начала JS должен уметь находить объект Flash на странице.
Для того, чтобы все работало кроссбраузерно, Flash-ролик нужно вставить с использованием обоих тегов: object и embed, например так:
<object
id="BridgeMovie" width="400" height="200"
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
<param name="movie" value="bridge.swf" />
<param name="allowScriptAccess" value="sameDomain" />
<embed
src="/forum/bridge.swf"
name="BridgeMovie" align="middle"
play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
width="400" height="200" scale="exactfit"
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/go/getflashplayer">
</embed>
</object>
В этом примере существенны детали:
- Имя ролика
BridgeMovie дублируется как object.id и embed.name.
- Путь к ролику
bridge.swf дублируется в object/embed
- Параметр
allowScriptAccess="sameDomain"
- Дублируются размеры ролика
Теперь объект ролика можно получить из window["BridgeMovie"] для IE или document["BridgeMovie"] в остальных браузерах:
function getMovie() {
var M$ = navigator.appName.indexOf("Microsoft")!=-1
return (M$ ? window : document)["BridgeMovie"]
}
Далее мы разберем средства для коммуникации с этим роликом.
Самый древний, знакомый большинству флешеров способ - это вызов javascript-функции посредством getURL с протоколом javascript:
getURL('javascript:функция("параметры");');
- Работает во всех броузерах
- Flash 5 и выше
- Прост в применении
- Не возвращает результат
- Длина передаваемой строки ограничена 508 символами.
Вызов осуществляется так:
fsCommand("функция", "параметры")
Чтобы принять этот вызов, в Javascript должна быть специальная обвязка.
Редактор Macromedia Flash может генерировать ее автоматически при публикации ролика.
Для этого нужно в Publish Settings:
- Во вкладке Formats включить публикацию html-файла
- Во вкладке HTML выбрать Template: Flash with FSCommand
Генерируемый шаблон javascript-обвязки состоит из двух частей: функция обработки и дополнительного кода для IE.
Название функции имеет вид <ИмяРолика>_DoFSCommand. В нашем случае это BridgeMovie_DoFSCommand
Первый аргумент - имя вызываемой функции, второй - строка аргументов.
Простейший вариант выглядит так:
function BridgeMovie_DoFSCommand(command, args) {
// вызвать функцию command с аргументом args
window[command].call(null, args)
}
Вызов, например, функции show из Flash приведет к цепочке вызовов:
- (Flash)
fsCommand("show","something")
- (JS)
BridgeMovie_DoFSCommand("show","something")
- (JS)
show("something")
Этот код нужен только для IE под Windows, в дополнение к BridgeMovie_DoFSCommand, так как в этом браузере fsCommand вызывает не Javascript, а VBScript.
if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1
&& navigator.userAgent.indexOf("Windows") != -1) {
document.write('<script language=\"VBScript\"\>\n');
document.write('On Error Resume Next\n');
document.write('Sub BridgeMovie_FSCommand(ByVal command, ByVal args)\n');
document.write(' Call BridgeMovie_DoFSCommand(command, args)\n');
document.write('End Sub\n');
document.write('</script\>\n');
}
Здесь VBScript просто передает вызов Javascript'у.
Итак, плюсы и минусы метода fscommand:
- Flash 5 и выше
- Не работает под Mac OS
- Не возвращает результат
- Нужен дополнительный JS-код
Этот способ работает, начиная с Flash 8. В отличие от всех предыдущих способов, он не только вызывает javascript, но и передает обратно возвращаемое значение, по возможности сохраняя его тип.
import flash.external.ExternalInterface;
var result = ExternalInterface.call("func", "param1", "param2", ...);
К сожалению, начиная с Flash 8, где он впервые появился, в ExternalInterface нашли большое количество разнообразных багов. Глюки сериализации, самопроизвольное изменение передаваемых данных и т.п.
Эти ошибки поправлены в новейших версиях Flash Player, но многие продолжают использовать более старые редакции Flash 8,9.
Актуальную информацию об ошибках можно получить из google, набрав "ExternalInterface bug".
- Простота
- Возвращает результат
- Разнообразные баги, в отличие от предыдущих способов
Самый простой способ - установка переменной ролику:
getMovie().SetVariable("message","data")
Обратите внимание - именно SetVariable, не setVariable. Регистр здесь важен.
Чтобы Flash получил значение - можно проверять сообщения, например, на каждом кадре. Это около 12 раз в секунду.
Следующий код срабатывает на каждом кадре и ждет появления значения переменной message.
var message = null
_root.onEnterFrame = function() {
if (message!==null) {
_root.txtRecieve.text = message // получили сообщение
message = null
}
}
- Простота и надежность
- Кросс-браузерность, Flash 5+
- Дорога в одну сторону, не больше одного сообщения за кадр.
Применив ExternalInterface из Flash8+, можно объявить флеш-метод, который будет обрабатывать вызовы из javascript.
Формат вызова:
ExternalInterface.addCallback(функция JS, объект Flash, функция Flash);.
Например, следующий код устанавливает глобальную функцию recieveFromJS как обработчик JS-вызова sendFromJS.
import flash.external.ExternalInterface;
...
ExternalInterface.addCallback("sendFromJS", null, recieveFromJS);
function recieveFromJS(msg) {
_root.txtRecieve.text = msg;
}
В JS достаточно сделать простой вызов:
getMovie().sendFromJS(value);
- Можно тут же получить значение из Flash
- Множество багов в ExternalInterface.
Можно также использовать LocalConnection, как это сделано во Flash-Javascript Integration Kit.
Этот пример пересылает текст из верхнего JS-поля направо во Flash, из нижнего Flash-поля - налево в JS.
Вводите любой, текст и жмите кнопку для пересылки нужным методом.
// Flash Storage example
import flash.external.ExternalInterface;
ExternalInterface.addCallback("sendFromJS", null, recieveFromJS);
function recieveFromJS(msg) {
_root.txtRecieve.text = msg;
}
_root.button.onRelease = function() {
fscommand("recieveFromFlash", _root.txtSend.text);
}
_root.button2.onRelease = function() {
ExternalInterface.call("recieveFromFlash", _root.txtSend.text);
}
_root.button3.onRelease = function() {
var txt = _root.txtSend.text.split('"').join('\\"')
getURL('javascript:recieveFromFlash("'+txt+'");');
}
var message = null
_root.onEnterFrame = function() {
if (message!==null) {
_root.txtRecieve.text = message
message = null
}
}
Скачать .fla - исходник флешки.
function recieveFromFlash(Txt) {
document.getElementById('txtRecieve').value = Txt;
}
function getMovie() {
var M$ = navigator.appName.indexOf("Microsoft")!=-1
return (M$ ? window : document)["BridgeMovie"]
}
function sendSetVariable() {
var value = document.getElementById('txtSend').value
var movie = getMovie()
movie.SetVariable("message", value)
}
function sendExternalInterface() {
var value = document.getElementById('txtSend').value
var movie = getMovie()
movie.sendFromJS(value);
}
/* movie name_DoFSCommand */
function BridgeMovie_DoFSCommand(command, args) {
window[command].call(null, args)
}
// Hook for Internet Explorer.
if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
navigator.userAgent.indexOf("Windows") != -1) {
document.write('<script language=\"VBScript\"\>\n');
document.write('On Error Resume Next\n');
document.write('Sub BridgeMovie_FSCommand(ByVal command, ByVal args)\n');
document.write(' Call BridgeMovie_DoFSCommand(command, args)\n');
document.write('End Sub\n');
document.write('</script\>\n');
}
По просьбам читателей - примеры и исходники вынесены на отдельную страницу.
Успешной интеграции!
|
Здравствуйте меня интересует маленький вопросик по поводу вот Этого кода
function getMovie() { var M$ = navigator.appName.indexOf("Microsoft")!=-1 return (M$ ? window : document)["BridgeMovie"] }При Вставке Flash в форму данное обращение необрабатывается в Explorer!!!
<form name="test" id="1"> <object id="BridgeMovie" width="400" height="200" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> <param name="movie" value="bridge.swf" /> <param name="allowScriptAccess" value="sameDomain" /> <embed src="/forum/bridge.swf" name="BridgeMovie" align="middle" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" width="400" height="200" scale="exactfit" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"> </embed> </object> </form>Если у вас будет время помогите решить данную сетуацию!!!
Честно - вопрос нихрена не понял. Какое обращение не обрабатывается и что при этом выдает.
Попробуйте примеры на отдельных страницах.
Большое спасибо за такие наглядные примеры - Ваш сайт, наверное, лучший путеводитель по JS в рунете. По крайней мере, мне, гуманитарию, все понятно!
Добрый день.
Вы не могли мне подсказать:
getURL('javascript:функция("параметры");');
Не отрабатывается в последней версии флэша. Т.е. вообще не происходит ни каких событий. Вызов функции не осуществляется. Когда стояла версия 8,0,22,0 все отрабатывалось.
К примеру, на нажатие на кнопку во флэше вешаем getURL('javascript:alert('test');');
А алерт вызывался когда стояла версия 8,0,22,0. Но стоило обновить до последней, то перестал. Может ктонибудь сталкивался с подобной проблемой? Или возможно после обновления какието настройки безопасности флэша поменялись?
Заранее благодарю!
ну если так кавычки ставить, то не будет работать
если это частная опечатка, тогда не знаю..
Огромное спасибо за этот пример, уже как год хотел научиться делать такой мост. Раньше просто не получалось, потом вообще забил, а теперь умею
Big thanks
Спасибо за детальное описание. Действительно понятно даже начинающему.
Здравствуйте.
Прекрасная статья, спасибо!
одно замечание - MSIE 7.0 осуществляет доступ к объекту так же через объект document, вместо объекта window.
Странно, но на локальной машине у меня не заработал ни один из ваших способов, флэш плеер 10
Очень нужно решение и я его так и не нашел. Настройки безопасности вроде сделал...
Без информации о том, какая машина (ОС, браузер), и что именно не заработало - посоветовать ничего нельзя..
Я тоже на локальной машине (запуская HTML минуя сервер) не могу получить вызов JS, а надо именно на локальной. OS WinXP Firefox 3.08
Сам нашел ответ. При вызове плейера нужно использовать параметр 'allowScriptAccess','always'
Ты лучший. Я пару часов потратил на поиски ответа и вот он !!! Все работает и на локальном компьютере.
Здравствуйте!
Читал, что метод SetVariable не работает для OS Mac,
а ExternalInterface работает - правда ли это?
Пробовал делать пересылку из js - flash методом ExternalInterface (OS Windows XP, Flash 8, IE7) - не работает, в чем может быть дело?
Вы пишете, что Flash 8 устарел - а какие не устарели и где их можно скачать?
Было бы неплохо, если бы выложили исходник тестовой страницы целиком,
а также флэш-исходник для Flash 8.
Буду благодарен за ответы на мои вопросы.Всго хорошего
Исходники и примеры выложены, см. конец статьи. То, что Вы слышали про Mac OS, имхо не верно, но все же попросите маковода тестануть
Благодарю за ответ, однако скачал с выложенных примеров исходники bridge.fla, example2.fla - во Flash 8 они не открываются, пишет "unexpected file format" Можно ли их сохранить в Flash 8, будет ли в этом флэше работать пересылка?
Откройте их в более старшей версии флеш и сохраните в формате Flash8
интересная особенность проявилась:
у меня есть некая флешка на странице. она лежит в блоке div. у этого div'a стоит свойство visibility в значение hidden
чего я хочу:
1. флешка загрузилась
2. Внутри флешки обрабатывается команда о завершении загрузки этой флешки
3. Эта команда вызывает функцию на страничке, которая ставит visibility блока div в значение visible.
4. Флешку (и все, что в этом блоке помимо нее) видно, все радуются
что получается сейчас:
1. Флешка загрузилась
2. Событие не отработалось
Судя по тому, что функция вызывается, когда блок div имеет visibility: visible, у меня возникают подозрения, что действия флешки игнорируются из-за этого свойства (мол, не видно слой, значит и работать ему нельзя).
Вопрос, я прав в своих домыслах? Если да, то каким способом я могу вызвать из флешки метод джаваскрипта?
Добавление флешки на страницу идет через swfObject
Не знаю насчет visible, но с display:none такое видел. Если флешка не видна, то она не работает, и событие прислать не может.
Можно див з-индексом опутить под страницу, а когда понадобится - поднять
Раньше знал только как из flash вызывать функции javascript, а теперь знаю и то и то
, благодаря этой статье
Ух, теперь я напишу то что хотел
Здравствуйте, а можно ли вытащить переменную из flash без изменения swf'ки?
Например, есть готовый swf-объект на странице, из него нужно взять переменную txtField. Если честно - нужно это сделать на чужой странице:) С хтмлом могу делать что угодно, но флэшки ни местонахождение, ни параметры, ни тем более код менять нельзя. Посоветуете?
Немного не ясно что Вы имеете в виду.
Возможность считывать динамически переменную флешки либо просто добраться до хранимого в ней значения?
То есть интересует Вас контент переменной или возможность скажем подгребать ее значение тем же джаваскриптом например?
Например можно попробовать следующее:
1. Создаем новый флеш проэкт.
2. Создаем там загрузчик и загружем в него интересующую нас флешку.
3. обходим в циклах все уровни загруженной флешки и выводим все переменные и их значения. Находим нужную и путь к ней.
4. В исходном проэкте создаем функцию которая считывает конкретно нужную нам переменную в нужное время, либо подписываемся на ее изменение.
5. Выводим полученное значение в куда нам уже нужно, в тот же самый джаваскрипт.
6. Получаем новую флешку, которая все что делает это загружает в себя нужную нам, вытаскивает из нее значение переменной и отправляет его дальше.
Спасибо! Сегодня целий день в нете рисчил - один спам нашел, а здесь все четко и ясно. Thanks =)
Статья супер, но у меня очень смешная ситуация: Сделал как все сказали, вызываю js функцию через ExternalInterface, ни в одном браузере не работает... НО!!! Представьте себе работает в лисе в IE TAB (мож кто не знает это плагин к лисе такой, он отображает страницу как это делает IE), в самом IE НЕ пашет а в лисе в IE TAB пашет!!!
Че за фигня?....
если кто знает что делать, напишите плз. очень надо на: code_master@mail.ru
p.s. Спасибо за ОТЛИЧНУЮ СТАТЬЮ!!!
Виноват, извиняюсь, тестировал на локальном компе, поэтому и пахало, вылил на удаленный сервер, все заработало
СУПЕР просто! всё понятно... мне очень помогло!!!!!
Здравствуйте. Не могли бы Вы сами сохранить файл example.fla из
Демка приема-передачи через ExternalInterface
чтобы он открывался в Flash 8, т.к. у меня да и у многих пользователей, я думаю, нет возможности найти старший плеер...
Вы можете легко получить плеер самой последней версии здесь: http://get.adobe.com/flashplayer/
ExternalInterface
К сожалению, начиная с Flash 8, где он впервые появился, в ExternalInterface нашли большое количество разнообразных багов. Глюки сериализации, самопроизвольное изменение передаваемых данных и т.п.
Эти ошибки поправлены в новейших версиях Flash Player, но многие продолжают использовать более старые редакции Flash 8,9
Всвязи с этим вопрос... Здесь имеется ввиду версия самого плеера, или компилятора (ПО в котором создавался FLA, затем SWF файл)?
Имеется в виду версия самого плеера.
Огромное спасибо за статью.
Четко и в полной мере. Почаще бы такие подсказки попадались!
Огромное спасибо, просто блеск!
описанный пример работает в IE, но запустить его в OPERA не получилось. Броузер просто не видит объект. То есть не работает ссылка ни window["objectname"] ни document["objectname"]. Кто нибудь может указать в каком направлении копать?
Opera, случайно, не под Linux ?
Opera 9.51 под winXP AC 3.6.0
Материал супер , но не подскажете как изменить функцыю
function getMovie() {
var M$ = navigator.appName.indexOf("Microsoft")!=-1
return (M$ ? window : document)["BridgeMovie"]
}
чтоб она работала с неопределеным именем ролика на пример getMovie(movie);
где movie это переменая
function getMovie(movie) { var M$ = navigator.appName.indexOf("Microsoft")!=-1 return (M$ ? window : document)[movie] }?
+стопитьсот
getMovie().SetVariable("_root.message","data"); getMovie().TCallLabel('_root','kadr');позволит выполнить код в кадре "kadr" вместо того, что бы крутить
if (message!==null){ ... }
Причём кадр этот может лежать в отдельной сцене, где первы кадр содержит
stop();
а второй "kadr" - обработчик на приход данных и данные будут обработаны незамедлительно.
день добрый
можете подсказать
я вставлю невидимый флеш
из Javascript передам значение во Flash
а из флешевского callbacka вызову функцию Javascript
эта функция отработает нормально ?
А зачем так извращаться? Если флеш невидим, то какова его функция в этой цепочке? Пример из жизни можна?
Пример из жизни - процессор звуковых сигналов для вэб месенджера.
Автору статьи РЕСПЕКТ!!!
Спасибо за статью!
Однако столкнулся с одной проблемой - использую ExternalInterface, скрипт работает только в том случае, если его прописать в первом кадре. Мне это не удобно, т.к. в первых кадрах расположен загрузчик, а данные загружаются из ХМЛя посже. Точнее, мне бы хотелось прописать экшн к кнопкам внутри мувиклипов (в первом кадре я еще не знаю их путей). Как можно это решить?
АС2, инклюд в первод кадре естественно.
Столкнулся с проблемой такого характера:
Хотел сделать чтоб при просматривании видео посетитель нажимал на проиграть ролик (на flv player-е) и при этом чтоб выскакивала реклама.
Помогите как это организовать?
ребят подскажите пожалуйста, а как должен выглядеть еод для файла .swf
Подскажите, пожалуйста:
Есть флеш объект, получив задание он отправляет его на сервер, после обработки задания сервер присылает флеш-объекту результат и тот выдаёт текст с результатом. Текст можно копировать и т.п.
Как можно перехватить текст результата от сервера (или прямо из флешобъекта) чтобы оперировать им.
Извиняюсь за нубский вопрос, но как мне остановить/проиграть flash'ку с помощью javascript?
Вопрос снят.
Решение:
Воспризвести: document.getElementById(obj).Play();
Остановить: document.getElementById(obj).StopPlay();
где obj - это id контейнера, при использовании динамеческого swfobject.
Источник: http://www.belonogov.ru/wrote/texts/fscommander/
Превосходно! Великолепно) Думал придется долго искать и думать, а решение быстро нашлось, спасибо за статью)
афтор молодца!!! зачотец!!!
в 10 флеше юзаю экстернал интерфейс
багов не вижу пока. наверно в 10 уже исправлено в отличие от 8 про который афтор говорит
Отправить комментарий
Приветствуются комментарии:- Полезные.
- Дополняющие прочитанное.
- Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.Для остальных вопросов и обсуждений есть форум.