【UXP教程-6】插件面板实战-运行JSX代码
UXP是Adobe新推出(虽然也有几年了)的插件架构,不像以前CEP那样使用JSX来和宿主进行交互,UXP官方提供了对应的photoshop-api,使用起来融合性更好,更方便一些。但是你在是做CEP插件迁移的时候会发现官方提供的API寥寥无几,很多以前在JSX可以运行的能力都缺失了,虽然Adobe也意识到了这个问题,于是提供了一个叫做batch play的补丁运作机制,但用起来还是非常别扭。
早在两年前多前,我在刚开始试水UXP插件的时候,就想过是不是可以在UXP中执行JSX代码,摸索了好久没找到方法,当时主要是觉得UXP在执行本地文件的时候有安全限制,所以感觉应该没戏了,就放弃了,后来一段时间也没有继续关注插件开发。
前一段时间,群里头有一个小伙伴在研究这个东西,并且找到了途径,在群里头做了分享,我当时也忙没顾上研究,趁这个春节假期比较闲,就打算深入看看,还真找到了方法,在这里先感谢 @糖炒栗子 的分享。
核心思路
我们的目标是要实现像CEP中那种csInterface.evalScript()
要实现这个功能,可以静默执行JSX代码(或文件),要实现这个功能本质需要两个条件:
- 能够在UXP中执行JSX的文件
- 绕开UXP的系统文件限制
1. 能够在UXP中执行JSX的文件
这个能力,是借助了Ps自带的执行脚本文件的功能,如下
这个功能在执行的时候,会输出ActionManager的代码,我们可以通过batchPlay来重写这段代码,结构如下:
1 | import { core, action } from 'photoshop'; |
这段代码,你只要传递正确的jsx文件路径,它就能够正确的执行,并且可以返回你JSX的执行结果。(返回值部分我们后面再介绍)
2. 绕开UXP的系统文件限制
这个是之前我困扰我好久的地方,因为UXP的安全限制要求访问系统文件,必须用户进行授权,就是得弹出一个文件选择框让用户选了,你才能操作里头的文件,这也是我之前放弃继续探索的原因,但是前几天我在开发图层导出PNG的时候,在论坛上看到了一些别人的代码,非常神奇,居然可以直接给目标文件自己授权,不通过系统选择框,于是我就将这两者结合起来,实现了这个功能。
1 | async function tokenify(filePath: string) { |
这段代码的功能就是给目标路径创建一个会话的token,相当于给文件授权了,这样batchPlay就会信任这个文件,你甚至都可以直接将token作为filePath传递给run函数,这样就实现了静默执行JSX文件的功能。
其实代码就这么些,没有特别复杂的东西,于是相当于你自己实现了一个csInterface.evalScript()
,这样你的uxp插件就会变得和CEP插件类似了,岂不美哉。
3. 返回值获取
如何获取到JSX文件的执行结果呢? 其实JSX文件(代码)的执行结果,会以标准输出的形式出出现,并被batchPlay捕获并且返回,你只要在jsx文件的最后,把返回值写上,就可以获取到了,类似这样:
1 | var a = 1; |
最后一行的a+b
就是返回值,你只要在run函数中获取到返回值,就可以获取到JSX文件的执行结果了,它会在batchPlay返回的javaScriptMessage
中。
这只是一个简单的例子,如果你想返回一个复杂的数据对象,可以使用JSON.stringify()来将对象转换为字符串,然后在UXP文件中使用JSON.parse()来解析返回值。
1 | var a = 1; |
综合
有了这些能力之后,你就可以和以往CEP一样开发插件了,你可以把jsx文件打包放到uxp的插件目录里头,然后在需要执行对应文件的时候,使用上面的代码,这里给个示例:
1 | import { storage, shell } from 'uxp'; |
然后你可以借助这个能力,写一个执行一段jsx代码的函数,你只要把这段代码临时写入到本地沙箱目录就可以了:
1 | export async function runJsxCode(jsx: string) { |
这个能力还是出乎我意料的,因为按照这个模式,UXP的安全限制并不完整,意思是你可以自己创建SessionToken来绕过系统文件的授权限制,这就打开了一个更大的空间,能做的事情会更多……
能够执行JSX代码,可以大幅扩展UXP的插件能力,你甚至可以把uxp当做一个壳,核心能力都用jsx来完成,这样从CEP迁移到UXP的成本就会低很多。还有UXP由于有很多安全限制,无法很顺畅的做系统文件操作,你就可以把这些操作都挪到JSX当中,就变相的绕过了这些限制:
好了,这篇文章就写到这里,希望对大家有帮助!再次感谢 @糖炒栗子 同学,也希望大家可以多多分享,促进交流和成长。