Original address:
https://webfe.kujiale.com/ele…


Kujia client: download address
https://www.kujiale.com/activ…

An overview of the

Currently, there are two architecture chips in MacBook, x86 and ARM architecture, which correspond to Intel chip and Apple M1 chip.

The old version of the Kujia client was run on MacBook devices with an M1 chip through Rosetta 2. After the new version 12.2.0, Kujia client natively supports M1 chip. This article mainly explains how Kujia client natively supports M1 chip.

Noun explanation

Kuknorr Client: Kuknorr’s official desktop client based on Electron, supporting Windows and MacOS.

Rosetta: Apple’s tool for translating apps. Rosetta was originally designed to translate PowerPC applications into Intel applications. This time, Apple released Rosetta 2, which translates Intel applications into applications that run on ARM based M1 chips (related documentation: https://zh.wikipedia.org/wiki… , https://support.apple.com/zh-.)

Why do I need to support M1 chips

Looking back at Apple’s last chip architecture replacement, which was the switch from PowerPC to Intel x86, Rosetta was installed by default for translation in 2005 at the beginning, but it was not installed by default in 2009, and by 2011 it was not supported at all.

Rosetta 2 will not be available by default in 3 or 4 years, and will not be supported at all in 5 or 6 years, so support for M1 chips must be done.

The x64 installation package

The previously released MacOS installer for the Kukler client was built for x64 and runs through Rosetta.

However, it should be noted that the release of Electron from 2020.7.22 to 2020.11.19 completely disabled Electron running on Rosetta (related PR) due to the Chromium crash issue. Because Kujia client V8.2.3 is not within this time, it can be used normally.

Of course you might be wondering if there was a Chromium crash on the Electron version that didn’t disable Rosetta? According to my actual tests, V8.2.3 of the Kukler client works fine on Rosetta. In fact, if you look closely at the discussion in the issue about the Chromium crash, someone mentioned that the Rosetta on the final production Mac should not have this crash issue (comment).

ARM64 installation package

According to the Electron blog post, as of v11.0.0, Electron has support for building Darwin-ARM64 applications that can run directly on an M1 chip machine without Rosetta translation.

electron-packager

The build tool used by the Kujia clientelectron-packager, also supports building the DARWIN-ARM64 installation package. You just need to package the ones in the parametersplatformValue is set todarwin.archValue is set toarm64Can.

electron-builder

Electron-Builder, another popular packaging tool in the community, is availablearchValue is set toarm64.

Support for Intel and Apple M1 common applications

You can now package the x64 and ARM64 MacOS installers separately for distribution to users. But split into two packages has an understanding cost to the user, who may not even know which one he should install. And for updates to be pushed to users, you also need to handle the installation and download logic of both packages, so there is a need to make a universal application.

Universal applications, as the name implies, are applications that can run natively on both Intel and Apple M1 chips. In this way, the user only needs to install the universal app, and the update push only needs to push the universal app, which can seamlessly replace the previously installed non-universal app. The downside, of course, is that by merging the two applications, the size of the package has nearly doubled.

Building Universal Applications

electron-builder

If you are using Electron-Builder, you can set the arch value to universal.

electron-packager

If you use Electron-packager like the Kukler client and VScode, then you need to use Electron-packager to build x64 and ARM64 applications respectively. Then combine the x64 and ARM64 applications into a generic application using the Electron official build tool @Electron /universal.

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',
});

The actual use of the pit

Hash detection reports an error

When we actually use @electron/universal, hash detection returns an error:

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

As you can see, all non-binary files are hashed.

This is because for binaries, general-purpose binaries can be generated using the LIPO command-line tool. As opposed to binary files, only one copy must be kept for the final universal application, so you need to make sure that the hash is consistent, so that the file in the universal application is the same as the file in the x64 and arm64 applications before they were built.

But you can see from the error messages that there is a problem with the Coderesources, which is generated by the code signatures, and of course the hash is inconsistent. In this case, the solution is not to sign the X64 and ARM64, but to sign the general application after the generation of the general application, which is also the strategy of Electron-Builder.

In addition to skipping the x64 & arm64 signature, I found another strategy in the vscode code: modify the @electron/universal code to support ignoring the detection hash for some files.

import { makeUniversalApp } from 'vscode-universal'; await makeUniversalApp({ x64AppPath, arm64AppPath, x64AsarPath, arm64AsarPath, filesToSkip: [ 'product.json', 'Credits.rtf', 'CodeResources', 'fsevents.node', 'Info.plist', // TODO@deepak1556: Packaged masculinity with 11.4.2 Internal Builds '. NPMRC ',], Outapppath, force: true,});

You can see that VS Code itself forks a VS Code-universal package and adds a FileStoskip parameter to ignore certain files for hash detection, where there are Coderesources.

And of course you might say is there a problem if you ignore the Coderesources, and the answer is pretty obvious, the code signature files of the general application will override that Coderesources, so there will be no problem.

Add LSRequiresNativeExecution

According to Apple’s official documentation, when running common applications, the MacOS system automatically selects the correct code to run, based on the architecture of the current device. But on devices that see the user’s M1 chip on the web, running the generic application is not correctly identified, and still runs the application through Rosetta Translate.

So it can be invoked in makeUniversalApp successfully generate universal application, modify the application Info. The file, add LSRequiresNativeExecution, this can guarantee not to use Rosetta translation, Of course, you have to confirm that the application will run on Apple M1 and Intel MacOS. Actually see the electron disable run on Rosetta commit, also can be found by adding LSRequiresNativeExecution.

Take a closer look at vscode code, in view of the general package also added 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');

The last

You are welcome to discuss in the comments section.

If you are interested in our front end team, please send your resume to me at [email protected]