关于electron:Electron-程序支持-M1-芯片

51次阅读

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

原文地址:https://webfe.kujiale.com/ele…
酷家乐客户端:下载地址 https://www.kujiale.com/activ…

概述

目前存在两种架构芯片的 macbook,别离是 x86 和 arm 架构,对应了 Intel 芯片和 Apple M1 芯片。

旧版本酷家乐客户端,是通过 Rosetta 2 运行在 M1 芯片的 macbook 设施上的。新版本 12.2.0 之后的酷家乐客户端原生反对了 M1 芯片,本文次要阐明酷家乐客户端是如何原生反对 M1 芯片的。

名词解释

酷家乐客户端:酷家乐官网基于 Electron 开发的桌面客户端,反对 windows 和 macos。

Rosetta:苹果提供的用于转译利用的工具。Rosetta 最后是用于将 PowerPC 的利用转译成 Intel 的利用,这次苹果公布 M1 芯片设施的同时公布了 Rosetta 2,用于将 Intel 的利用转译为能够在 arm 架构的 M1 芯片上运行的利用(相干文档:https://zh.wikipedia.org/wiki…、https://support.apple.com/zh-…)

为什么须要反对 M1 芯片

回顾苹果上一次的芯片架构替换,也就是从 PowerPC 换成 intel x86,在刚开始的 2005 年零碎默认装置了 Rosetta 用于转译,而 2009 年零碎不在默认装置 Rosetta,到 2011 年零碎彻底不在反对 Rosetta。

也就是说目前提供的 Rosetta 2 也应该会在 3、4 年后不在默认提供,5、6 年后彻底不在反对,所以反对 M1 芯片必须是要实现的。

x64 的安装包

酷家乐客户端之前公布的 macos 安装包是针对 x64 构建的,通过 Rosetta 是能够运行的。

然而须要你留神的是:electron 从 2020.7.22 – 2020.11.19 之间公布的版本因为 chromium 的解体问题(相干 issue),彻底禁用了 electron 在 Rosetta 上运行(相干 pr)。因为酷家乐客户端 v8.2.3 不在这个工夫内,所以能够失常应用。

当然你可能会思考那些没有禁用 Rosetta 运行的 electron 版本上,没有 chromium 解体问题吗?依据我的理论测试,酷家乐客户端的 v8.2.3 是能够失常通过 Rosetta 上运行的。其实认真查看那个对于 chromium 解体问题的 issue 中的探讨,有人提到在最终量产的 Mac 上的 Rosetta 应该没有这个解体问题(相干评论)。

arm64 的安装包

依据 electron 博客文章,从 v11.0.0 开始,electron 曾经反对构建 darwin-arm64 的利用,能够不通过 Rosetta 转译,间接运行在 M1 芯片的机器上。

electron-packager

酷家乐客户端应用的构建工具 electron-packager,也反对构建 darwin-arm64 安装包了。只须要将打包参数里的 platform 值设置为 darwinarch 值设置为 arm64 即可。

electron-builder

另外一个社区中应用较多的打包工具 electron-builder,能够应用 arch 值设置为 arm64

反对 Intel 和 Apple M1 的通用利用

当初曾经能够别离打包 x64 和 arm64 的 macos 安装包,用于分发给用户。然而分成两个包,对用户来说,是有肯定的了解老本的,用户可能基本不分明本人应该装置哪一个。并且对于推送给用户的更新,也须要解决两种包的装置下载逻辑,所以就有了制作通用利用的需要。

通用利用,顾名思义就是能够同时原生运行在 Intel 和 Apple M1 芯片上的利用。这样用户只须要装置通用利用,更新推送也只须要推送通用利用,能够无缝替换之前装置的非通用利用。当然也有毛病,因为是合并了两个利用,所以安装包的体积也靠近翻倍了。

构建通用利用

electron-builder

如果你应用的是 electron-builder,能够应用 arch 值设置为 universal 即可。

electron-packager

如果是和酷家乐客户端,以及 vscode 一样应用的是 electron-packager,则须要先应用 electron-packager 别离构建出 x64 和 arm64 利用,而后应用 electron 官网提供的构建工具 @electron/universal 将 x64 和 arm64 利用合并成通用利用。

import {makeUniversalApp} from '@electron/universal';
 
await makeUniversalApp({
  x64AppPath: 'path/to/App_x64.app',
  arm64AppPath: 'path/to/App_arm64.app',
  outAppPath: 'path/to/App_universal.app',
});

理论应用时的踩坑

hash 检测报错

理论应用 @electron/universal 时会呈现 hash 检测报错:

(node:10983) UnhandledPromiseRejectionWarning: Error: Expected all non-binary files to have identical SHAs when creating a universal build but "Contents/CodeResources" did not

能够看到,这里对所有的非二进制文件都进行了 hash 检测。

这是因为对于二进制文件,能够通过 lipo 命令行工具 生成通用二进制文件。而非二进制文件,就必须只保留一份放入到最终的通用利用中,所以须要保障 hash 统一,这样就能够保障通用利用中的文件是和构建前的 x64 和 arm64 利用中的都是统一的。

然而从报错信息能够看到 CodeResources 有问题,而 CodeResources 是代码签名生成的,当然 hash 是不统一的。这时的解决办法就只能在生成 x64 和 arm64 的过程中,不进行签名,而是在生成通用利用之后,对通用利用进行签名即可,这个形式也是 electron-builder 的策略。

除了跳过 x64 & arm64 的签名以外,我在 vscode 的代码中找到来另外的策略:批改 @electron/universal 代码,反对对某些文件进行疏忽检测 hash。

import {makeUniversalApp} from 'vscode-universal';
 
await makeUniversalApp({
  x64AppPath,
  arm64AppPath,
  x64AsarPath,
  arm64AsarPath,
  filesToSkip: [
    'product.json',
    'Credits.rtf',
    'CodeResources',
    'fsevents.node',
    'Info.plist', // TODO@deepak1556: regressed with 11.4.2 internal builds
    '.npmrc',
  ],
  outAppPath,
  force: true,
});

能够看到 vscode 本人 fork 了一个 vscode-universal 包,增加了 filesToSkip 参数,用于疏忽某些文件对 hash 检测,其中就有 CodeResources

当然你可能会问,疏忽了对 CodeResources 的检测,会不会有问题,其实答案很显然,通用利用的代码签名文件其实会笼罩掉这个 CodeResources,所以不会有问题。

增加 LSRequiresNativeExecution

依据苹果官网文档的阐明,macos 零碎在运行通用利用时,会主动依据以后设施所属的架构,抉择运行正确的代码。然而在网上有看到用户的 M1 芯片的设施上,运行通用利用时未正确辨认,依然是通过 Rosetta 转译来运行利用。

所以这里能够在调用 makeUniversalApp 胜利生成通用利用后,批改利用的 Info.plist 文件,增加上 LSRequiresNativeExecution,这个能够保障不应用 Rosetta 转译,当然前提是你必须曾经确认利用能够在 Apple M1 芯片和 Intel 芯片的 macos 上失常运行。其实查看 electron 禁用在 Rosetta 上运行的 commit,能够发现也是通过增加 LSRequiresNativeExecution 来实现的。

认真查看 vscode 的代码,针对通用包也增加了 LSRequiresNativeExecution

import * as plist from 'plist';
let infoPlistString = await fs.readFile(infoPlistPath, 'utf8');
let infoPlistJson = plist.parse(infoPlistString);
Object.assign(infoPlistJson, {LSRequiresNativeExecution: true,});
await fs.writeFile(infoPlistPath, plist.build(infoPlistJson), 'utf8');

最初

欢送大家在评论区探讨,技术交换。

对酷家乐前端团队感兴趣的同学能够把简历发到我的邮箱 xinming@qunhemail.com

正文完
 0