';

这是 CEP 的用到的技术概览,你能从中了解构建 CEP 扩展的运行方式和具体的配置方法。

CEP 的运行机制

一个 CEP 插件实际上是一个在显示在宿主程序面板窗口中的网页,通过 CEP 提供的接口与宿主程序进行交互。这里要分清 CEP 扩展与宿主应用的关系:

 

宿主应用

所谓宿主,就是载入 CEP 扩展的应用,例如一个运行在 PhotoShop 中的 CEP 扩展,它的宿主程序就是 PhotoShop ,作为宿主程序的 PhotoShop 有很多内置功能,和一个被称为 ExtendScript 的脚本引擎,通过 ExtendScript 脚本引擎能够调用各种 PhotoShop 的内置功能,比如创建一个图层、设置背景颜色等等。要注意的是 CEP 和 ExtendScript  都使用 JavaScript 但是它们分别运行在两个虚拟机中,并不在一个上下文中,所以互相是独立的。
另外,一个 CEP 扩展可以同时被多个宿主运行。

ExtendScript

实际上 ExtendScript 不一定是 JavaScript 还有基于 VBScript 和 AppleScript 的一套接口,不过这里只针对 CEP 用到的 JavaScript 来说。ExtendScript  是 Adobe 早期为其应用提供的自动化功能,它把应用(如 PhotoShop)的各种操作封装成 DOM 使用 ExtendScript  脚本去操作。

作为 ExtendScript 的 JavaScript 代码会在宿主程序内置的一个 JavaScript VM(虚拟机)中被解析,这是与 CEP 扩展中的 JavaScript 代码的区别,CEP 扩展中的 JavaScript 代码会在另一个 JavaScript VM (CEF )中运行。
我们暂且把 CEP 的 JavaScript 解析引擎称为 CEP VM, 运行在其中的代码称为 JavaScript ,ExtendScript 的解析引擎称为 ExtendScript VM ,运行在其中的代码称为 ExtendScript 或者 JSX ,以示区别。

CEP VM 运行的就是 HTML 中的 JavaScript 代码 ,因为与 ExtendScript VM 是互相独立的,所以需要使用 Adobe 提供的 CSInterface.js 来执行 ExtendScript VM 中的方法 (实际上通过 window.__adobe_cep__ 也可以,CSInterface.js 是对 CEP VM 中  window.__adobe_cep__ 中方法的封装)并互相传递数据。CEP VM 运行的 JavaScript 是支持 Node.js 的,而 JSX 是不支持的,
通常我们在 CEP VM 的 JavaScript 中写扩展的主要逻辑,只有涉及到宿主的操作时才使用 JSX,因为在 2 个虚拟机间传递信息是一件麻烦并且很慢的事 。

 

CEP 文件结构

CEP 扩展存放的目录

每一个 CEP 扩展都以一个文件夹的形式存放在下面的目录中,其中Windows 通用路径是只对当前用户有效的路径,放在其中的扩展只有当前系统用户才能正常使用。
此外 宿主应用安装目录\Required\CEP\extensions\ 中也可以存放扩展,而且你能在这里找到应用自带的扩展。

CC 2014, CC 2015, CC 2015.1
Windows 32 位 C:\Program Files\Common Files\Adobe\CEP\extensions\
Windows 64 位 C:\Program Files (x86)\Common Files\Adobe\CEP\extensions\
Windows 通用 C:\Users\系统用户名\AppData\Roaming\Adobe\CEP\extensions\
OS X /Library/Application Support/Adobe/CEP/extensions/
CC
Windows 32 位 C:\Program Files\Common Files\Adob\CEPServiceManager4\extensions\
Windows 64 位 C:\Program Files\Common Files\Adob\CEPServiceManager4\extensions\
Windows 通用 C:\Users\系统用户名\AppData\Roaming\Adobe\CEPServiceManager4\extensions\
OS X /Library/Application Support/Adobe/CEP/extensions/

另外在 PhotoShop 的帮助-系统信息中可以看到每个扩展的存放路径:

 

常见目录结构

CEP 扩展只有 CSXS\manifest.xml 是固定必要的文件,其他都是可以自由组织的,不过通常都是以下面这种形式来组织的:

│  index.html
│
├─CSXS
│      manifest.xml
├─css
│      styles.css
│─jsx
│      func.jsx
└─js
        AgoraLib.js
        CSInterface.js
        ...
  • CSXS
    最重要的文件夹,因为它存储了 CEP 扩展的说明文件 manifest.xml
  • index.html
    扩展的入口和界面,扩展面板的内容就是载入的它。实际上它的位置和名称都是 manifest.xml 中 <MainPath> 定义的, 所以一个扩展的 Main 可能不叫 index.html
  • cssjsjsx 文件夹
    分别是存放样式表和 Javascript 、ExtendScript 文件的文件夹,当然也可以不叫这个名字,这是由 index.html 和 manifest.xml 决定的,不过通常扩展使用这样的目录名称。
  • jsjsx
    都是存放 Javascript 文件,但是运行环境是不同的,他们之间的区别以后会详解。

 

manifest.xml 详解

manifest.xml 里面有扩展的重要的配置信息,包括扩展名称、版本、在什么宿主中运行、入口文件、尺寸等等等,manifest.xml 只有宿主应用启动时载入,所以修改了 manifest.xml 只有重启宿主应用才会使修改生效。 manifest.xml 是一个 XML 文件,你可以用任何文本编辑器打开并编辑它,另外还可以使用 foxe 等 XML 编辑器更加直观的以树形列表查看和编辑。

用 foxe 编辑 manifest.xml

下面是一个简单的 manifest.xml 的示例:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ExtensionManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ExtensionBundleId="com.nullice.cep.devtest" ExtensionBundleVersion="1.0" Version="6.0"> <!-- MAJOR-VERSION-UPDATE-MARKER -->
    <ExtensionList>
        <Extension Id="com.nullice.cep.devtest" Version="1.0"/>
    </ExtensionList>

    <ExecutionEnvironment>
        <HostList>
            <Host Name="PHXS" Version="[11.0,99.9]"/>
            <Host Name="PHSP" Version="[11.0,99.9]"/>
        </HostList>

        <LocaleList>
            <Locale Code="All"/>
        </LocaleList>

        <RequiredRuntimeList>
            <RequiredRuntime Name="CSXS" Version="6.0"/> <!-- MAJOR-VERSION-UPDATE-MARKER -->
        </RequiredRuntimeList>

    </ExecutionEnvironment>


    <DispatchInfoList>
        <Extension Id="com.nullice.cep.devtest">
            <DispatchInfo>
                <Resources>
                    <MainPath>./index.html</MainPath>
                </Resources>

                <Lifecycle>
                    <AutoVisible>true</AutoVisible>
                </Lifecycle>

                <UI>
                    <Type>Panel</Type>
                    <Menu>Exchange Extension 测试2</Menu>
                    <Geometry>
                        <Size>
                            <Height>300</Height>
                            <Width>300</Width>
                        </Size>
                        <MaxSize>
                            <Height>900</Height>
                            <Width>900</Width>
                        </MaxSize>
                        <MinSize>
                            <Height>300</Height>
                            <Width>300</Width>
                        </MinSize>
                    </Geometry>
                </UI>

            </DispatchInfo>
        </Extension>
    </DispatchInfoList>
</ExtensionManifest>

manifest.xml 的详细定义( XSD )

扩展 ID

<ExtensionManifest> 标签中的 ExtensionBundleId 属性定义的是这个扩展程序集的识别 ID ,之所以说是扩展程序集,因为一个 manifest.xml 可以定义多个子扩展,每个扩展集中的子扩展可以共用资源而在宿主应用的插件列表中有自己的位置。

每个子扩展的信息写在 <ExtensionList> 的 <Extension> 子标签中。每个扩展 ID 都需要是唯一的,所以常常使用前缀避免与其他开发者的扩展冲突如:com.nullice.xxxxcom.adobe.xxxx

下面这个示例就定义了一个 ID 为 com.nullice.cep.devtest 的扩展集,并拥有 3 个子扩展:

<ExtensionManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ExtensionBundleId="com.nullice.cep.devtest" ExtensionBundleVersion="1.0" Version="6.0"> <!-- MAJOR-VERSION-UPDATE-MARKER -->

<ExtensionList>
 <Extension Id="com.nullice.cep.devtest.c_1" Version="1.0"/> 
 <Extension Id="com.nullice.cep.devtest.c_2" Version="1.0"/> 
 <Extension Id="com.nullice.cep.devtest.c_3" Version="1.0"/> 
</ExtensionList>

支持宿主版本

<ExecutionEnvironment> 标签的子标签 <HostList> 中的 <Host> 定义了这个扩展集的所有程序可以在那些宿主和其对应版本中运行,比如:

<Host Name="PHSP" Version="14.0"/>
<Host Name="PHXS" Version="14.0"/>

Name 属性是支持的宿主程序名, PHSPPHXS 表示的是 PhotoShop ,Version 属性是限定宿主程序的版本,比如 PhotoShop CC2015 的版本是 16.0,除了限定在某个版本,还可以限定在一个区间,比如下面这个例子是限定运行在 11.0 到 99.9 之间的版本。

<Host Name="PHXS" Version="[11.0,99.9]"/>

这是各个 Adobe 程序与对应宿主 ID 还有各版本版本号的列表:

软件 宿主 ID CC CC 2014 CC2015
Photoshop PHXS/PHSP 14 15 16
InDesign IDSN 9 10 11
InCopy AICY 9 10 11
Illustrator ILST 17 18 19
Premiere Pro PPRO 7 8 9
After Effects AEFT 不支持 13 14
Prelude PRLD 2 3 4
Flash Pro FLPR 13 14 15
Dreamweaver DRWV 不支持 不支持 15

扩展定义

<DispatchInfoList> 的子标签 <Extension> 中的 <DispatchInfo> 标签定义了扩展具体的各种属性。对应不同的子扩展,<DispatchInfoList>可以有多个<Extension>标签。

指定资源文件
<Resources>    
  <MainPath>./index.html</MainPath>
  <ScriptPath>./jsx/Source1.jsx</ScriptPath>
</Resources>

<MainPath> 指定的是主页面的 HTML 文化的位置, 这个文件就是 CEP 面板中的内容,在面板打开时第一个就会载入它。
<ScriptPath> 是指定扩展中会使用到的 JSX 文件的内容。(除了在这里指定还可以动态加载 JSX 文件,以后会详细说明)

 

生命周期

<Lifecycle> 标签下的设置关于插件启动和可视的设定。

  • 扩展可视
    <AutoVisible>true</AutoVisible>
    设定扩展是否可视,值为 false 的话, 扩展就是没有界面的不可视扩展。(要让插件完全隐形的话,可以不要设置下面会说的 <Menu> 标签,这样扩展就不会出现在 PhotoShop 的扩展功能菜单中)
  • 自动运行
    <StartOn> 标签下可以添加多个 <Event> 标签,每个 <Event> 标签值为一个事件,当事件发生时,扩展就会被自动打开。
    下面这个例子中扩展会在 PhotoShop 启动时自动打开:
    <Lifecycle>
        <StartOn>
           <Event>applicationActivate</Event>
        </StartOn>
    </Lifecycle>

    关于扩展中的事件(Event)后面会详细说。

界面

<UI> 标签下的各种子标签指定关于扩展界面的各种属性

界面类型

<Type> 标签指定扩展界面的显示类型,有 3 中类型:

<Type>Panel</Type> 面板型(Panel) 即普通的工具面板,最为常用
<Type>ModalDialog</Type> 模态对话框(ModalDialog) 把扩展作为一个单独窗口显示,而且在操作扩展的窗口时,是不能操作 PhotoShop 的,必须等扩展窗口关闭后才能继续 PhotoShop。
<Type>Modeless</Type> 非模态对话框(Modeless) 把扩展作为一个单独窗口显示,与模态对话框不同,操作扩展窗口的同时可以随时切换到 PhotoShop 窗口中去。
扩展面板标题

<Menu>Exchange Extension 测试2</Menu>
设置扩展面板的标题,同时也是 PhotoShop 扩展功能菜单列表中的名称。

 

插件尺寸

通过 <Geometry> 标签可以指定扩展面板的大小
分为 <Size><MaxSize><MinSize>,分别是面板默认的初始尺寸、用户能把面板拉伸到的最大和最小尺寸。

 <Geometry>
        <Size>
            <Height>580</Height>
            <Width>1000</Width>
        </Size>
        <MaxSize>
            <Height>800</Height>
            <Width>1200</Width>
        </MaxSize>
        <MinSize>
            <Height>400</Height>
            <Width>600</Width>
        </MinSize>
    </Geometry>
扩展图标

<Icons> 标签的子标签 <Icon> 可以设置扩展的图标,图标有 2 种类型 Normal 和 DarkNormal ,分别在宿主应用的界面主题颜色为亮色和暗色时显示。
另外你可以在 xxx.png 图标文件所在目录放入 xxx@2X.png 文件,在高清屏下 PhotoShop 会调用 xxx@2X.png 文件。一般普通图标的尺寸为 23 x 23 而 xxx@2X.png 为它的 2 倍 46 x 46。

另外还有 RollOver 类型的图标,这是鼠标悬停在图标上时显示的,不过只在 Illustrator 上有效,Photoshop 并不支持。

<Icons>    
    <Icon Type="Normal">./img/icon1.png</Icon>    
    <Icon Type="DarkNormal">./img/icon1.png</Icon>
    <Icon Type="RollOver">./img/IconLight.png</Icon>
    <Icon Type="DarkRollOver">./img/IconDark.png</Icon>
</Icons>

 

CEP JavaScript 库

CEP 有 3 个官方的 JavaScript 库(下载),可以通过他们调用 CEP 功能。

  • CSInterface.js
    提供接口让 HTML 面板的 JavaScript 引擎运行的 JavaScript 代码能与 PhotoShop 的内部的 ExtendScript 引擎运行的 JavaScript(JAX)交互。和调用 PhotoShop 的一系列 API。
  • Vulcan.js
    操作其他的程序比如在 PhotoShop 中与 Illustrator 交互。
  • AgoraLib.js
    操作 Adobe Exchange 的在线服务。

HTML 面板界面

之前也说过了,CEP 的界面也就是面板是使用的是 HTML 技术,实际上它是一个运行在 CEF —— 一个特殊的 Chromium 浏览器中的网页。

面板就是 HTML 网页

在 CEP6 (CC 2015) 上 CEF 版本为 3.1453.1339 相当于 Chormium 27,也就是对 HTML5 支持程度相当于 2013 年的 Chrome ,而最新的 CEP 6.1 (CC2015.1) 中 CEF 升级到了3.2272.67, 相当于 Chromium  41,对 HTML5 支持程度已经相当于 2015 年初的 Chrome 了。

 

引入第三方库(如 jQuery )

要注意的是要引入会占用 $ 符号的第三方库如 jQuery ,要在载入前加入一句:window.module = undefined 否则 jQuery 无法把自己注册到 $ 符号,使用  jQuery  时就会出现 $ 未定义的错误,

<script type="text/javascript">window.module = undefined</script>
<script src="js/jquery-2.1.4.min.js" type="text/javascript"></script>

 

 

Node.js

CEP  使用了 Node.js ,而 CEP 6.1 变成了 io.js v1.20 ( 2015-02-10 发布的版本) ,io.js 是一些 Node.js 核心开发者受不了 Node.js 项目迟钝保守管理做风,从而分裂出来的项目,io.js 的更新相对于 Node.js 更活跃,对新特性的更新更积极,而且相对与 Node.js 有相对更好的性能表现。
不过对这个改变,几乎可以预见的是未来 CEP 还会换回 Node.js ,因为 io.js 和 Node.js 从分裂又走向了合并,2 个社区完成了和解,成了了新的基金会,合并成了新的 Node.js 2.0+ 版本。不过对于使用上来说, Node.js 和 io.js 几乎是没有区别的。

io.js 取代了 Node.js

 

开启  Node.js

 

在 CEP 6.1 之前,CEP 是默认开启  Node.js 的,而  CEP 6.1 之后是默认关闭  Node.js 的,需要在 manifest.xml<Resources> 标签下指定开启 Node.js:

...
 <Resources>
     <CEFCommandLine>
          <Parameter>--enable-nodejs</Parameter>
      </CEFCommandLine>
</Resources>
...

而使用 <iframe> 标签组织页面时也需要指定启用 Node.js ,如:

<iframe id="someID"  enable-nodejs></iframe>