MacOS에서 Electron Builder로 구축된 Electron 어플리케이션에 대한 공증

우리❤️ 소프트웨어 방면에서 나는 여러 해 동안 많은 플랫폼과 각종 프로그래밍 언어에서 이 일을 완성했다.최근에 나는 Electron으로 구축된 데스크톱 응용 프로그램을 개발해 왔다. 나는 전체 첫 번째 체험이 상당히 즐겁다고 말해야 한다.'조금'주목해야 할 것은 서로 다른 플랫폼(Windows, macOS)의 구축 과정인데 그 중 일부는 macOS의 응용 프로그램 공증 절차이다.탁상공론은 보기에 매우 간단해 보였는데, 나는 몇 시간과 대량의 탐정 작업을 들여서야 비로소 그것을 해냈다🕵️‍♀️.
다음은 Electron Builder(22.7.0)과 Electron Notarize(1.0.0.0)을 사용할 때 맥OS에 공증을 설치하는 단계별 안내서입니다. 제가 애플 공증 서비스와 관련된 문제를 포함한 완전한 해결 방법입니다.진짜 슈퍼히어로처럼 도와줬으면 좋겠어요.🦸🏻‍♂️, 그래서 너의 시간과 정력은 다른 더 긴박한 일에 쓸 수 있다🦾.

약간 배경이 있어요.
바로 해결하고 싶으세요?🧐? 단계 가이드로 이동합니다.
왜 또 공증을 귀찮게 합니까?맥OS(그리고 Windows)에 운영체제는 악성 소프트웨어가 기계에 설치되고 운행되는 것을 방지하기 위해 각종 안전 메커니즘을 내장하였다.macOS와 Windows는 설치 프로그램과 바이너리 파일에 유효한 인증서를 사용하여 암호화 서명을 해야 합니다.그러나 맥OS에는 압축 파일을 보내는 것과 관련된 추가 구축 시 공증 절차가 있다.ANS(Appliance Archiving Service)를 통해 애플리케이션을 검증합니다.
대부분의 경우 전체 과정은 아프지 않지만, 나의 예에서, 즉 의존항과 제3자 이진 파일이 많은 전자 응용 프로그램은 그렇게 많지 않다🤕. ANS는 ZIP 아카이브가 필요합니다.응용 프로그램 패키지는 PKZIP 2.0 프로젝트를 사용하여 압축되며 맥OS와 함께 제공되는 기본 zip 유틸리티는 Electron Enrolize가 사용하며 일반적인 zip 알고리즘의 3.0 버전이 있습니다.이 둘 사이에는 몇 가지 현저한 차이가 있습니다. 제 뜻을 이해하기 위해 수동으로 .app에 서명한 다음 다음 다음 명령을 사용하여 압축하십시오.
  • 명령행 zip 유틸리티,
  • Finder에서
  • 압축 옵션,
  • 명령행에서 공증을 제출하다.Finder에서 생성한 아카이브는 통과되고 zip 1은 실패합니다.zipinfo 명령줄 도구 표시:
  • Finder는 PKZIP 2.0 프로젝트를 사용하고 zip 3.0 버전은 일반적인 ZIP 알고리즘을 사용합니다.
  • Finder 압축의 모든 파일응용 프로그램은 이진 파일로 하고, 'zip' 은 내용 형식에 따라 (코드는 텍스트로 하고, 이진 파일은 이진 파일로 한다) 파일을 처리합니다.
  • Finder
  • Finder는 MacOS의 특정 속성을 아카이브, 특히 동적 라이브러리에 삽입하는 데 사용되는 신기한 __MACOSX 폴더를 포함합니다(예를 들어 일부 노드 모듈에서 발견).
  • 이러한 문제를 해결하는 방법은 ditto이 아닌 zip을 사용하여 .app 패키지의 압축 아카이브를 만드는 것입니다.Ditto은 macOS와 함께 제공되는 명령줄 도구로 카탈로그 복제 및 아카이브 생성/추출에 사용됩니다.Finder(PKZIP)와 같은 방안을 사용하고 메타데이터를 보존하여 애플의 서비스와 출력을 호환시킨다.이 경우 Finder의 동작을 모방하는 ditto의 옵션을 수행합니다.
  • -c-k PKZIP 압축 파일 작성,
  • —sequesterRsrc 메타데이터 저장(__MACOSX),
  • —keepParent은 부모 디렉토리 이름 소스를 아카이브에 포함합니다.
  • 전체 호출은 다음과 같습니다.
    ditto -c -k —sequesterRsrc —keepParent APP_NAME.app APP_NAME.app.zip
    
    Electron Builder의 공증 프로세스에 적용하려면 Electron 공증을 수정해야 합니다.응용 프로그램과 압축 절차를 '동상' 으로 사용합니다.이 작업은 Electron Builder 구성 파일에 정의된 "afterSign"훅을 통해 수행할 수 있습니다.
    너는 follow up essay에서 내가 왜 이런 방법을 선택했는지 이해할 수 있다.좋아했으면 좋겠어!

    해결 방법 포함 macOS 응용 프로그램 공증 설정
    시작하기 전에 먼저 code signing과 각종 지침에 따라 official documentation of Electron Builder을 정확하게 배치해야 한다.완전하게 보기 위해서, 나는 나의 경험과 다른 개발자의 뛰어난 업무에 따라 공증에 필요한 모든 절차를 열거했다.
  • Create an app-specific password은 애플 공증 서비스에 사용됩니다.개발자 Apple ID
  • 을 사용하는 것이 좋습니다.
  • 전자 애플리케이션별 권한 .plist 파일을 만듭니다.우리의 예에서 다음과 같은 내용이 작용했다(entitlements.mac.plist).
  • <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
      <dict>
        <!-- https://github.com/electron/electron-notarize#prerequisites -->
        <key>com.apple.security.cs.allow-jit</key>
        <true/>
        <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
        <true/>
        <key>com.apple.security.cs.allow-dyld-environment-variables</key>
        <true/>
        <!-- https://github.com/electron-userland/electron-builder/issues/3940 -->
        <key>com.apple.security.cs.disable-library-validation</key>
        <true/>
      </dict>
    </plist>
    
  • 은 Electron Builder 구성 파일에서 macOS build의 entitlementsentitlementInherit 옵션을 이전 단계에서 만든 .plist으로 설정합니다.
  • 에서 notarize.js 스크립트를 만들고 Electron Builder에서 .app과 그 내용을 서명한 후에 실행합니다.Electron Builder 구성 파일에 정의된 빌드 디렉토리에 파일을 배치합니다.
  • const {notarize} = require("electron-notarize");
    
    exports.default = async function notarizing(context) {
      const {electronPlatformName, appOutDir} = context;
    
      if (electronPlatformName !== "darwin") {
        return;
      }
    
      const appName = context.packager.appInfo.productFilename;
    
      return await notarize({
        appBundleId: process.env.APP_BUNDLE_ID,
        appPath: `${appOutDir}/${appName}.app`,
        appleId: process.env.APPLE_ID,
        appleIdPassword: process.env.APPLE_ID_PASSWORD,
      });
    };
    
  • Electron Builder 구성 파일에 "afterSign": "./PATH_TO_NOTARIZE_JS_IN_BUILD_DIRECTORY” 을 추가합니다.
  • 원숭이 패치 전자 공증.Electron Builder의 CLI 명령 전에 스크립트를 실행해야 합니다.우리의 예에서 우리는 유니버설 응용 프로그램 체계 구조에 대해 매우 모듈화된 방법을 취했기 때문에 구축 스크립트(TypeScript 파일)는 별도의 commons 모듈을 포함하고 이 모듈은 Electron Enjurize patcher가 가져온다..ts 파일은 다음과 같은 방법으로 ts-node을 사용할 수 있습니다.
  • ts-node -O {\"module\":\"CommonJS\"} scripts/patch-electron-notarize.ts
    
    패치 자체는 build/node_modules/electron-notarize/lib/index.js의 다음 코드를 교체하는 한 가지 작업만 수행합니다.
    spawn('zip', ['-r', '-y', zipPath, path.basename(opts.appPath)]
    
    가지다
    spawn('ditto', ['-c', '-k', '--sequesterRsrc', '--keepParent', path.basename(opts.appPath), zipPath]
    
    Dell 코드는 commons(patcher-commons.ts)입니다.
    import {promises as fsp} from "fs";
    
    export type FileContentsTransformer = (content: string) => string;
    
    export async function replaceFileContents(path: string, transformer: FileContentsTransformer) {
      let fh: fsp.FileHandle | null = null;
      let content: string = "";
    
      try {
        fh = await fsp.open(path, "r");
    
        if (fh) {
          content = (await fh.readFile()).toString();
        }
      } finally {
        if (fh) {
          await fh.close();
        }
      }
    
      try {
        fh = await fsp.open(path, "w");
    
        if (fh) {
          await fh.writeFile(transformer(content));
        }
      } finally {
        if (fh) {
          await fh.close();
        }
      }
    }
    
    및 패치(patch-electron-notarize.ts):
    import {FileContentsTransformer, replaceFileContents} from "./common";
    
    const ELECTRON_NOTARIZE_INDEX_PATH = "build/node_modules/electron-notarize/lib/index.js";
    
    async function main() {
      const transformer: FileContentsTransformer = (content: string) => {
        return content.replace(
            "spawn('zip', ['-r', '-y', zipPath, path.basename(opts.appPath)]",
            "spawn('ditto', ['-c', '-k', '--sequesterRsrc', '--keepParent', path.basename(opts.appPath), zipPath]"
        );
      };
    
      await replaceFileContents(ELECTRON_NOTARIZE_INDEX_PATH, transformer);
    }
    
    // noinspection JSIgnoredPromiseFromCall
    main();
    
  • 은 개발자 컴퓨터나 CI 환경에서 Electron Builder를 실행하기 전에 APPLE_IDAPPLE_ID_PASSWORD 환경 변수(단계 1에서 정의한 변수)를 설정합니다.너는 현지 기계에서 열쇠고리를 사용할 수 있다.
  • 거의 이렇다.너는 simple, working example을 보고 이 모든 것을 어떻게 함께 두는지 볼 수 있다.지금 너는 여분의 시간을 네가 좋아하는 일에 쓸 수 있다🏖!

    세 개 배달
  • 이 끊겼을 때 가장 예상치 못한 곳에서 근본적인 원인을 찾는다.내 프로젝트에서 절차를 줄이는 것이 의외의 주범이다.
  • 특정한 기능이나 오류 복구가 제품의 성공에 매우 중요할 때 반드시 고집을 부려야 한다.여기서 공증은 매우 중요하다. 공증은 약간의 시간을 들여 정확하지만, 최종 결과는 고객이 소프트웨어를 설치할 때 안전을 느끼는 것이다.
  • 은 때때로'일'만으로도 충분하다.나는 더 좋은 해결 방안을 생각해 낼 수 있지만, 그것은 약간의 귀중한 시간이 필요하다.나는 더욱 긴박한 문제에 관심을 가지기로 했다.
  • 댓글에서나 소셜 미디어에서나 피드백과 질문은 모두 매우 환영을 받는다🙂
    Piotr Tomiak()와 Jakub Tomanik()가 본문 초고를 읽어주셔서 감사합니다.

    도구책
  • 관련 출처: https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db.
  • GitHub Gists의 전체 코드입니다.
  • 좋은 웹페이지 즐겨찾기