适用于无控件播放器的 ActionScript 3.0 封装容器

本文由外部开发者撰写并提交。YouTube API 和工具团队感谢 Matthew Richmond 抽出宝贵时间并提供专业知识。


Matthew Richmond, The Chopping Block, Inc.
2008 年 10 月

简介

在本文中,我将介绍并简要概述适用于无 Chrome 的 YouTube 播放器的可靠 ActionScript 3.0 封装容器。该封装器使用 ActionScript 的 ExternalInterface 类和 YouTube 的 JavaScript API。

借助 Google 的 YouTube 播放器工具和无 Chrome 播放器,设计师/开发者可以快速轻松地将 YouTube 的强大功能集成到其在线项目中。这种方法非常适合采用固定预算、不允许托管视频的小型项目,也适用于希望在不脱离 YouTube 受众群体的情况下获得自定义最终用户体验的客户的大型项目。

ActionScript 3.0 封装容器屏幕截图
图 1:ActionScript 3.0 封装容器屏幕截图

YouTube 的 Flash API 和嵌入式播放器是采用 ActionScript 2.0 编写的,能够很好地与 ActionScript 2.0 配合使用;但是,如果您的项目是 ActionScript 3.0,那么无缝集成就会变得有点复杂。虽然可以轻松将 ActionScript 2.0 播放器加载到 ActionScript 3.0 swf 中,但您无法直接与加载的播放器通信或将任何函数调用传入加载的播放器。由于来自 YouTube 服务器的 swf 文件会将视频加载到自身中,因此情况会更加复杂。我们的封装容器需要完全了解这一事实并做出相应反应。幸运的是,ActionScript 语言包含两种合理的解决方法,即 LocalConnection 类或 ExternalInterface 类,用于重新连接这些嵌套但断开连接的部分。本演示将重点介绍后者,因为 ExternalInterface 可与详实的 JavaScript API 无缝配合使用,因此可与 XHTML 网页中的其他任何内容完美配合。

重要资源

在开始之前,以下列出了您可以使用的相关资源和文件。下方链接中详细介绍了本文中讨论的许多主题。

深入探究

封装容器演示概览

ActionScript 类文件
图 3:JavaScript 文件
ActionScript 类文件
图 2:ActionScript 类文件

ActionScript 3.0 封装容器实质上由两个相互连接的部分组成:一个是位于 src/choppingblock/video/ 中的 ActionScript 3.0 类文件(图 2),另一个是“youTubeLoader.js”位于 deploy/_assets/js/ 中的 JavaScript 文件(图 3)。您的 Flash/Flex 源文件会创建 YouTubeLoader ActionScript 类的实例;您的 XHTML 网页会嵌入该 Flash 文件,并使用 youTubeLoader JavaScript 文件中的函数注册该文件。请务必了解,从此时起,YouTubeLoader 在 Flash 文件中执行的所有操作都将通过 JavaScript 函数进行控制。

由于 Flash 中的所有功能均通过 JavaScript API 控制,因此您将无法在 Flash 的“Test Movie”(测试影片)播放器中加载任何 YouTube 内容。只有在嵌入 XHTML 网页并正确连接到 youTubeLoader JavaScript 函数时,它才能正常工作。

注意:如需测试任何此类调用,您必须让文件在 Web 服务器上运行,或者修改 Flash Player 的安全设置,因为 Flash Player 会限制本地文件与互联网之间的调用。

创建 YouTubeLoader 对象

在 Flash/Flex 项目中创建 YouTubeLoader 对象的实例之前,您必须先确保所需文件的软件包(文件夹)与项目位于同一目录中(如图 2 所示),或使用项目的类路径进行定义。然后,您可以导入软件包文件:

import choppingblock.video.*;

这样,您的 ActionScript 文件就可以访问“YouTubeLoader.as”和“YouTubeLoaderEvent.as”类。现在,您可以创建 YouTubeLoader 类的实例和必要的事件监听器了:

import choppingblock.video.*;

public class YouTubeDemo extends Sprite {

  private var _youTubeLoader:YouTubeLoader;	
  
  // ------------------------------------
  // CONSTRUCTOR
  // ------------------------------------
  
  public function YouTubeDemo () {
    
    // create YouTubeLoader object
    _youTubeLoader = new YouTubeLoader();
    
    // add event listener to call youTubePlayerLoadedHandler method on load
    _youTubeLoader.addEventListener(YouTubeLoaderEvent.LOADED, youTubePlayerLoadedHandler);
    
    // create the actual loader 
    _youTubeLoader.create();
    
    // add object to the display stack
    addChild(_youTubeLoader);
  };
  
  // ------------------------------------
  // EVENT METHODS
  // ------------------------------------
  
  /**
  Called via player loaded event, lets you know you are all clear to send player commands.
  */
  private function youTubePlayerLoadedHandler (event:YouTubeLoaderEvent):void{
    //trace("YouTubeDemo: youTubePlayerLoadedHandler");
    
    // you are now clear to start making calls to the YouTubeLoader object
  };
};

现在,如果 JavaScript 文件已就绪并正确连接,系统应该会成功调用 youTubePlayerLoadedHandler,然后就可以开始发出请求了。

嵌入 swf 并连接 youTubeLoader JavaScript

只有将 swf 文件嵌入到 XHTML 文件并连接到 youTubeLoader JavaScript 后,您才能成功加载 YouTube 内容。我们建议使用 SWFObject 来嵌入可通过 JavaScript API 访问的所有播放器。这样,您就可以检测最终用户的 Flash Player 版本(JavaScript API 需要 Flash Player 8 或更高版本),还可以消除使用 Internet Explorer 查看播放器时显示的“点击以启用此控件”框。

在 XHTML 文件的 <head> 部分中,将 swfobject 和 youTubeLoader 文件连接起来:

<script type="text/javascript" src="_assets/js/swfobject.js"></script>
<script type="text/javascript" src="_assets/js/youTubeLoader.js"></script>

请参见下面的示例,了解如何在启用了 JavaScript API 的情况下使用 SWFObject 嵌入您的 ActionScript 3.0 swf,然后将对 Action 的引用传递到 youTubeLoader JavaScript API。

<script type="text/javascript">

  var flashvars = {};
  var params = {
    menu: "false",
    allowScriptAccess: "always",
    scale: "noscale"
  };
  var attributes = {
    id: "youtubewrapper"
  };

  swfobject.embedSWF("YouTubeIntegrationDemo.swf", "flashcontent", "960", "500", "9.0.0", "_assets/swf/expressInstall.swf", flashvars, params, attributes);
  
  //init the youTubeLoader JavaScript methods
  SWFID = "youtubewrapper"
    
</script>

由于 Chromeless Player 与 XHTML 网页托管在不同的网域上,因此需要使用代码中的 allowScriptAccess 参数,才能让播放器 SWF 在对应的 HTML 网页上调用函数。

我们传入的唯一属性是嵌入对象的 ID,在本例中为 youtubewrapper。youTubeLoader.js 文件将使用此 ID 通过 getElementById() 获取对播放器的引用。

swfobject.embedSWF 将会从 YouTube 加载该播放器,并将其嵌入你的页面。

swfobject.embedSWF(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj)

  • swfUrlStr - 这是 SWF 的网址。请注意,我们已将 enablejsapiplayerapiid 参数附加到常规 YouTube SWF 网址,以启用 JavaScript API 调用。
  • replaceElemIdStr - 这是要替换为嵌入内容的 HTML DIV ID。在上面的示例中,它是 ytapiplayer
  • widthStr - 播放器的宽度。
  • heightStr - 播放器的高度。
  • swfVersionStr - 用户查看内容所需的最低版本。在此示例中,需要使用版本8或更高版本。如果用户的版本低于 8,则会在 HTML DIV 中看到默认的一行文本。
  • xiSwfUrlStr -(可选)指定快速安装 SWF 的网址。此示例中未使用。
  • flashVarsObj -(可选)以“名称:值”对的形式指定 FlashVar。此示例中未使用。
  • parObj -(可选)嵌入对象的参数。在本例中,我们设置了 allowScriptAccess
  • AttObj -(可选)嵌入对象的属性。在本例中,我们将 ID 设置为 myytplayer

请参阅SWFObject文档,了解进一步的说明。

SWFID ≡ 将存储对嵌入对象 ID 的引用,以供 JavaScript API 使用。您使用的嵌入对象 ID 必须与您为 csv 文件提供的嵌入对象 ID 相同。

SWFID ≡ "youtubewrapper"

此时,您应该能够成功测试您的项目。YouTubeLoader 对象应加载无 Chrome 播放器,并且应成功调用 YouTubeLoaderEvent.LOADED 事件处理脚本。现在,我们可以发出视频请求并与 YouTubeLoader 对象互动了。

与玩家互动

由于为 Chromeless Player 创建 ActionScript 3.0 封装容器的方法采用了 ActionScript 的 ExternalInterface 类,因此我们现在可以使用YouTube JavaScript Player API中的任何操作来控制已加载的播放器。如果您在“youTubeLoader.js”位于 deploy/_assets/js/ 的 JavaScript 文件(图 3)中,您会发现其中包含了大部分可用的函数。每个运算函数都会先与 checkObj 函数进行检查,以验证 SWFID 变量是否已正确设置,然后再执行。

//------------------------------------
// UTILITY METHODS
//------------------------------------

function checkObj () {
  // alert("youTubeLoader.js : checkObj");
  if (SWFID) {
    createObj();
    return true;
  } else{
    alert("YouTubeLoader: In order to call methods within a swf, you must first set the variable \"SWFID\"!");
    return false;
  };
}
  
//------------------------------------
// YOUTUBE METHODS
//------------------------------------

function loadVideoById(id, startSeconds) {
  // alert("youTubeLoader.js : loadVideoById");
  if (checkObj()) {
    obj.loadVideoById(id,startSeconds);
  };
};

function cueNewVideo(id, startSeconds) {
  // alert("youTubeLoader.js : loadVideoById");
  if (checkObj()) {
    obj.cueVideoById(id, startSeconds);
  }
}

function clearVideo() {
  // alert("youTubeLoader.js : clearVideo");
  if (checkObj()) {
    obj.clearVideo();
  }
}

// plus 17 more...

鉴于适用于无 Chrome 播放器的 ActionScript 3.0 封装容器的最终目标是从 ActionScript 3.0 Flash/Flex 项目中与 YouTube API 进行无缝互动,因此我们向位于 src/choppingblock/video/ 中的“YouTubeLoader.as”类文件添加了完全相同的公共方法(图 2)。这意味着,您可以直接对 Flash/Flex 中的 YouTubeLoader 对象调用完全相同的操作。如果您查看类文件,会发现:

// ------------------------------------
// YOUTUBE METHODS
// ------------------------------------

public function loadVideoById (id:String, startSeconds:Number = 0):void{
  //trace("YouTubeLoader: loadVideoById");
  ExternalInterface.call("loadVideoById", id, startSeconds);
};

public function cueNewVideo (id:String, startSeconds:Number = 0):void{
  //trace("YouTubeLoader: cueNewVideo");
  ExternalInterface.call("cueNewVideo", id, startSeconds);
};

public function clearVideo ():void{
  //trace("YouTubeLoader: clearVideo");
  ExternalInterface.call("clearVideo");
};

// plus 17 more...

ActionScript 方法使用 ExternalInterface 类来简单地调用 JavaScript API 中的相应函数。

请求视频

现在,您可以使用播放器引用调用函数,从 ActionScript 3.0 文件中请求视频。例如,如果您想在用户点击按钮时播放视频,请向按钮中添加 MouseEvent.CLICK 事件监听器。示例如下:

// assuming your button was called 'myButton'
myButton.addEventListener(MouseEvent.CLICK, youtubeLoadVideoHandler);

然后创建一个事件处理脚本方法来处理请求。示例如下:

private function youtubeLoadVideoHandler (event:MouseEvent):void{
  
  // assuming that '_youTubeLoader' is a reference to your YouTubeLoader object
  _youTubeLoader.loadVideoById( "u1zgFlCw8Aw" );
};

您可以选择在 Flash/Flex 文件外直接调用相应的 JavaScript 函数来请求视频。示例如下:

 <a href="javascript:loadVideoById('u1zgFlCw8Aw')">Play</a> 

发出其他调用

其他调用的工作原理与请求视频完全相同;在 ActionScript 3 中,您只需使用播放器引用调用方法即可。下面提供了可用方法的完整列表。

订阅事件

在播放器的引用中添加事件监听器可订阅事件。例如,如需在播放器状态发生变化时接收通知,请为 YouTubeLoaderEvent.STATE_CHANGE 添加事件监听器。示例如下:

// assuming that '_youTubeLoader' is a reference to your YouTubeLoader object
_youTubeLoader.addEventListener(YouTubeLoaderEvent.STATE_CHANGE, youTubePlayerStateChangeHandler);

并创建一个事件处理脚本方法来处理请求。示例如下:


private function youTubePlayerStateChangeHandler (event:YouTubeLoaderEvent):void{
  //trace("YouTubeIntegrationDemo: youTubePlayerStateChangeHandler");
  
  _stateField.text = event.state;
};

可用的操作

要调用 YouTubePlayer API 方法,您必须先在 ActionScript 文件中创建 YouTubePlayer 类的实例,并存储对要控制的 YouTubePlayer 对象的引用。这可以通过调用以下内容来实现:

var _youTubeLoader:YouTubeLoader;
_youTubeLoader = new YouTubeLoader();

公共方法

player.loadVideoById(id:String, startSeconds:Number = 0):void
根据指定 ID 加载和播放视频。
player.cueNewVideo(id:String, startSeconds:Number = 0):void
根据指定 ID 加载,但不自动播放视频。
player.clearVideo():void
清除当前已插入/已加载的视频。
player.setSize(w:Number, h:Number):void
设置 YouTubePlayer 实例的大小。
player.play():void
播放当前已插入/已加载的视频。
player.pause():void
暂停当前已插入/已加载的视频。
player.stop():void
停止当前已插入/已加载的视频。
player.seekTo(seconds:Number):void
跳转到当前已提示/加载的视频中的指定时间。
player.getPlayerState():String
返回当前已插入/已加载的视频的当前状态。
player.getBytesLoaded():Number
返回当前已插入/已加载的视频的当前已加载字节数的值。
player.getBytesTotal():Number
返回当前已提示/加载的视频的已加载字节总数的值。
player.getCurrentTime():Number
返回当前已插入/已加载的视频的当前位置。
player.getDuration():Number
返回当前已提示/加载的视频的当前时长。
player.getStartBytes():Number
返回当前已插入/已加载的视频的起始字节。
player.setVolume(newVolume:Number):void
设置当前已提示/加载的视频的音量。
player.getVolume():Number
返回当前已插入/已加载视频的当前音量。
player.mute():void
存储当前音量,并将当前已提示/加载的视频的音量更改为 0。
player.unmute():void
在静音时,将当前已提示/加载的视频的音量返回到上次存储的值。
player.getEmbedCode():String
返回当前 cue/加载的视频的当前 YouTube 嵌入代码。
player.getVideoUrl():String
返回当前已提示/加载视频的当前 YouTube 视频网址。

事件

YouTubeLoaderEvent.LOADED
在 Chromeless Player 成功完成加载并准备好接受操作调用时触发。
YouTubeLoaderEvent.STATE_CHANGE
每当玩家的状态发生变化时触发。YouTubeLoader 类会将 JavaScript API 数字转换为其相关的字符串值,YouTubeLoaderEvent 类会将当前事件存储在名为 state 的变量中。可能的值包括:unstarted、started、played、 paused、正在缓冲、video cued。初次加载时,系统会广播一个未开始事件。在视频插入完毕并可供播放时,会播放已插入视频事件。
YouTubeLoaderEvent.IO_ERROR
在播放器中发生错误时触发。有两种错误代码可能出现:如果未找到所请求的视频,则系统会广播 100。如果视频因任何原因遭到移除或标记为私享视频,就会出现这种情况。如果请求的视频不允许在嵌入式播放器中播放,系统会广播 101。

演示备注

出于演示目的,我们希望在嵌入的 ActionScript 3 封装容器下方添加 XHTML 表单字段、按钮和显示界面。为了同时更新 swf 文件和 XHTML,我们必须在“youTubeLoader.js”位于“deploy/_assets/js/”中的 JavaScript 文件(图 3)。将此文件集成到您的项目中时,您需要移除以下两行 [69, 79]:

//------------------------------------
// SPECIAL YOUTUBE EVENT METHODS
//------------------------------------

function onYouTubePlayerReady(playerId) {

  if (checkObj()) {	
    obj.addEventListener("onStateChange", "onytplayerStateChange");
  };

  // PLEASE NOTE: For the purpose of this demo:
  // This calls a secondary method located in the index.html file allowing the html display to update.
  // You will most likely not need this, it's gross, remove this when you implement this code.
  secondaryOnYouTubePlayerReady(playerId);
}

function onytplayerStateChange(newState) {
    //alert("Player's new state: " + newState);
  obj.playerStateUpdateHandler(newState);

  // PLEASE NOTE: For the purpose of this demo:
  // This calls a secondary method located in the index.html file allowing the html display to update.
  // You will most likely not need this, it's gross, remove this when you implement this code.
  secondaryOnytplayerStateChange(newState)
}

演示文件及随附的 ActionScript 库都是免费软件:您可以根据 GNU 宽通用公共许可证的条款再分发和/或修改它。我们分发这些文件是希望它很有用,但不提供任何保证。

总结

本文、演示源文件应该能让您全面了解一种相对简单且可靠的解决方案,该解决方案使用我们为自己的项目开发的封装容器库将 YouTube API 和嵌入式播放器集成到 ActionScript 3 环境中。我已对大部分代码进行了注释,因此最好能够非常直接地探索和改编库。它也并非没有局限性,我们始终有改进、重构和增强的空间。如果您对此有任何想法,欢迎随时与我联系。

作者简介


马修·里士满

Matthew Richmond 拥有 14 年的互动设计、开发和架构经验。在工作室之外,他会在视觉艺术学院教授数字插图/摄影技术和高级 ActionScript。Matthew 是 choppingblock.com 的创始合伙人兼设计师。