大家好,我又回来了。我已经考完试了,下一步就是等出成绩,等录取通知书啦。
接下来我会继续回归系列教程的更新,以专题的形式补充一些我之前没有讲到的内容。同时预计春节后,会开始写UXP部分的教程,敬请期待。
之前有小伙伴反馈文章的形式对一些操作性的内容不太友好,我接下来会试着同时发布文章和视频的方式,视频会发布到B站和知乎,欢迎大家点赞关注转发。这篇文章的视频链接在这里【CEP教程】隐藏面板的妙用】 ,视频和文章的侧重点不一样,建议结合来观看。
这篇专题文章给大家介绍CEP插件中一种独特的面板形态 - 隐藏面板,以及它可以用来完成的一些有趣的功能。在某些情况下对我们非常有帮助。
隐藏面板 从官方的文档里头,我们可以看到,CEP提供了4种面板形态:
常规面板(Panel)
模态面板(ModalDialog)
非模态面板(Modeless)
自定义面板(Custom)
我们通常用的就是常规面板,它的特点是可以自由拖动和调整大小,并且可以在菜单栏中找到入口并打开,同时面板的开启并不会影响到用户的其他操作。而模态面板 类似一个对话框,它会强制阻断用户的操作,必须关闭此面板,用户才能继续操作其他内容。
今天我们要介绍的隐藏面板 ,其实就是自定义面板 ,它在整个Ps的运行周期中均不可见。那你可能就会想了,面板不可见,那我也打不开它,那能拿来干啥呢?我们反过来思考:既然用户无法打开它,也意味着用户关不了它。不像常规面板,如果用户关掉了面板,你的代码也就再没有执行的机会了。于是,隐藏面板因为用户无法进行关闭,这就给了我们一个永久运行生命周期 的机会。看不见的隐藏面板意味着:
始终在后台运行
用户无感知
比如你希望在用户打开Ps的时候,就开始自动执行一些任务,或者你希望在用户整个Ps的运行时间内都可以随时运行你的代码,那这就是隐藏面板带来的具体价值所在。
我们下来介绍如何来创建一个隐藏面板
隐藏面板的创建 通过设置manifest.xml文件,我们可以创建一个隐藏面板。
设置manifest的版本为5.0或者更高
1 2 3 <ExtensionManifest Version ="5.0" > ... </ExtensionManifest >
在Extension - UI - Type中设置为Custom
1 2 3 4 5 6 <Extension Id ="com.sample.id" > ... <UI > <Type > Custom</Type > </UI > </Extension >
在Extension - Lifecycle - AutoVisible中设置为false
1 2 3 4 5 6 <Extension Id ="com.sample.id" > ... <Lifecycle > <AutoVisible > false</AutoVisible > </Lifecycle > </Extension >
记得不要添加Menu 这个标签,不然它会出现在菜单栏里头
在Extension - Lifecycle - StartOn中添加面板的启动事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <Extension Id ="com.sample.id" > ... <Lifecycle > <AutoVisible > false</AutoVisible > <StartOn > <Event > applicationActivate</Event > <Event > com.adobe.csxs.events.ApplicationActivate</Event > <Event > com.adobe.csxs.events.AppOnline</Event > <Event > documentAfterActivate</Event > </StartOn > </Lifecycle > </Extension >
其中最重要的,其实是第5步,既然面板是隐藏的,切没有入口,那它合适启动呢?这就是第5步要做的内容,它定义了一些宿主的事件,当宿主发生这些事件的时候,就会触发启动面板。比如上面的例子,当用户打开Ps的时候,就会触发启动面板。这就使得我们可以实现一个全生命周期的面板。
整个manifest.xml的内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?xml version="1.0" encoding="UTF-8" standalone="no" ?> <ExtensionManifest xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" ExtensionBundleId ="IamInvisible" ExtensionBundleVersion ="1.0" Version ="5.0" > <ExtensionList > <Extension Id ="IamInvisible" Version ="1.0" /> </ExtensionList > <ExecutionEnvironment > <HostList > <Host Name ="PHXS" Version ="13.0" /> </HostList > <LocaleList > <Locale Code ="All" /> </LocaleList > <RequiredRuntimeList > <RequiredRuntime Name ="CSXS" Version ="5.0" /> </RequiredRuntimeList > </ExecutionEnvironment > <DispatchInfoList > <Extension Id ="IamInvisible" > <DispatchInfo > <Resources > <MainPath > ./html/invisible.html</MainPath > <CEFCommandLine > <Parameter > --enable-nodejs</Parameter > </CEFCommandLine > </Resources > <Lifecycle > <AutoVisible > false</AutoVisible > <StartOn > <Event > applicationActivate</Event > <Event > com.adobe.csxs.events.ApplicationActivate</Event > <Event > com.adobe.csxs.events.AppOnline</Event > <Event > documentAfterActivate</Event > </StartOn > </Lifecycle > <UI > <Type > Custom</Type > <Geometry > <Size > <Height > 1</Height > <Width > 1</Width > </Size > </Geometry > </UI > </DispatchInfo > </Extension > </DispatchInfoList > </ExtensionManifest >
面板的功能 完成manifest.xml的设置之后,我们就可以开始写面板的功能了。面板的其他结构和常规面板是一致的。我们在html文件里头简单写一段代码来验证它是不是能够在Ps启动的时候就执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!doctype html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Invisible Panel</title > <meta name ="viewport" content ="width=device-width,initial-scale=1.0" > </head > <body > <script src ="../js/CSInterface-6.1.0.js" > </script > <script > alert ("这个弹窗来自隐藏面板" ); </script > </body > </html >
这个时候,我们打开Ps,就会发现,这个弹窗已经出现了。这就说明我们的面板已经成功的启动了。并且你还无法在菜单栏里头找到它。
上面我们测试的是Js部分的执行,接下来看看JSX应该如何来使用。有一个地方需要注意的是,隐藏面板不支持ScriptPath 标签,即无法默认加载一个jsx脚本,不过我们可以通过Js去动态加载我们的jsx脚本来执行。
1 2 3 4 5 var csInterface = new CSInterface ();var extensionRoot = csInterface.getSystemPath (SystemPath .EXTENSION );var jsxFile = extensionRoot + "/jsx/main.jsx" ;csInterface.evalScript(`$.evalFile('${jsxFile} ')` );
这里的实现和我们常规面板开发是基本一致的。
隐藏面板的应用场景 上面我们已经完成了隐藏面板的开发,接下来我们来看看隐藏面板的应用场景。
App启动时执行脚本
这个上面的示例已经介绍了,因为隐藏面板就是在App启动的时候开启的,我们在里面的代码就能够实现app自动时执行。
与常规面板交互
单独一个隐藏面板对用于而言是没有什么价值的,我们一般会提供一个常规面板,这个时候隐藏面板可以作为一个后台运行的服务,为我们的常规面板提供能力,比如说面板重启功能。
我们的插件发布的时候,一般会将面板设置为Persistent 模式,这样用户每次打开能够停留在上一次关闭的状态,但是这样也会带来一个问题,就是如果我们的插件出现了问题,用户无法通过关闭面板来重启插件,这个时候我们就可以通过隐藏面板来实现这个功能。
在前面的文章中,我们介绍过插件之间可以通过事件来进行通信,由于隐藏面板是常驻运行的,所以我们可以随时给它发送消息,让它去重启我们的面板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const csInterface = new CSInterface ();const extensionId = csInterface.getExtensionID ();const event = new CSEvent ();event.type = "my.restart.event" ; event.extensionId = extensionId; event.scope = "APPLICATION" ; event.data = JSON .stringify ({restart : 1000 , extensionId : extensionId}) csInterface.dispatchEvent (event); setTimeout (() => { csInterface.closeExtension (); }, 100 );
隐藏面板可以通过监听这个事件来接收到消息,然后去重启我们的面板。
1 2 3 4 5 6 7 8 9 10 11 12 13 const cs = new CSInterface ();cs.addEventListener ("my.restart.event" , function (event ) { console .log ("restart extension: " + JSON .stringify (event.data )); const data = event.data ; const extensionId = data.extensionId ; const time = data.restart ; setTimeout (function ( ) { cs.requestOpenExtension (extensionId) setTimeout (function ( ) { cs.requestOpenExtension (extensionId) }, 1500 ) }, time); });
这里需要注意的是,如果你的插件已经设置了Persistent,需要先进行UnPersistent 操作,避免重新打开的插件依然是之前的状态。
1 2 3 4 5 function unPersistent ( ) { const event = new CSEvent ("com.adobe.PhotoshopUnPersistent" , "APPLICATION" ); event.extensionId = extensionId; csInterface.dispatchEvent (event); }
常驻后台服务
由于隐藏面板的常驻生命周期特性,我们可以通过它来实现一个常驻后台的服务,比如长链接与我们的服务器进行通信,这样你可以通过远端实时推送一些消息给你的用户。或者是一些数据的统计和上报等等,都可以在后台进行默默的操作。这方面涉及到的案例代码量都比较大,我就不在这里展示了,大家可以根据自己的需要去实现。
总结 这个是示例项目的代码地址 ,大家可以下载下来,自己去尝试一下。
以上,就是我们要介绍的关于隐藏面板 的使用,这种纯应用型的知识是无法在官方文档里头找到的,也是许多前人实践的一些经验,希望能够帮助到大家。
另外需要注意的是,不同的宿主App(如Ps/ID/AI)等对隐藏面板的支持程度和特性都不太相同,大家使用的时候要特别小心,明白走进死胡同。