Skip to content

Commit

Permalink
feat: Apple Silicon Universal Support (#5481)
Browse files Browse the repository at this point in the history
  • Loading branch information
lutzroeder authored Dec 22, 2020
1 parent 0262278 commit ca20151
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/app-builder-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"dependencies": {
"7zip-bin": "~5.0.3",
"@develar/schema-utils": "~2.6.5",
"@electron/universal": "1.0.4",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.9",
"builder-util": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions packages/app-builder-lib/scheme.json
Original file line number Diff line number Diff line change
Expand Up @@ -4960,6 +4960,7 @@
"arm64",
"armv7l",
"ia32",
"universal",
"x64"
],
"type": "string"
Expand All @@ -4971,6 +4972,7 @@
"arm64",
"armv7l",
"ia32",
"universal",
"x64"
],
"type": "string"
Expand Down
37 changes: 37 additions & 0 deletions packages/app-builder-lib/src/macPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { PkgTarget, prepareProductBuildArgs } from "./targets/pkg"
import { createCommonTarget, NoOpTarget } from "./targets/targetFactory"
import { isMacOsHighSierra } from "./util/macosVersion"
import { getTemplatePath } from "./util/pathManager"
import { promisify } from "util"

export default class MacPackager extends PlatformPackager<MacConfiguration> {
readonly codeSigningInfo = new Lazy<CodeSigningInfo>(() => {
Expand Down Expand Up @@ -91,6 +92,42 @@ export default class MacPackager extends PlatformPackager<MacConfiguration> {
}
}

protected async doPack(outDir: string, appOutDir: string, platformName: ElectronPlatformName, arch: Arch, platformSpecificBuildOptions: MacConfiguration, targets: Array<Target>): Promise<any> {
switch (arch) {
default: {
return super.doPack(outDir, appOutDir, this.platform.nodeName as ElectronPlatformName, arch, this.platformSpecificBuildOptions, targets);
}
case Arch.universal: {
const x64Arch = Arch.x64;
const x64AppOutDir = appOutDir + '-' + Arch[x64Arch];
await super.doPack(outDir, x64AppOutDir, platformName, x64Arch, platformSpecificBuildOptions, targets, false);
const arm64Arch = Arch.arm64;
const arm64AppOutPath = appOutDir + '-' + Arch[arm64Arch];
await super.doPack(outDir, arm64AppOutPath, platformName, arm64Arch, platformSpecificBuildOptions, targets, false);
const framework = this.info.framework
log.info({
platform: platformName,
arch: Arch[arch],
[`${framework.name}`]: framework.version,
appOutDir: log.filePath(appOutDir),
}, `packaging`)
const appFile = `${this.appInfo.productFilename}.app`;
const { makeUniversalApp } = require('@electron/universal');
await makeUniversalApp({
x64AppPath: path.join(x64AppOutDir, appFile),
arm64AppPath: path.join(arm64AppOutPath, appFile),
outAppPath: path.join(appOutDir, appFile),
force: true
});
const rmdir = promisify(require('fs').rmdir);
await rmdir(x64AppOutDir, { recursive: true });
await rmdir(arm64AppOutPath, { recursive: true });
await this.doSignAfterPack(outDir, appOutDir, platformName, arch, platformSpecificBuildOptions, targets);
break;
}
}
}

async pack(outDir: string, arch: Arch, targets: Array<Target>, taskManager: AsyncTaskManager): Promise<any> {
let nonMasPromise: Promise<any> | null = null

Expand Down
8 changes: 1 addition & 7 deletions packages/app-builder-lib/src/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,12 +427,6 @@ export class Packager {
break
}

await this.installAppDependencies(platform, arch)

if (this.cancellationToken.cancelled) {
break
}

// support os and arch macro in output value
const outDir = path.resolve(this.projectDir, packager.expandMacro(this._configuration!!.directories!!.output!!, Arch[arch]))
const targetList = createTargets(nameToTarget, targetNames.length === 0 ? packager.defaultTarget : targetNames, outDir, packager)
Expand Down Expand Up @@ -477,7 +471,7 @@ export class Packager {
}
}

private async installAppDependencies(platform: Platform, arch: Arch): Promise<any> {
public async installAppDependencies(platform: Platform, arch: Arch): Promise<any> {
if (this.options.prepackaged != null || this.framework.isNpmRebuildRequired !== true) {
return
}
Expand Down
33 changes: 29 additions & 4 deletions packages/app-builder-lib/src/platformPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,21 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>
}
}

protected async doPack(outDir: string, appOutDir: string, platformName: ElectronPlatformName, arch: Arch, platformSpecificBuildOptions: DC, targets: Array<Target>) {
protected async doPack(outDir: string, appOutDir: string, platformName: ElectronPlatformName, arch: Arch, platformSpecificBuildOptions: DC, targets: Array<Target>, sign: boolean = true) {
if (this.packagerOptions.prepackaged != null) {
return
}

if (this.info.cancellationToken.cancelled) {
return
}

await this.info.installAppDependencies(this.platform, arch);

if (this.info.cancellationToken.cancelled) {
return
}

const framework = this.info.framework
log.info({
platform: platformName,
Expand Down Expand Up @@ -241,11 +251,26 @@ export abstract class PlatformPackager<DC extends PlatformSpecificBuildOptions>

const isAsar = asarOptions != null
await this.sanityCheckPackage(appOutDir, isAsar, framework)
await this.signApp(packContext, isAsar)
if (sign) {
await this.doSignAfterPack(outDir, appOutDir, platformName, arch, platformSpecificBuildOptions, targets);
}
}

const afterSign = resolveFunction(this.config.afterSign, "afterSign")
protected async doSignAfterPack(outDir: string, appOutDir: string, platformName: ElectronPlatformName, arch: Arch, platformSpecificBuildOptions: DC, targets: Array<Target>) {
const asarOptions = await this.computeAsarOptions(platformSpecificBuildOptions);
const isAsar = asarOptions != null;
const packContext = {
appOutDir,
outDir,
arch,
targets,
packager: this,
electronPlatformName: platformName
};
await this.signApp(packContext, isAsar);
const afterSign = resolveFunction(this.config.afterSign, "afterSign");
if (afterSign != null) {
await Promise.resolve(afterSign(packContext))
await Promise.resolve(afterSign(packContext));
}
}

Expand Down
7 changes: 4 additions & 3 deletions packages/builder-util/src/arch.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export enum Arch {
ia32, x64, armv7l, arm64
ia32, x64, armv7l, arm64, universal
}

export type ArchType = "x64" | "ia32" | "armv7l" | "arm64"
export type ArchType = "x64" | "ia32" | "armv7l" | "arm64" | "universal"

export function toLinuxArchString(arch: Arch, targetName: string): string {
switch (arch) {
Expand Down Expand Up @@ -38,7 +38,8 @@ export function archFromString(name: string): Arch {
return Arch.arm64
case "armv7l":
return Arch.armv7l

case "universal":
return Arch.universal
default:
throw new Error(`Unsupported arch ${name}`)
}
Expand Down
12 changes: 11 additions & 1 deletion packages/electron-builder/src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface CliOptions extends PackagerOptions, PublishOptions {
ia32?: boolean
armv7l?: boolean
arm64?: boolean
universal?: boolean

dir?: boolean
}
Expand Down Expand Up @@ -46,6 +47,9 @@ export function normalizeOptions(args: CliOptions): BuildOptions {
if (args.ia32) {
result.push(Arch.ia32)
}
if (args.universal) {
result.push(Arch.universal)
}

return result.length === 0 && currentIfNotSpecified ? [archFromString(process.arch)] : result
}
Expand Down Expand Up @@ -120,6 +124,7 @@ export function normalizeOptions(args: CliOptions): BuildOptions {
delete result.x64
delete result.armv7l
delete result.arm64
delete result.universal

let config = result.config

Expand Down Expand Up @@ -198,7 +203,7 @@ export function coerceTypes(host: any): any {
export function createTargets(platforms: Array<Platform>, type?: string | null, arch?: string | null): Map<Platform, Map<Arch, Array<string>>> {
const targets = new Map<Platform, Map<Arch, Array<string>>>()
for (const platform of platforms) {
const archs = (arch === "all" ? (platform === Platform.MAC ? [Arch.x64, Arch.arm64] : [Arch.x64, Arch.ia32]) : [archFromString(arch == null ? process.arch : arch)])
const archs = (arch === "all" ? (platform === Platform.MAC ? [Arch.x64, Arch.arm64, Arch.universal] : [Arch.x64, Arch.ia32]) : [archFromString(arch == null ? process.arch : arch)])
const archToType = new Map<Arch, Array<string>>()
targets.set(platform, archToType)

Expand Down Expand Up @@ -259,6 +264,11 @@ export function configureBuildCommand(yargs: yargs.Argv): yargs.Argv {
description: "Build for arm64",
type: "boolean",
})
.option("universal", {
group: buildGroup,
description: "Build for universal",
type: "boolean",
})
.option("dir", {
group: buildGroup,
description: "Build unpacked dir. Useful to test.",
Expand Down
35 changes: 35 additions & 0 deletions test/snapshots/mac/macPackagerTest.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ Object {
"size": "@size",
},
},
Object {
"arch": "universal",
"file": "TestApp-1.1.0-mac-universal.dmg",
"updateInfo": Object {
"sha512": "@sha512",
"size": "@size",
},
},
Object {
"file": "TestApp-1.1.0-mac-universal.dmg.blockmap",
"updateInfo": Object {
"sha512": "@sha512",
"size": "@size",
},
},
Object {
"arch": "x64",
"file": "TestApp-1.1.0-mac.dmg",
Expand Down Expand Up @@ -176,6 +191,12 @@ Object {
"size": "@size",
"url": "TestApp-1.1.0-mac-arm64.zip",
},
Object {
"blockMapSize": "@blockMapSize",
"sha512": "@sha512",
"size": "@size",
"url": "TestApp-1.1.0-mac-universal.zip",
},
Object {
"sha512": "@sha512",
"size": "@size",
Expand All @@ -186,6 +207,11 @@ Object {
"size": "@size",
"url": "TestApp-1.1.0-mac-arm64.dmg",
},
Object {
"sha512": "@sha512",
"size": "@size",
"url": "TestApp-1.1.0-mac-universal.dmg",
},
],
"path": "TestApp-1.1.0-mac.zip",
"releaseDate": "@releaseDate",
Expand All @@ -202,6 +228,15 @@ Object {
"size": "@size",
},
},
Object {
"arch": "universal",
"file": "TestApp-1.1.0-mac-universal.zip",
"updateInfo": Object {
"blockMapSize": "@blockMapSize",
"sha512": "@sha512",
"size": "@size",
},
},
Object {
"arch": "x64",
"file": "TestApp-1.1.0-mac.zip",
Expand Down
Loading

0 comments on commit ca20151

Please sign in to comment.