使用高级压缩进行导出

743次阅读
没有评论

共计 2343 个字符,预计需要花费 6 分钟才能阅读完成。

使用高级压缩进行导出

导出项目时,有一个“压缩脚本”的选项。这会压缩 Construct 引擎和您自己脚本中使用的所有 JavaScript 代码,有助于混淆项目,使其更难以逆向工程。但是,如果您选择高级模式,可能需要调整在 Construct 中编写 JavaScript 代码的方式。

“无”模式只是完全跳过脚本压缩,因此脚本不会有任何改变。“简单”模式会消除空白字符,并进行诸如将局部变量重命名为更短名称之类的简单调整。这不会影响代码的运行,所以始终可以安全使用。“高级”模式会重命名其他所有内容,包括对象属性、类方法名称等等。这个过程被称为属性混淆。它提供了最佳的压缩和混淆效果,但在某些情况下可能会影响代码的运行。因此,您必须了解其工作原理,并相应地编写代码,以安全地使用它。

# Construct 引擎中的所有内容都支持高级模式。只有在使用脚本功能在 Construct 中编写 JavaScript 代码时,才需要小心使用高级模式。

脚本压缩由 Google 的 Closure Compiler 处理。这是一个广泛使用的 JavaScript 处理工具。本指南涵盖了基本要求,但您也可以参考 Google 自己的文档以获取更多详细信息。

属性混淆的工作原理

属性混淆会将对象属性重命名为更短的名称。例如,考虑以下代码:

使用高级压缩进行导出

这将记录数字 1 和 2,因为它们对应于对象属性 apples 和 oranges。经过高级压缩后,属性将被重命名为更短的名称,例如:

使用高级压缩进行导出

这是更短的代码(加载速度更快),更难以理解(更难以逆向工程)。并且它的运行方式与之前完全相同。

避免重命名

在某些情况下,存在您不希望重命名的特定名称。例如,如果在运行时加载外部库并调用如下方法:

使用高级压缩进行导出

属性重命名将更改函数的名称,例如:

使用高级压缩进行导出

这会破坏代码,因为它切换到调用一个不存在的函数。问题在于压缩过程不知道来自您自己脚本之外的代码,最终重命名了不应该重命名的内容。

为避免这种情况,您可以使用字符串属性语法,如下所示。

使用高级压缩进行导出

高级压缩永远不会重命名字符串属性,因此即使在压缩后,名称 doSomethingUseful 也会保留,并且代码继续正常工作。

要将全局名称编写为字符串属性,请将其作为 globalThis 的属性进行访问,例如:

使用高级压缩进行导出

内置名称

Construct 使用内部的内置浏览器 API 名称列表,压缩器会使用该列表避免重命名内置函数和属性。例如,名称 console 和 log 在列表中,因此在诸如 console.log("Hello") 之类的内置调用中,它永远不会重命名这些属性。

在某些情况下,浏览器 API 可能不在内部列表中,例如,如果它只是在最新的浏览器版本中刚刚添加。在这种情况下,您可以使用字符串属性进行访问,以确保它不会被重命名。

来自 Construct 的对象和变量名称

一些运行时 API 使用来自 Construct 编辑器的名称,例如 runtime.objects.Sprite(它从对象的名称 Sprite 中获取名称)。这些属性与您代码中的其他所有内容一起被一致地重命名,因此您应该正常将它们作为点属性进行访问,以确保压缩后您的代码仍然正常工作。

# 只有有效的 JavaScript 标识符的对象名称才会被重命名。例如,**Sprite** 会被重命名,但 **0Sprite** 不会。原因是 **0Sprite** 不是有效的 JavaScript 标识符,不能用作点属性(例如 **runtime.objects.0Sprite** 是无效的)。它必须始终作为字符串属性进行引用(例如 **runtime.objects["0Sprite"]**),并且压缩器不会更改字符串属性。考虑始终为对象名称使用有效的 JavaScript 属性名称,以避免任何混淆。

不要混合属性样式

使用高级压缩破坏代码的主要错误是混合使用正常属性(会被重命名)和字符串属性(不会被重命名)。例如,考虑以下会被破坏的代码:

使用高级压缩进行导出

这对属性名称 apples 同时使用了字符串语法和正常语法。通常,此代码有效(记录数字 1),但在高级压缩后,只有一个属性被重命名,导致如下代码:

使用高级压缩进行导出

请注意,“apples”保留了其名称(因为它使用字符串语法),但 obj.apples 被重命名为 obj.a。该对象上不存在该属性,因此现在代码记录的是 undefined 而不是 1。

解决方案是始终一致地使用相同的语法。只要属性名称始终不使用字符串语法,或者始终使用字符串语法,它就会正常工作。只有当两种类型混合使用时,代码才会被破坏。

有几种不太明显的方式可能会导致字符串属性混合。例如,Object.defineProperty() 仅接受属性名称的字符串。由于字符串永远不会被重命名,如果您使用此方法,则该属性名称必须始终使用字符串语法进行引用。

全局变量

高级压缩的一个额外要求是全局变量必须始终作为全局对象的属性进行引用。例如,下面的代码由于全局变量未作为属性引用而存在问题。

使用高级压缩进行导出

使用 console.log(myGlobal) 通常确实是引用全局变量。但是,在高级模式下压缩会失败。(这是由于难以自动重命名与局部变量编写方式相同的全局变量。)解决方案是始终将全局变量作为全局对象的属性进行引用,即使用点,如下所示:

使用高级压缩进行导出

结论

脚本压缩有助于压缩代码大小,并使逆向工程更加困难。高级压缩提供了最佳的压缩和保护效果,但在编写代码时需要注意确保不会因属性混淆而破坏。通常,在高级模式下,代码无需进行任何特定更改即可正常工作。需要注意的情况仅有:

  • 1. 调用外部库函数(或不在 Construct 内置名称列表中的新浏览器 API)
  • 2. 混合使用字符串属性语法和正常属性语法
  • 3. 始终将全局变量作为全局属性进行引用

如果您确保代码正确处理了上述情况,那么您应该能够在 Construct 中安全地使用自己的 JavaScript 代码的高级压缩模式。

正文完
 0
评论(没有评论)