Electron 문서1.4.1

Docs / All

Accelerator

키보드 단축키를 정의합니다.

Accelerator는 + 문자를 통해 여러 혼합키와 키코드를 결합할 수 있습니다.

예시:

플랫폼에 관련하여 주의할 점

Linux와 Windows에서는 Command키가 없으므로 작동하지 않습니다. 대신에 CommandOrControl을 사용하면 macOS의 Command와 Linux, Windows의 Control 모두 지원할 수 있습니다.

Option 대신 Alt을 사용하는게 좋습니다. Option 키는 macOS에만 있으므로 모든 플랫폼에서 사용할 수 있는 Alt 키를 권장합니다.

Super키는 Windows와 Linux 에서는 윈도우키를, macOS에서는 Cmd키로 맵핑됩니다.

사용 가능한 혼합키

사용 가능한 전체 키코드

키코드는 단축어로도 사용할 수 있습니다


app

애플리케이션의 이벤트 생명주기를 제어합니다.

밑의 예시는 마지막 윈도우가 종료되었을 때, 애플리케이션을 종료시키는 예시입니다:

const {app} = require('electron')
app.on('window-all-closed', () => {
  app.quit()
})

Events

app 객체는 다음과 같은 이벤트를 가지고 있습니다:

Event: ‘will-finish-launching’

애플리케이션이 기본적인 시작 준비를 마치면 발생하는 이벤트입니다. Windows, Linux 운영체제에서의 will-finish-launching 이벤트는 ready 이벤트와 동일합니다. macOS에서의 이벤트는 NSApplicationapplicationWillFinishLaunching에 대한 알림으로 표현됩니다. 대개 이곳에서 open-fileopen-url 이벤트 리스너를 설정하고 crash reporter와 auto updater를 시작합니다.

대부분의 경우, 모든 것을 ready 이벤트 핸들러 안에서 해결해야 합니다.

Event: ‘ready’

Returns:

Electron이 초기화를 끝냈을 때 발생하는 이벤트입니다.

Event: ‘window-all-closed’

모든 윈도우가 종료되었을 때 발생하는 이벤트입니다.

만약 이 이벤트를 구독하지 않은 상태로 모든 윈도우가 닫혔을 때의 기본 동작은 앱을 종료하는 것입니다. 하지만, 이 이벤트를 구독하면, 앱을 종료할지 다른 일을 할지 제어할 수 있습니다. 만약 사용자가 Cmd + Q를 입력했거나 개발자가 app.quit()를 호출했다면, Electron은 먼저 모든 윈도우의 종료를 시도하고 will-quit 이벤트를 발생시킵니다. 그리고 will-quit 이벤트가 발생했을 땐 window-all-closed 이벤트가 발생하지 않습니다.

역자주: 이 이벤트는 말 그대로 현재 애플리케이션에서 윈도우만 완전히 종료됬을 때 발생하는 이벤트입니다. 따라서 애플리케이션을 완전히 종료하려면 이 이벤트에서 app.quit()를 호출해 주어야 합니다.

Event: ‘before-quit’

Returns:

애플리케이션 윈도우들이 닫히기 시작할 때 발생하는 이벤트입니다. event.preventDefault() 호출은 이벤트의 기본 동작을 방지하기 때문에 이를 통해 애플리케이션의 종료를 방지할 수 있습니다.

Event: ‘will-quit’

Returns:

모든 윈도우들이 종료되고 애플리케이션이 종료되기 시작할 때 발생하는 이벤트입니다. event.preventDefault() 호출을 통해 애플리케이션의 종료를 방지할 수 있습니다.

will-quitwindow-all-closed 이벤트의 차이점을 확인하려면 window-all-closed 이벤트의 설명을 참고하세요.

Event: ‘quit’

Returns:

애플리케이션이 종료될 때 발생하는 이벤트입니다.

Event: ‘open-file’ macOS

Returns:

사용자가 애플리케이션을 통해 파일을 열고자 할 때 발생하는 이벤트입니다.

open-file 이벤트는 보통 애플리케이션이 열려 있을 때 OS가 파일을 열기 위해 애플리케이션을 재사용할 때 발생합니다. 이 이벤트는 파일을 dock에 떨어트릴 때, 애플리케이션이 실행되기 전에도 발생합니다. 따라서 이 이벤트를 제대로 처리하려면 open-file 이벤트 핸들러를 애플리케이션이 시작하기 전에 등록해 놓았는지 확실히 확인해야 합니다. (ready 이벤트가 발생하기 전에)

이 이벤트를 처리할 땐 반드시 event.preventDefault()를 호출해야 합니다.

Windows에선 process.argv (메인 프로세스에서)를 통해 파일 경로를 얻을 수 있습니다.

Event: ‘open-url’ macOS

Returns:

유저가 애플리케이션을 통해 URL을 열고자 할 때 발생하는 이벤트입니다. 애플리케이션에서 URL을 열기 위해 반드시 URL 스킴이 등록되어 있어야 합니다.

이 이벤트를 처리할 땐 반드시 event.preventDefault()를 호출해야 합니다.

Event: ‘activate’ macOS

Returns:

애플리케이션이 활성화 되었을 때 발생하는 이벤트입니다. 이 이벤트는 사용자가 애플리케이션의 dock 아이콘을 클릭했을 때 주로 발생합니다.

Event: ‘continue-activity’ macOS

Returns:

다른 기기에서 받아온 activity를 재개하려고 할 때 Handoff 하는 동안 발생하는 이벤트입니다. 이 이벤트를 처리하려면 반드시 event.preventDefault()를 호출해야 합니다.

사용자 activity는 activity의 소스 애플리케이션과 같은 개발자 팀 ID를 가지는 애플리케이션 안에서만 재개될 수 있고, activity의 타입을 지원합니다. 지원하는 activity의 타입은 애플리케이션 Info.plistNSUserActivityTypes 키에 열거되어 있습니다.

Event: ‘browser-window-blur’

Returns:

browserWindow에 대한 포커스가 사라졌을 때 발생하는 이벤트입니다.

Event: ‘browser-window-focus’

Returns:

browserWindow에 대한 포커스가 발생했을 때 발생하는 이벤트입니다.

역자주: 포커스 는 창을 클릭해서 활성화 시켰을 때를 말합니다.

Event: ‘browser-window-created’

Returns:

새로운 browserWindow가 생성되었을 때 발생하는 이벤트입니다.

Event: ‘web-contents-created’

Returns:

새로운 webContents가 생성되었을 때 발생하는 이벤트입니다.

Event: ‘certificate-error’

Returns:

url에 대한 certificate 인증서의 유효성 검증에 실패했을 때 발생하는 이벤트입니다. 인증서를 신뢰한다면 event.preventDefault()callback(true)를 호출하여 기본 동작을 방지하고 인증을 승인할 수 있습니다.

const {app} = require('electron')

app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
  if (url === 'https://github.com') {
    // 확인 로직.
    event.preventDefault()
    callback(true)
  } else {
    callback(false)
  }
})

Event: ‘select-client-certificate’

Returns:

클라이언트 인증이 요청되었을 때 발생하는 이벤트입니다.

url은 클라이언트 인증서를 요청하는 탐색 항목에 해당합니다. 그리고 callback은 목록에서 필터링된 항목과 함께 호출될 필요가 있습니다. 이 이벤트에서의 event.preventDefault() 호출은 초기 인증 때 저장된 데이터를 사용하는 것을 막습니다.

const {app} = require('electron')

app.on('select-client-certificate', (event, webContents, url, list, callback) => {
  event.preventDefault()
  callback(list[0])
})

Event: ‘login’

Returns:

webContents가 기본 인증을 요청할 때 발생하는 이벤트입니다.

기본 동작은 인증 요청을 모두 취소시킵니다. 동작을 새로 정의하려면 반드시 event.preventDefault()를 호출한 후 callback(username, password) 형태의 콜백을 호출하여 인증을 처리해야 합니다.

const {app} = require('electron')

app.on('login', (event, webContents, request, authInfo, callback) => {
  event.preventDefault()
  callback('username', 'secret')
})

Event: ‘gpu-process-crashed’

Returns:

GPU 처리가 충돌하거나 종료되었을 때 발생하는 이벤트입니다.

Event: ‘accessibility-support-changed’ macOS Windows

Returns:

Chrome의 접근성 지원이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 스크린 리더와 같은 접근성 기술이 활성화되거나 비활성화될 때 발생합니다. 자세한 내용은 https://www.chromium.org/developers/design-documents/accessibility 를 참고하세요.

Methods

app 객체는 다음과 같은 메서드를 가지고 있습니다:

참고: 몇몇 메서드는 특정 플랫폼에서만 작동합니다.

app.quit()

모든 윈도우 종료를 시도합니다. before-quit 이벤트가 먼저 발생합니다. 모든 윈도우가 성공적으로 종료되면 will-quit 이벤트가 발생하고 기본 동작에 따라 애플리케이션이 종료됩니다.

이 함수는 모든 beforeunloadunload 이벤트 핸들러가 제대로 실행됨을 보장합니다. beforeunload 이벤트 핸들러에서 false를 반환했을 때 윈도우 종료가 취소 될 수 있습니다.

app.exit(exitCode)

exitCode와 함께 애플리케이션을 즉시 종료합니다.

모든 윈도우는 사용자의 동의 여부에 상관없이 즉시 종료되며 before-quit 이벤트와 will-quit 이벤트가 발생하지 않습니다.

app.relaunch([options])

현재 인스턴스가 종료되면 애플리케이션을 재시작합니다.

기본적으로 새 인스턴스는 같은 작업 디렉토리의 것과 함께 현재 인스턴스의 명령줄 인수를 사용합니다. 만약 args가 지정되면, args가 기본 명령줄 인수 대신에 전달됩니다. execPath가 지정되면, 현재 애플리케이션 대신 execPath가 실행됩니다.

참고로 이 메서드는 애플리케이션을 종료하지 않으며, 애플리케이션을 다시 시작시키려면 app.relaunch를 호출한 후 app.quit 또는 app.exit를 실행해주어야 합니다.

app.relaunch가 여러 번 호출되면, 현재 인스턴스가 종료된 후 여러 인스턴스가 시작됩니다.

다음은 현재 인스턴스를 즉시 종료시킨 후 새로운 명령줄 인수를 추가하여 새 인스턴스의 애플리케이션을 실행하는 예시입니다:

const {app} = require('electron')

app.relaunch({args: process.argv.slice(1).concat(['--relaunch'])})
app.exit(0)

app.isReady()

Returns Boolean - Electron 이 초기화를 마쳤으면 true, 아니면 false.

app.focus()

Linux에선, 첫 번째로 보여지는 윈도우가 포커스됩니다. macOS에선, 애플리케이션을 활성화 앱 상태로 만듭니다. Windows에선, 애플리케이션의 첫 윈도우에 포커스 됩니다.

app.hide() macOS

최소화를 하지 않고 애플리케이션의 모든 윈도우들을 숨깁니다.

app.show() macOS

숨긴 애플리케이션 윈도우들을 다시 보이게 만듭니다. 자동으로 포커스되지 않습니다.

app.getAppPath()

Returns String - 현재 애플리케이션 디렉토리.

app.getPath(name)

Returns String -name 에 관련한 특정 디렉터리 또는 파일의 경로. 실패시 Error 발생.

역자주: 이 메서드는 운영체제에서 지정한 특수 디렉터리를 가져오는데 사용할 수 있습니다.

name은 다음 목록에 있는 경로 중 하나를 선택해 사용할 수 있습니다:

app.setPath(name, path)

name에 대한 특정 디렉터리나 파일의 경로인 path를 재정의합니다. 만약 지정한 디렉터리의 경로가 존재하지 않으면 디렉터리가 이 메서드를 통해 새로 생성됩니다. 재정의에 실패했을 땐 Error를 반환합니다.

이 메서드는 app.getPath에 정의되어 있는 name의 경로만 재정의할 수 있습니다.

기본적으로, 웹 페이지의 쿠키와 캐시는 userData 디렉터리에 저장됩니다. 만약 이 위치를 변경하고자 한다면, 반드시 app 모듈의 ready 이벤트가 발생하기 전에 userData 경로를 재정의해야 합니다.

app.getVersion()

Returns String - 로드된 애플리케이션의 버전. 만약 package.json 파일에서 애플리케이션의 버전을 찾을 수 없는 경우, 현재 번들 또는 실행 파일의 버전을 반환합니다.

app.getName()

Returns String - package.json 에 기술된 현재 애플리케이션의 이름.

npm 모듈 규칙에 따라 대부분의 경우 package.jsonname 필드는 소문자 이름을 사용합니다. 하지만 Electron은 name대신 productName 필드를 주로 사용하기 때문에 반드시 이 필드도 같이 지정해야 합니다. 이 필드는 맨 앞글자가 대문자인 애플리케이션 전체 이름을 지정해야 합니다.

app.setName(name)

현재 애플리케이션의 이름을 덮어씌웁니다.

app.getLocale()

Returns String - 현재 애플리케이션의 로케일. 반환될 수 있는 값은 여기에서 찾아볼 수 있습니다.

참고: 패키징된 앱을 배포할 때, locales 폴더도 같이 배포해야 합니다.

참고: Windows에선 ready 이벤트가 발생한 이후에 이 메서드를 호출해야 합니다.

app.addRecentDocument(path) macOS Windows

최근 문서 목록에 path를 추가합니다.

이 목록은 OS에 의해 관리됩니다. 최근 문서 목록은 Windows의 경우 작업 표시줄에서 찾을 수 있고, macOS의 경우 dock 메뉴에서 찾을 수 있습니다.

app.clearRecentDocuments() macOS Windows

최근 문서 목록을 모두 비웁니다.

app.setAsDefaultProtocolClient(protocol[, path, args]) macOS Windows

Returns Boolean - 호출 성공 여부.

이 메서드는 지정한 프로토콜(URI scheme)에 대해 현재 실행파일을 기본 핸들러로 등록합니다. 이를 통해 운영체제와 더 가깝게 통합할 수 있습니다. 한 번 등록되면, your-protocol://과 같은 모든 링크에 대해 호출시 현재 실행 파일이 실행됩니다. 모든 링크, 프로토콜을 포함하여 애플리케이션의 인수로 전달됩니다.

Windows에선 실행시에 선택적 매개변수를 통해 경로, 실행 파일, 인수, 실행 파일로 전달될 인수의 배열을 제공할 수 있습니다.

참고: macOS에선, 애플리케이션의 info.plist에 등록해둔 프로토콜만 사용할 수 있습니다. 이는 런타임에서 변경될 수 없습니다. 이 파일은 간단히 텍스트 에디터를 사용하거나, 애플리케이션을 빌드할 때 스크립트가 생성되도록 할 수 있습니다. 자세한 내용은 Apple의 참조 문서를 확인하세요.

이 API는 내부적으로 Windows 레지스트리와 LSSetDefaultHandlerForURLScheme를 사용합니다.

호출에 성공하면 true를 반환하고 그렇지 않다면 false를 반환합니다.

app.removeAsDefaultProtocolClient(protocol[, path, args]) macOS Windows

Returns Boolean - 호출 성공 여부.

이 메서드는 현재 실행파일이 지정한 프로토콜(URI scheme)에 대해 기본 핸들러인지를 확인합니다. 만약 그렇다면, 이 메서드는 앱을 기본 핸들러에서 제거합니다.

app.isDefaultProtocolClient(protocol[, path, args]) macOS Windows

Returns Boolean

이 메서드는 현재 실행 파일이 지정한 프로토콜에 대해 기본 동작인지 확인합니다. (URI 스킴) 만약 그렇다면 true를 반환하고 아닌 경우 false를 반환합니다.

참고: macOS에선, 응용 프로그램이 프로토콜에 대한 기본 프로토콜 동작으로 등록되었는지를 확인하기 위해 이 메서드를 사용할 수 있습니다. 또한 macOS에서 ~/Library/Preferences/com.apple.LaunchServices.plist를 확인하여 검증할 수도 있습니다. 자세한 내용은 Apple의 참조 문서를 참고하세요.

이 API는 내부적으로 Windows 레지스트리와 LSSetDefaultHandlerForURLScheme를 사용합니다.

app.setUserTasks(tasks) Windows

Windows에서 사용할 수 있는 JumpList의 Tasks 카테고리에 task를 추가합니다.

tasks는 다음과 같은 구조를 가지는 Task 객체의 배열입니다:

Task Object:

Returns Boolean - 호출 성공 여부.

참고: 점프 목록을 커스터마이징 하려면 대신 app.setJumpList(categories) 를 사용하세요.

app.getJumpListSettings() Windows

Returns Object: * minItems Integer - 점프 목록에서 보여질 항목의 최소 수 (이 값에 대한 자세한 설명은 MSDN 문서)를 보세요. * removedItems JumpListItem[] - 점프 목록의 사용자 정의 카테고리에서 사용자가 삭제한 항목에 해당하는 JumpListItem 객체 배열. 이 항목들은 다음 app.setJumpList() 호출로 다시 추가하면 안됩니다. 윈도우는 삭제된 항목을 포함하는 카테고리를 표시하지 않을 것 입니다.

app.setJumpList(categories) Windows

애플리케이션에 사용자 정의 점프 목록을 설정하거나 삭제하고 다음 문자열 중 하나를 반환:

만약 categoriesnull 이면 이전 사용자 점프 목록 설정은 앱을 위한 표준 점프 목록으로 대체됩니다 (윈도우에 의해 관리됨).

JumpListCategory 객체는 다음 속성을 가져야 합니다:

참고: JumpListCategory 객체가 type, name 속성 둘 다 없다면 typetasks 로 가정합니다. name 속성이 설정되었지만 type 속성이 생략된 경우 typecustom 으로 가정합니다.

참고: 사용자는 사용자 카테고리에서 항목을 삭제할 수 있습니다. 그리고 윈도우는 app.setJumpList(categories) 의 다음 성공적인 호출 이후까지 삭제된 항목을 다시 추가하는 것을 금지할 것 입니다. 그 이전에 커스텀 카테고리에 삭제된 항목을 다시 추가하려 한다면 커스텀 카테고리가 전부 점프 목록에서 빠질 것 입니다. 제거된 항목 목록은 app.getJumpListSettings() 를 사용해 얻을 수 있습니다.

JumpListItem 객체는 다음 속성을 가져야 합니다:

사용자 점프 목록을 생성하는 간단한 예제 입니다:

const {app} = require('electron')

app.setJumpList([
  {
    type: 'custom',
    name: 'Recent Projects',
    items: [
      { type: 'file', path: 'C:\\Projects\\project1.proj' },
      { type: 'file', path: 'C:\\Projects\\project2.proj' }
    ]
  },
  { // has a name so `type` is assumed to be "custom"
    name: 'Tools',
    items: [
      {
        type: 'task',
        title: 'Tool A',
        program: process.execPath,
        args: '--run-tool-a',
        icon: process.execPath,
        iconIndex: 0,
        description: 'Runs Tool A'
      },
      {
        type: 'task',
        title: 'Tool B',
        program: process.execPath,
        args: '--run-tool-b',
        icon: process.execPath,
        iconIndex: 0,
        description: 'Runs Tool B'
      }
    ]
  },
  { type: 'frequent' },
  { // has no name and no type so `type` is assumed to be "tasks"
    items: [
      {
        type: 'task',
        title: 'New Project',
        program: process.execPath,
        args: '--new-project',
        description: 'Create a new project.'
      },
      { type: 'separator' },
      {
        type: 'task',
        title: 'Recover Project',
        program: process.execPath,
        args: '--recover-project',
        description: 'Recover Project'
      }
    ]
  }
])

app.makeSingleInstance(callback)

현재 애플리케이션을 단일 인스턴스 애플리케이션으로 만들어줍니다. 이 메서드는 애플리케이션이 여러 번 실행됐을 때 다중 인스턴스가 생성되는 대신 한 개의 주 인스턴스만 유지되도록 만들 수 있습니다. 이때 중복 생성된 인스턴스는 주 인스턴스에 신호를 보내고 종료됩니다.

callback은 주 인스턴스가 생성된 이후 또 다른 인스턴스가 생성됐을 때 callback(argv, workingDirectory) 형식으로 호출됩니다. argv는 두 번째 인스턴스의 명령줄 인수이며 workingDirectory는 현재 작업중인 디렉터리입니다. 보통 대부분의 애플리케이션은 이러한 콜백이 호출될 때 주 윈도우를 포커스하고 최소화되어있으면 창 복구를 실행합니다.

callbackappready 이벤트가 발생한 후 실행됨을 보장합니다.

이 메서드는 현재 실행된 애플리케이션이 주 인스턴스인 경우 false를 반환하고 애플리케이션의 로드가 계속 진행 되도록 합니다. 그리고 두 번째 중복된 인스턴스 생성인 경우 true를 반환합니다. (다른 인스턴스에 인수가 전달됬을 때) 이 불리언 값을 통해 중복 생성된 인스턴스는 즉시 종료시켜야 합니다.

macOS에선 사용자가 Finder에서 애플리케이션의 두 번째 인스턴스를 열려고 했을 때 자동으로 단일 인스턴스화 하고 open-fileopen-url 이벤트를 발생시킵니다. 그러나 사용자가 애플리케이션을 CLI 터미널에서 실행하면 운영체제 시스템의 싱글 인스턴스 메커니즘이 무시되며 그대로 중복 실행됩니다. 따라서 macOS에서도 이 메서드를 통해 확실히 중복 실행을 방지하는 것이 좋습니다.

다음 예시는 두 번째 인스턴스가 생성되었을 때 중복된 인스턴스를 종료하고 주 애플리케이션 인스턴스의 윈도우를 활성화 시키는 예시입니다:

const {app} = require('electron')
let myWindow = null

const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => {
  // 애플리케이션을 중복 실행했습니다. 주 애플리케이션 인스턴스를 활성화 합니다.
  if (myWindow) {
    if (myWindow.isMinimized()) myWindow.restore()
    myWindow.focus()
  }
})

if (shouldQuit) {
  app.quit()
}

// 윈도우를 생성하고 각종 리소스를 로드하고 작업합니다.
app.on('ready', () => {
})

app.releaseSingleInstance()

모든 makeSingleInstance에 의해 생성된 제한을 해제합니다. 이 메서드는 다시 여러 인스턴스의 애플리케이션이 나란히 실행될 수 있도록 합니다.

app.setUserActivity(type, userInfo[, webpageURL]) macOS

NSUserActivity를 만들고 현재 activity에 설정합니다. 이 activity는 이후 다른 기기와 Handoff할 때 자격으로 사용됩니다.

app.getCurrentActivityType() macOS

Returns String - 현재 작동중인 activity의 타입.

app.setAppUserModelId(id) Windows

애플리케이션의 사용자 모델 IDid로 변경합니다.

app.importCertificate(options, callback) LINUX

pkcs12 형식으로된 인증서를 플랫폼 인증서 저장소로 가져옵니다. callback은 가져오기의 결과를 포함하는 result 객체를 포함하여 호출됩니다. 값이 0 일 경우 성공을 의미하며 다른 값은 모두 Chrominum의 net_error_list에 따라 실패를 의미합니다.

app.disableHardwareAcceleration()

현재 애플리케이션의 하드웨어 가속을 비활성화합니다.

이 메서드는 appready 이벤트가 발생하기 전에만 호출할 수 있습니다.

app.setBadgeCount(count) Linux macOS

Returns Boolean - 호출 성공 여부.

현재 앱에 대해 카운터 뱃지를 설정합니다. count 를 0으로 설정하면 뱃지를 숨깁니다.

macOS에선 독 아이콘에 표시됩니다. Linux에선 Unity 런처에서만 작동합니다.

참고: Unity 런처는 이 기능을 작동하기 위해 .desktop 파일을 필요로 합니다. 이에 대한 자세한 내용은 데스크톱 환경 통합을 참고하세요.

app.getBadgeCount() Linux macOS

Returns Integer - 현재 카운터 뱃지에 표시중인 값.

app.isUnityRunning() Linux

Returns Boolean - 현재 데스크톱 환경이 Unity 인지 여부.

app.getLoginItemSettings() macOS Windows

Returns Object:

참고: 이 API 는 docs/tutorial/mac-app-store-submission-guide 에 영향을 주지 않습니다.

app.setLoginItemSettings(settings) macOS Windows

앱의 로그인 항목 설정을 지정합니다.

참고: 이 API 는 docs/tutorial/mac-app-store-submission-guide 에 영향을 주지 않습니다.

app.isAccessibilitySupportEnabled() macOS Windows

Returns Boolean - Chrome의 접근성 지원이 활성화되어있으면 true를 그렇지 않다면 false를 반환합니다. 이 API는 사용할 수 있는 스크린 리더와 같은 접근성 기술이 감지되었을 때 true를 반환합니다. 자세한 내용은 https://www.chromium.org/developers/design-documents/accessibility 를 참고하세요.

app.setAboutPanelOptions(options) macOS

정보 패널의 옵션을 설정합니다. 앱의 .plist 에 정의된 값보다 우선합니다. 자세한 내용은 애플 문서를 참조하세요.

app.commandLine.appendSwitch(switch[, value])

Chrominum의 명령줄에 스위치를 추가합니다. value는 추가적인 값을 뜻하며 옵션입니다.

참고: 이 메서드는 process.argv에 영향을 주지 않습니다. 개발자들은 보통 Chrominum의 로우 레벨 수준의 동작을 제어하기 위해 주로 사용합니다.

app.commandLine.appendArgument(value)

Chrominum의 명령줄에 인수를 추가합니다. 인수는 올바르게 인용됩니다.

참고: 이 메서드는 process.argv에 영향을 주지 않습니다.

app.dock.bounce([type]) macOS

critical이 전달되면 dock 아이콘이 애플리케이션이 활성화되거나 요청이 중지되기 전까지 통통 튀는 바운스 효과를 적용합니다.

informational이 전달되면 dock 아이콘이 1초만 통통 튑니다. 하지만 애플리케이션이 활성화되거나 요청이 중지되기 전까지 요청은 계속 활성화로 유지 됩니다.

또한 요청을 취소할 때 사용할 수 있는 ID를 반환합니다.

app.dock.cancelBounce(id) macOS

app.dock.bounce([type]) 메서드에서 반환한 id의 바운스 효과를 취소합니다.

app.dock.downloadFinished(filePath) macOS

filePath가 다운로드 폴더에 들어있다면 다운로드 스택을 바운스합니다.

app.dock.setBadge(text) macOS

dock의 badge에 표시할 문자열을 설정합니다.

app.dock.getBadge() macOS

Returns String - dock의 badge에 설정된 문자열.

app.dock.hide() macOS

dock 아이콘을 숨깁니다.

app.dock.show() macOS

dock 아이콘을 표시합니다.

app.dock.isVisible() macOS

Returns Boolean - dock 아이콘이 보이는 상태인지 여부. app.dock.show() 호출은 비동기이므로 해당 메서드를 호출한 후 바로 이 메서드를 호출하면 true를 반환하지 않을 수 있습니다.

app.dock.setMenu(menu) macOS

애플리케이션의 dock menu를 설정합니다.

app.dock.setIcon(image) macOS

dock 아이콘의 image를 설정합니다.


autoUpdater

애플리케이션이 자동으로 업데이트를 진행할 수 있도록 기능을 활성화합니다.

autoUpdater 모듈은 Squirrel 프레임워크에 대한 인터페이스를 제공합니다.

다음 프로젝트 중 하나를 선택하여, 애플리케이션을 배포하기 위한 멀티-플랫폼 릴리즈 서버를 손쉽게 구축할 수 있습니다:

플랫폼별 참고 사항

autoUpdater는 기본적으로 모든 플랫폼에 대해 같은 API를 제공하지만, 여전히 플랫폼별로 약간씩 다른 점이 있습니다.

macOS

macOS에선 autoUpdaterSquirrel.Mac를 기반으로 작동합니다. 따라서 이 모듈을 작동시키기 위해 특별히 준비해야 할 작업은 없습니다. 서버 사이드 요구 사항은 서버 지원을 참고하세요.

참고: macOS에서 자동 업데이트를 지원하려면 반드시 사인이 되어있어야 합니다. 이것은 Squirrel.Mac의 요구 사항입니다.

Windows

Windows에선 autoUpdater를 사용하기 전에 애플리케이션을 사용자의 장치에 설치해야 합니다. electron-winstaller, electron-builder 또는 grunt-electron-installer를 사용하여 애플리케이션 인스톨러를 만드는 것을 권장합니다.

Windows에선 autoUpdater 모듈을 사용하기 전에 사용자의 장치에 애플리케이션을 설치해야 합니다. 따라서 electron-winstaller 모듈이나 grunt-electron-installer 패키지를 사용하여 애플리케이션 인스톨러를 만드는 것을 권장합니다.

Squirrel로 생성된 인스톨러는 Application User Model ID와 함께 com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE으로 형식화된 바로가기 아이콘을 생성합니다. com.squirrel.slack.Slackcom.squirrel.code.Code가 그 예시입니다. app.setAppUserModelId API를 통해 애플리케이션 ID를 동일하게 유지해야 합니다. 그렇지 않으면 Windows 작업 표시줄에 애플리케이션을 고정할 때 제대로 적용되지 않을 수 있습니다.

서버 사이드 요구 사항 또한 macOS와 다르게 적용됩니다. 자세한 내용은 Squirrel.Windows를 참고하세요.

Linux

Linux는 따로 autoUpdater를 지원하지 않습니다. 각 배포판의 패키지 관리자를 통해 애플리케이션 업데이트를 제공하는 것을 권장합니다.

Events

autoUpdater 객체는 다음과 같은 이벤트를 발생시킵니다:

Event: ‘error’

Returns:

업데이트에 문제가 생기면 발생하는 이벤트입니다.

Event: ‘checking-for-update’

업데이트를 확인하기 시작할 때 발생하는 이벤트입니다.

Event: ‘update-available’

사용 가능한 업데이트가 있을 때 발생하는 이벤트입니다. 이벤트는 자동으로 다운로드 됩니다.

Event: ‘update-not-available’

사용 가능한 업데이트가 없을 때 발생하는 이벤트입니다.

Event: ‘update-downloaded’

Returns:

업데이트의 다운로드가 완료되었을 때 발생하는 이벤트입니다.

Methods

autoUpdater 객체에서 사용할 수 있는 메서드입니다:

autoUpdater.setFeedURL(url[, requestHeaders])

url을 설정하고 자동 업데이터를 초기화합니다.

autoUpdater.getFeedURL()

Returns String - 현재 업데이트 피드 URL.

autoUpdater.checkForUpdates()

서버에 새로운 업데이트가 있는지 요청을 보내 확인합니다. API를 사용하기 전에 setFeedURL를 호출해야 합니다.

autoUpdater.quitAndInstall()

애플리케이션을 다시 시작하고 다운로드된 업데이트를 설치합니다. 이 메서드는 update-downloaded 이벤트가 발생한 이후에만 사용할 수 있습니다.


BrowserWindow

브라우저 윈도우를 생성하고 제어합니다.

// 메인 프로세스에서
const {BrowserWindow} = require('electron')

// 또는 렌더러 프로세스에서
// const {BrowserWindow} = require('electron').remote

let win = new BrowserWindow({width: 800, height: 600})
win.on('closed', () => {
  win = null
})

// 원격 URL 로드
win.loadURL('https://github.com')

// 또는 로컬 HTML 로드
win.loadURL(`file://${__dirname}/app/index.html`)

Frameless 윈도우

Frameless 윈도우를 만들거나 일정한 모양의 투명한 윈도우를 만드려면, Frameless 윈도우 API를 사용할 수 있습니다.

우아하게 윈도우 표시하기

윈도우에서 페이지를 로딩할 때, 사용자는 페이지가 로드되는 모습을 볼 것입니다. 네이티브 어플리케이션으로써 좋지 않은 경험입니다. 윈도우가 시각적인 깜빡임 없이 표시되도록 만드려면, 서로 다른 상황을 위해 두 ���지 방법이 있습니다.

ready-to-show 이벤트 사용하기

페이지가 로딩되는 동안, ready-to-show 이벤트가 랜더러 프로세스가 랜더링이 완료되었을 때 처음으로 발생합니다. 이 이벤트 이후로 윈도우를 표시하면 시각적인 깜빡임 없이 표시할 수 있습니다.

const {BrowserWindow} = require('electron')
let win = new BrowserWindow({show: false})
win.once('ready-to-show', () => {
  win.show()
})

이 이벤트는 보통 did-finish-load 이벤트 이후에 발생하지만, 페이지가 너무 많은 외부 리소스를 가지고 있다면, did-finish-load 이벤트가 발생하기 이전에 발생할 수도 있습니다.

backgroundColor 설정하기

복잡한 어플리케이션에선, ready-to-show 이벤트가 너무 늦게 발생할 수 있습니다. 이는 사용자가 어플리케이션이 느리다고 생각할 수 있습니다. 이러한 경우 어플리케이션 윈도우를 바로 보이도록 하고 어플리케이션의 배경과 가까운 배경색을 backgroundColor을 통해 설정합니다:

const {BrowserWindow} = require('electron')

let win = new BrowserWindow({backgroundColor: '#2e2c29'})
win.loadURL('https://github.com')

참고로 ready-to-show 이벤트를 사용하더라도 어플리케이션을 네이티브 느낌이 나도록 하기 위해 backgroundColor도 같이 설정하는 것을 권장합니다.

부모와 자식 윈도우

parent 옵션을 사용하면 자식 윈도우를 만들 수 있습니다:

const {BrowserWindow} = require('electron')

let top = new BrowserWindow()
let child = new BrowserWindow({parent: top})
child.show()
top.show()

child 윈도우는 언제나 top 윈도우의 상위에 표시됩니다.

모달 윈도우

모달 윈도우는 부모 윈도우를 비활성화 시키는 자식 윈도우입니다. 모달 윈도우를 만드려면 parent, modal 옵션을 동시에 설정해야 합니다:

const {BrowserWindow} = require('electron')

let child = new BrowserWindow({parent: top, modal: true, show: false})
child.loadURL('https://github.com')
child.once('ready-to-show', () => {
  child.show()
})

플랫폼별 특이사항

Class: BrowserWindow

BrowserWindowEventEmitter를 상속받은 클래스 입니다.

BrowserWindowoptions를 통해 네이티브 속성을 포함한 새로운 윈도우를 생성합니다.

new BrowserWindow([options])

options 객체 (optional), 사용할 수 있는 속성들:

minWidth/maxWidth/minHeight/maxHeight를 통해 최소 또는 최대 윈도우 크기를 지정한 경우, 이는 사용자만을 제약하며, setBounds/setSize 또는 BrowserWindow의 생성자에서 크기 제약을 따르지 않는 윈도우 크기를 전달하는 것은 막을 수 없습니다.

type 속성에서 사용할 수 있는 값과 동작은 다음과 같으며, 플랫폼에 따라 다릅니다:

titleBarStyle의 속성은 다음과 같습니다:

webPreferences 속성은 다음과 같은 속성을 가질 수 있습니다:

Instance Events

new BrowserWindow로 생성된 객체는 다음과 같은 이벤트를 발생시킵니다:

참고: 몇몇 이벤트는 라벨에 특정한 OS에서만 작동합니다.

Event: ‘page-title-updated’

Returns:

문서의 제목이 변경될 때 발생하는 이벤트입니다. event.preventDefault()를 호출하여 네이티브 윈도우의 제목이 변경되는 것을 방지할 수 있습니다.

Event: ‘close’

Returns:

윈도우가 닫히기 시작할 때 발생하는 이벤트입니다. 이 이벤트는 DOM의 beforeunloadunload 이벤트 전에 발생합니다. event.preventDefault()를 호출하여 윈도우 종료를 취소할 수 있습니다.

보통 창을 닫아야 할지 결정하기 위해 beforeunload 이벤트를 사용하려고 할 것입니다. 이 이벤트는 윈도우 콘텐츠를 새로고칠 때도 발생합니다. Electron에선 undefined가 아닌 이외의 값을 전달할 경우 윈도우 종료를 취소합니다. 예시는 다음과 같습니다:

window.onbeforeunload = (e) => {
  console.log('I do not want to be closed')

  // 일반적인 브라우저와는 달리 사용자에게 확인 창을 보여주지 않고, non-void 값을 반환하면
  // 조용히 닫기를 취소합니다.
  // Dialog API를 통해 사용자가 애플리케이션을 종료할지 정할 수 있도록 확인 창을 표시하는 것을
  // 추천합니다.
  e.returnValue = false
}

Event: ‘closed’

윈도우 종료가 완료된 경우 발생하는 이벤트입니다. 이 이벤트가 발생했을 경우 반드시 윈도우의 레퍼런스가 더 이상 사용되지 않도록 제거해야 합니다.

Event: ‘unresponsive’

웹 페이지가 응답하지 않을 때 발생하는 이벤트입니다.

Event: ‘responsive’

응답하지 않는 웹 페이지가 다시 응답하기 시작했을 때 발생하는 이벤트입니다.

Event: ‘blur’

윈도우가 포커스를 잃었을 때 발생하는 이벤트입니다.

Event: ‘focus’

윈도우가 포커스를 가졌을 때 발생하는 이벤트입니다.

Event: ‘show’

윈도우가 보여진 상태일 때 발생하는 이벤트입니다.

Event: ‘hide’

윈도우가 숨겨진 상태일 때 발생하는 이벤트입니다.

Event: ‘ready-to-show’

웹 페이지가 완전히 랜더링되어 윈도우가 시각적인 깜빡임없이 콘텐츠를 보여줄 수 있을 때 발생하는 이벤트입니다.

Event: ‘maximize’

윈도우가 최대화됐을 때 발생하는 이벤트입니다.

Event: ‘unmaximize’

윈도우의 최대화 상태가 해제되었을 때 발생하는 이벤트입니다.

Event: ‘minimize’

윈도우가 최소화됐을 때 발생하는 이벤트입니다.

Event: ‘restore’

윈도우가 최소화 상태에서 복구되었을 때 발생하는 이벤트입니다.

Event: ‘resize’

윈도우의 크기가 재조정될 때 발생하는 이벤트입니다.

Event: ‘move’

윈도우가 새로운 위치로 이동될 때 발생하는 이벤트입니다.

참고: macOS에선 이 이벤트가 그저 moved 이벤트의 별칭(alias)으로 사용됩니다.

Event: ‘moved’ macOS

윈도우가 새로운 위치로 이동되었을 때 발생하는 이벤트입니다. (한 번만)

Event: ‘enter-full-screen’

윈도우가 풀 스크린 모드로 진입할 때 발생하는 이벤트입니다.

Event: ‘leave-full-screen’

윈도우가 풀 스크린 모드에서 해제될 때 발생하는 이벤트입니다.

Event: ‘enter-html-full-screen’

윈도우가 HTML API에 의해 풀 스크린 모드로 진입할 때 발생하는 이벤트입니다.

Event: ‘leave-html-full-screen’

윈도우가 HTML API에 의해 풀 스크린 모드에서 해제될 때 발생하는 이벤트입니다.

Event: ‘app-command’ Windows

Returns:

App Command가 호출됐을 때 발생하는 이벤트입니다. 이 이벤트는 일반적으로 키보드 미디어 키 또는 브라우저 커맨드(기본 동작 키)에 관련되어 있습니다. 예를 들어 Windows에서 작동하는 몇몇 마우스는 “뒤로가기” 같은 동작을 포함하고 있습니다.

반환되는 커맨드들은 모두 소문자화되며 언더스코어(_)는 하이픈(-)으로 변경되며 APPCOMMAND_ 접두어는 제거됩니다. e.g. APPCOMMAND_BROWSER_BACKWARDbrowser-backward와 같이 반환됩니다.

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.on('app-command', (e, cmd) => {
  // Navigate the window back when the user hits their mouse back button
  if (cmd === 'browser-backward' && win.webContents.canGoBack()) {
    win.webContents.goBack()
  }
})

Event: ‘scroll-touch-begin’ macOS

스크롤 휠 이벤트가 동작하기 시작했을 때 발생하는 이벤트입니다.

Event: ‘scroll-touch-end’ macOS

스크롤 휠 이벤트가 동작을 멈췄을 때 발생하는 이벤트입니다.

Event: ‘scroll-touch-edge’ macOS

스크롤 휠 이벤트로 요소의 끝에 도달했을 때 발생하는 이벤트입니다.

Event: ‘swipe’ macOS

Returns:

3-손가락 스와이프가 작동할 때 발생하는 이벤트입니다. 방향은 up, right, down, left가 될 수 있습니다.

Static Methods

BrowserWindow 클래스는 다음과 같은 정적 메서드를 가지고 있습니다:

BrowserWindow.getAllWindows()

Returns BrowserWindow[] - 열려있는 모든 브라우저 윈도우의 배열.

BrowserWindow.getFocusedWindow()

Returns BrowserWindow - 애플리케이션에서 포커스된 윈도우. 없을 경우 null.

BrowserWindow.fromWebContents(webContents)

Returns BrowserWindow - webContents 를 소유한 윈도우.

BrowserWindow.fromId(id)

Returns BrowserWindow - id 에 해당하는 윈도우.

BrowserWindow.addDevToolsExtension(path)

path에 있는 개발자 도구 확장 기능을 추가합니다. 그리고 확장 기능의 이름을 반환합니다.

확장 기능은 기억됩니다. 따라서 API는 단 한 번만 호출되어야 합니다. 이 API는 실제 프로그램 작성에 사용할 수 없습니다. 만약 이미 로드된 확장 기능을 추가하려 한다면, 이 메서드는 아무것도 반환하지 않고 콘솔에 경고가 로그됩니다.

참고: 이 API는 app 모듈의 ready 이벤트가 발생하기 전까지 사용할 수 없습니다.

BrowserWindow.removeDevToolsExtension(name)

name에 해당하는 개발자 도구 확장 기능을 제거합니다.

참고: 이 API는 app 모듈의 ready 이벤트가 발생하기 전까지 사용할 수 없습니다.

BrowserWindow.getDevToolsExtensions()

Returns Object - 키는 확장 기능 이름을 값은 nameversion 속성을 포함하는 객체를 가집니다.

개발자 도구 확장 기능이 설치되었는지 확인하려면 다음과 같이 실행할 수 있습니다:

const {BrowserWindow} = require('electron')

let installed = BrowserWindow.getDevToolsExtensions().hasOwnProperty('devtron')
console.log(installed)

참고: 이 API는 app 모듈의 ready 이벤트가 발생하기 전까지 사용할 수 없습니다.

Instance Properties

new BrowserWindow로 생성한 객체는 다음과 같은 속성을 가지고 있습니다:

const {BrowserWindow} = require('electron')
// `win`은 BrowserWindow의 인스턴스입니다
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('https://github.com')

win.webContents

윈도우의 WebContents 객체입니다. 모든 웹 페이지와 관련된 이벤트와 작업이 이 객체를 통해 수행됩니다.

메서드나 이벤트에 대한 자세한 내용은 webContents 문서를 참고하세요.

win.id

Integer 형식의 윈도우 고유 ID 입니다.

Instance Methods

new BrowserWindow로 생성한 객체는 다음과 같은 메서드들을 가지고 있습니다:

참고: 몇몇 메서드들은 라벨에서 특정한 운영체제 시스템에서만 작동합니다.

win.destroy()

윈도우를 강제로 닫습니다. 웹 페이지의 unloadbeforeunload 이벤트는 일어나지 않습니다. 또한 이 윈도우의 close도 일어나지 않습니다. 하지만 closed 이벤트는 반드시 발생함을 보장합니다.

win.close()

윈도우의 종료를 시도합니다. 이 메서드는 사용자가 윈도우의 닫기 버튼을 클릭했을 때와 같은 효과를 냅니다. 웹 페이지는 로드가 취소되고 종료됩니다. 자세한 내용은 close 이벤트를 참고하세요.

win.focus()

윈도우에 포커스를 맞춥니다.

win.blur()

윈도우의 포커스를 없앱니다.

win.isFocused()

Returns Boolean - 윈도우가 포커스되었는지 여부.

win.isDestroyed()

Returns Boolean - 윈도우가 소멸되었는지 여부.

win.show()

윈도우를 표시하고 포커스합니다.

win.showInactive()

윈도우를 표시만 하고 포커스하지 않습니다.

win.hide()

윈도우를 숨깁니다.

win.isVisible()

Returns Boolean - 윈도우가 사용자에게 표시되고 있는지 여부.

win.isModal()

Returns Boolean - 현재 윈도우가 모달 윈도우인지 여부.

win.maximize()

윈도우를 최대화 시킵니다.

win.unmaximize()

윈도우 최대화를 취소합니다.

win.isMaximized()

Returns Boolean - 윈도우가 최대화 되어있는지 여부.

win.minimize()

윈도우를 최소화 시킵니다. 어떤 플랫폼은 최소화된 윈도우가 Dock에 표시됩니다.

win.restore()

최소화된 윈도우를 이전 상태로 되돌립니다.

win.isMinimized()

Returns Boolean - 윈도우가 최소화되었는지 여부.

win.setFullScreen(flag)

윈도우의 전체화면 상태를 지정합니다.

win.isFullScreen()

Returns Boolean - 윈도우가 전체화면 모드인지 여부.

win.setAspectRatio(aspectRatio[, extraSize]) macOS

이 메서드는 윈도우의 종횡비를 유지하는 기능을 수행합니다. 엑스트라 크기는 개발자가 픽셀로 특정한 공간이 있을 때 종횡비 계산에서 제외됩니다. 이 API는 윈도우의 크기와 콘텐츠 사이즈의 차이를 이미 고려하고 있습니다.

일반 윈도우에서 작동하는 HD 비디오 플레이어와 관련된 컨트롤을 고려합니다. 만약 15 픽셀의 컨트롤이 왼쪽 가장자리에 있고 25 픽셀의 컨트롤이 오른쪽 가장자리에 있으며 50 픽셀의 컨트롤이 플레이어 밑에 있을 때 플레이어 자체가 16:9 종횡비(HD의 표준 종횡비는 @1920x1080)를 유지하기 위해선 이 함수를 16/9, [ 40, 50 ] 인수와 함께 호출해야 합니다. 두번째 인수 엑스트라 크기는 존재하는 크기만 관여하고 콘텐츠 뷰 내의 크기는 관여하지 않습니다. 그저 전체 콘텐츠 뷰 내에 있는 모든 엑스트라 너비, 높이 영역이 합해집니다.

win.setBounds(bounds[, animate])

윈도우를 주어진 영역으로 크기 재조정 및 이동합니다.

win.getBounds()

Returns structures/rectangle

win.setContentBounds(bounds[, animate])

윈도우의 내부 영역 (예. 웹페이지) 을 주어진 영역으로 크기 재조정 및 이동합니다.

win.getContentBounds()

윈도우의 클라이언트 영역 (웹 페이지)의 너비, 높이, x, y 값을 포함하는 객체를 반환합니다.

win.setSize(width, height[, animate])

widthheight 값으로 윈도우 크기를 재조정합니다. (너비, 높이)

win.getSize()

Returns Integer[] - 윈도우의 너비, 높이를 포함.

win.setContentSize(width, height[, animate])

윈도우 클라이언트 영역(웹 페이지)의 크기를 width, height로 재조정합니다.

win.getContentSize()

Returns Integer[] - 윈도우 내부 영역의 너비, 높이를 포함.

win.setMinimumSize(width, height)

윈도우의 최소 width, height 크기를 지정합니다.

win.getMinimumSize()

Returns Integer[] - 윈도우의 최소 너비, 높이를 포함.

win.setMaximumSize(width, height)

윈도우의 최대 width, height 크기를 지정합니다.

win.getMaximumSize()

Returns Integer[] - 윈도우의 최대 너비, 높이를 포함.

win.setResizable(resizable)

사용자에 의해 윈도우의 크기가 재조정될 수 있는지를 지정합니다.

win.isResizable()

Returns Boolean - 사용자에 의해 윈도우의 크기가 재조정될 수 있는지 여부.

win.setMovable(movable) macOS Windows

사용자에 의해 윈도우를 이동시킬 수 있는지 여부를 지정합니다. Linux에선 아무 일도 일어나지 않습니다.

win.isMovable() macOS Windows

Returns Boolean - 사용자에 의해 윈도우를 이동시킬 수 있는지 여부.

Linux에선 항상 true를 반환합니다.

win.setMinimizable(minimizable) macOS Windows

사용자에 의해 윈도우를 최소화시킬 수 있는지 여부를 지정합니다. Linux에선 아무 일도 일어나지 않습니다.

win.isMinimizable() macOS Windows

Returns Boolean - 사용자에 의해 윈도우를 최소화시킬 수 있는지 여부.

Linux에선 항상 true를 반환합니다.

win.setMaximizable(maximizable) macOS Windows

사용자에 의해 윈도우를 최대화시킬 수 있는지 여부를 지정합니다. Linux에선 아무 일도 일어나지 않습니다.

win.isMaximizable() macOS Windows

Returns Boolean - 사용자에 의해 윈도우를 최대화시킬 수 있는지 여부.

Linux에선 항상 true를 반환합니다.

win.setFullScreenable(fullscreenable)

최대화/줌 버튼이 전체화면 모드 또는 윈도우 최대화를 토글할 수 있게 할지 여부를 지정합니다.

win.isFullScreenable()

Returns Boolean - 최대화/줌 버튼이 전체화면 모드 또는 윈도우 최대화를 토글할 수 있는지 여부.

win.setClosable(closable) macOS Windows

사용자에 의해 윈도우가 수동적으로 닫힐 수 있는지 여부를 지정합니다. Linux에선 아무 일도 일어나지 않습니다.

win.isClosable() macOS Windows

Returns Boolean - 사용자에 의해 윈도우가 수동적으로 닫힐 수 있는지 여부.

Linux에선 항상 true를 반환합니다.

win.setAlwaysOnTop(flag[, level])

윈도우가 언제나 다른 윈도우들 위에 표시되는지 여부를 지정합니다. 이 설정을 활성화 하면 윈도우는 포커스 될 수 없는 툴박스 윈도우가 아닌 일반 윈도우로 유지됩니다.

win.isAlwaysOnTop()

윈도우가 언제나 다른 윈도우들 위에 표시되는지 여부를 반환합니다.

win.center()

윈도우를 화면 정 중앙으로 이동합니다.

win.setPosition(x, y[, animate])

윈도우의 위치를 x, y로 이동합니다.

win.getPosition()

Returns Integer[] - 윈도우의 현재 위치.

win.setTitle(title)

title을 네이티브 윈도우의 제목으로 지정합니다.

win.getTitle()

Returns String - 네이티브 윈도우의 제목.

참고: 웹 페이지의 제목과 네이티브 윈도우의 제목은 서로 다를 수 있습니다.

win.setSheetOffset(offsetY[, offsetX]) macOS

macOS에서 시트를 부착할 위치를 지정합니다. 기본적으로 시트는 윈도우의 프레임 바로 아래의 위치에 부착됩니다. 아마도 이 기능은 보통 다음과 같이 HTML 렌더링된 툴바 밑에 표시하기 위해 사용할 것입니다:

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()

let toolbarRect = document.getElementById('toolbar').getBoundingClientRect()
win.setSheetOffset(toolbarRect.height)

win.flashFrame(flag)

사용자가 윈도우에 관심을 가질 수 있도록 창을 깜빡이거나 이를 중지합니다.

win.setSkipTaskbar(skip)

애플리케이션 아이콘을 작업표시줄에 보이지 않도록 설정합니다.

win.setKiosk(flag)

Kiosk(키오스크) 모드를 설정합니다.

win.isKiosk()

Returns `Boolean’ - 현재 윈도우가 kiosk 모드인지 여부.

win.getNativeWindowHandle()

Returns Buffer - 플랫폼 별 윈도우의 핸들.

핸들의 타입에 따라 적절히 캐스팅됩니다. Windows의 HWND, macOS의 NSView*, Linux의 Window (unsigned long)를 예로 들 수 있습니다.

win.hookWindowMessage(message, callback) Windows

Windows 메시지 훅을 등록합니다. callback은 WndProc에서 메시지를 받았을 때 호출됩니다.

win.isWindowMessageHooked(message) Windows

Returns Boolean - 지정한 메시지가 후킹됐는지에 따라 true 또는 false.

win.unhookWindowMessage(message) Windows

지정한 메시지 훅을 등록 해제합니다.

win.unhookAllWindowMessages() Windows

모든 메시지 훅을 등록 해제합니다.

win.setRepresentedFilename(filename) macOS

윈도우 대표 파일의 경로명을 설정합니다. 파일의 아이콘이 윈도우 타이틀 바에 표시됩니다.

win.getRepresentedFilename() macOS

Returns String - 윈도우 대표 파일의 경로.

win.setDocumentEdited(edited) macOS

윈도우의 문서가 변경되었는지 여부를 설정합니다. 그리고 true로 설정했을 때 타이틀 바의 아이콘이 회색으로 표시됩니다.

win.isDocumentEdited() macOS

Returns Boolean - 윈도우의 문서가 변경되었는지 여부.

win.focusOnWebView()

win.blurWebView()

win.capturePage([rect, ]callback)

webContents.capturePage([rect, ]callback)와 같습니다.

win.loadURL(url[, options])

webContents.loadURL(url[, options]) API와 같습니다.

url은 원격 주소 (e.g. http://)가 되거나 file:// 프로토콜을 사용하는 로컬 HTML 경로가 될 수 있습니다.

파일 URL이 올바른 형식으로 지정되었는지 확인하려면 Node의 url.format 메서드를 사용하는 것을 권장합니다.

let url = require('url').format({
  protocol: 'file',
  slashes: true,
  pathname: require('path').join(__dirname, 'index.html')
})

win.loadURL(url)

win.reload()

webContents.reload API와 같습니다.

win.setMenu(menu) Linux Windows

지정한 menu를 윈도우의 메뉴로 설정합니다 null을 설정하면 메뉴를 제거합니다.

win.setProgressBar(progress[, options])

작업표시줄에 표시되고 있는 애플리케이션 아이콘에 진행 상태를 표시합니다. [0, 1.0] 사이의 값을 지정할 수 있습니다.

진행 상태가 < 0 이 되면 진행 상태 표시를 제거합니다. 진행 상태가 > 1 이 되면 불확정 상태 표시로 전환합니다.

Linux 플랫폼에선 Unity 데스크톱 환경만 지원합니다. 그리고 이 기능을 사용하려면 *.desktop 파일을 생성한 후 package.jsondesktopName 필드에 파일 이름을 지정해야 합니다. 기본적으로 app.getName().desktop을 통해 접근합니다.

Windows에선 모드를 전달할 수 있습니다. 사용할 수 있는 값은 none, normal, indeterminate, error, 그리고 paused가 있습니다. 만약 모드 설정 없이 setProgressBar를 호출하면 (올바른 범위의 값을 전달했을 때), normal이 기본적으로 설정됩니다.

win.setOverlayIcon(overlay, description) Windows

현재 작업표시줄 아이콘에 16 x 16 픽셀 크기의 오버레이를 지정합니다. 보통 이 기능은 애플리케이션의 여러 상태를 사용자에게 소극적으로 알리기 위한 방법으로 사용됩니다.

win.setHasShadow(hasShadow) macOS

윈도우가 그림자를 가질지 여부를 지정합니다. Windows와 Linux에선 아무 일도 일어나지 않습니다.

win.hasShadow() macOS

Returns Boolean - 윈도우가 그림자를 가지고 있는지 여부.

Windows와 Linux에선 항상 true를 반환합니다.

win.setThumbarButtons(buttons) Windows

Returns Boolean - 버튼이 성공적으로 추가되었는지 여부

윈도우 작업표시줄 버튼 레이아웃의 미리보기 이미지 영역에 미리보기 툴바와 버튼 세트를 추가합니다. 반환되는 Boolean 값은 미리보기 툴바가 성공적으로 추가됬는지를 알려줍니다.

미리보기 이미지 영역의 제한된 크기로 인해 미리보기 툴바에 추가될 수 있는 최대 버튼의 개수는 7개이며 이 이상 추가될 수 없습니다. 플랫폼의 제약으로 인해 미리보기 툴바는 한 번 설정되면 삭제할 수 없습니다. 하지만 이 API에 빈 배열을 전달하여 버튼들을 제거할 수 있습니다.

buttonsButton 객체의 배열입니다:

flags 는 다음 String 들을 포함할 수 있는 배열입니다: * enabled - 사용자가 사용할 수 있도록 버튼이 활성화 됩니다. * disabled - 버튼이 비활성화 됩니다. 버튼은 표시되지만 시각적인 상태는 사용자의 동작에 응답하지 않는 비활성화 상태로 표시됩니다. * dismissonclick - 버튼이 클릭되면 작업표시줄 버튼의 미리보기(flyout)가 즉시 종료됩니다. * nobackground - 버튼의 테두리를 표시하지 않습니다. 이미지에만 사용할 수 있습니다. * hidden - 버튼을 사용자에게 표시되지 않도록 숨깁니다. * noninteractive - 버튼은 활성화되어 있지만 반응이 제거되며 버튼을 눌러도 눌려지지 않은 상태를 유지합니다. 이 값은 버튼을 알림의 용도로 사용하기 위해 만들어졌습니다.

win.setThumbnailClip(region) Windows

작업 표시줄에 윈도우의 섬네일이 표시될 때 섬네일 이미지로 사용할 윈도우의 영역을 지정합니다. 빈 영역을 지정하는 것으로 전체 윈도우의 섬네일로 초기화할 수 있습니다: {x: 0, y: 0, width: 0, height: 0}.

win.setThumbnailToolTip(toolTip) Windows

작업 표시줄의 윈도우 섬네일 위에 표시될 툴팁을 설정합니다.

win.showDefinitionForSelection() macOS

webContents.showDefinitionForSelection()와 같습니다.

win.setIcon(icon) Windows Linux

윈도우 아이콘을 변경합니다.

win.setAutoHideMenuBar(hide)

메뉴 막대 자동 숨김 기능을 활성화 합니다. 숨겨진 메뉴는 사용자가 Alt 키를 단일 입력했을 때만 표시됩니다.

메뉴 막대가 이미 표시되고 있을 때 setAutoHideMenuBar(true)를 호출한다고 해서 메뉴가 즉시 숨겨지지는 않습니다.

win.isMenuBarAutoHide()

Returns Boolean - 메뉴 막대 자동 숨김 상태 여부.

win.setMenuBarVisibility(visible)

메뉴 막대의 표시 여부를 설정합니다. 만약 메뉴 막대 자동 숨김 상태라면 여전히 사용자가 Alt 키를 입력하여 메뉴 막대를 표시되도록 할 수 있습니다.

역자주: 기본 메뉴 막대를 완전히 없애려면 win.setMenu(null)를 호출해야 합니다. 단순히 이 API를 사용하면 여전히 메뉴에 등록된 핫 키가 작동합니다.

win.isMenuBarVisible()

Returns Boolean - 메뉴 막대가 표시되고 있는지 여부.

win.setVisibleOnAllWorkspaces(visible)

윈도우가 모든 워크스페이스에서 표시될지 여부를 설정합니다.

참고: 이 API는 Windows에서 아무 일도 하지 않습니다.

win.isVisibleOnAllWorkspaces()

Returns Boolean - 윈도우가 모든 워크스페이스에서 표시될지 여부.

참고: 이 API는 Windows에서 언제나 false를 반환합니다.

win.setIgnoreMouseEvents(ignore)

윈도우가 모든 마우스 이벤트를 무시하게 만듭니다.

이 윈도우에서 일어나는 모든 마우스 이벤트가 이 윈도우 밑의 윈도우로 전달됩니다. 하지만 이 윈도우가 포커스되어 있다면, 여전히 키보드 이벤트는 받을 수 있습니다.

win.setContentProtection(enable) macOS Windows

윈도우 콘텐츠가 외부 어플리케이션에 의해 캡쳐되는 것을 막습니다.

macOS에선 NSWindow의 sharingType을 NSWindowSharingNone로 설정합니다. Windows에선 WDA_MONITOR와 함께 SetWindowDisplayAffinity를 호출합니다.

win.setFocusable(focusable) Windows

윈도우가 포커스될 수 있는지 여부를 변경합니다.

win.setParentWindow(parent) Linux macOS

win.getParentWindow()

Returns BrowserWindow - 부모 윈도우.

win.getChildWindows()

Returns BrowserWindow[] - 모든 자식 윈도우.


크롬 명령줄 스위치 지원

Electron에서 지원하는 커맨드 명령줄 스위치입니다.

애플리케이션 메인 스크립트의 app 모듈에서 ready 이벤트가 실행되기 전에 app.commandLine.appendSwitch를 호출하면, 애플리케이션의 명령줄 옵션을 추가로 지정할 수 있습니다:

const {app} = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1')

app.on('ready', () => {
  // Your code here
})

–ignore-connections-limit=domains

domains 리스트(,로 구분)의 연결 제한을 무시합니다.

–disable-http-cache

HTTP 요청 캐시를 비활성화합니다.

–disable-http2

HTTP/2와 SPDY/3.1 프로토콜을 비활성화합니다.

–remote-debugging-port=port

지정한 port에 HTTP 기반의 리모트 디버거를 활성화합니다. (개발자 도구)

–js-flags=flags

JS 엔진에 지정한 플래그를 전달합니다. flags를 메인 프로세스에서 활성화하고자 한다면, Electron이 시작되기 전에 스위치를 전달해야 합니다.

$ electron --js-flags="--harmony_proxies --harmony_collections" your-app

–proxy-server=address:port

시스템 설정의 프록시 서버를 무시하고 지정한 서버로 연결합니다. HTTP와 HTTPS 요청에만 적용됩니다.

시스템 프록시 서버 설정을 무시하고 지정한 서버로 연결합니다. 이 스위치는 HTTP와 HTTPS 그리고 WebSocket 요청에만 적용됩니다. 그리고 모든 프록시 서버가 HTTPS가 WebSocket 요청을 지원하지 않고 있을 수 있으므로 사용시 주의해야 합니다.

–proxy-bypass-list=hosts

Electron이 세미콜론으로 구분된 호스트 리스트에서 지정한 프록시 서버를 건너뛰도록 지시합니다.

예시:

app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678')

위 예시는 로컬 주소(localhost, 127.0.0.1, 등)와 google.com의 서브도메인, foo.com을 접미사로 가지는 호스트, 1.2.3.4:5678 호스트를 제외한 모든 연결에서 프록시 서버를 사용합니다.

–proxy-pac-url=url

지정한 url의 PAC 스크립트를 사용합니다.

–no-proxy-server

프록시 서버를 사용하지 않습니다. 다른 프록시 서버 플래그 및 설정을 무시하고 언제나 직접 연결을 사용합니다.

–host-rules=rules

Hostname 맵핑 규칙을 설정합니다. (,로 구분)

예시:

이 맵핑은 네트워크 요청시의 endpoint를 지정합니다. (TCP 연결과 직접 연결의 호스트 resolver, http 프록시 연결의 CONNECT, SOCKS 프록시 연결의 endpoint 호스트)

–host-resolver-rules=rules

--host-rules 플래그와 비슷하지만 이 플래그는 host resolver에만 적용됩니다.

–auth-server-whitelist=url

통합 인증을 사용하도록 설정할 쉼표로 구분된 서버의 리스트.

예를 들어:

--auth-server-whitelist='*example.com, *foobar.com, *baz'

그리고 모든 example.com, foobar.com, baz로 끝나는 url은 통합 인증을 사용하도록 설정됩니다. * 접두어가 없다면 url은 정확히 일치해야 합니다.

–auth-negotiate-delegate-whitelist=url

필수적인 사용자 자격 증명을 보내야 할 쉼표로 구분된 서버의 리스트. * 접두어가 없다면 url은 정확히 일치해야 합니다.

–ignore-certificate-errors

인증서 에러를 무시합니다.

–ppapi-flash-path=path

Pepper 플래시 플러그인의 위치를 설정합니다.

–ppapi-flash-version=version

Pepper 플래시 플러그인의 버전을 설정합니다.

–log-net-log=path

Net log 이벤트를 활성화하고 path에 로그를 기록합니다.

–ssl-version-fallback-min=version

TLS fallback에서 사용할 SSL/TLS 최소 버전을 지정합니다. (tls1, tls1.1, tls1.2)

–cipher-suite-blacklist=cipher_suites

SSL 암호화를 비활성화할 대상 목록을 지정합니다. (,로 구분)

–disable-renderer-backgrounding

Chromium이 렌더러 프로세스의 보이지 않는 페이지의 우선순위를 낮추는 것을 방지합니다.

이 플래그는 전역적이며 모든 렌더러 프로세스에 적용됩니다. 만약 하나의 윈도우창에만 스로틀링을 비활성화하고 싶다면 조용한 오디오를 재생하는 핵을 사용할 수 있습니다.

–enable-logging

Chromium의 로그를 콘솔에 출력합니다.

이 스위치는 애플리케이션이 로드되기 전에 분석 되므로 app.commandLine.appendSwitch 메서드에선 사용할 수 없습니다. 하지만 ELECTRON_ENABLE_LOGGING 환경 변수를 설정하면 본 스위치를 지정한 것과 같은 효과를 낼 수 있습니다.

–v=log_level

기본 V-logging 최대 활성화 레벨을 지정합니다. 기본값은 0입니다. 기본적으로 양수를 레벨로 사용합니다.

이 스위치는 --enable-logging 스위치를 같이 지정해야 작동합니다.

–vmodule=pattern

--v 옵션에 전달된 값을 덮어쓰고 모듈당 최대 V-logging 레벨을 지정합니다. 예를 들어 my_module=2,foo*=3my_module.*, foo*.*와 같은 파일 이름 패턴을 가진 모든 소스 코드들의 로깅 레벨을 각각 2와 3으로 설정합니다.

또한 슬래시(/) 또는 백슬래시(\)를 포함하는 패턴은 지정한 경로에 대해 패턴을 테스트 합니다. 예를 들어 */foo/bar/*=2 표현식은 foo/bar 디렉터리 안의 모든 소스 코드의 로깅 레벨을 2로 지정합니다.

이 스위치는 --enable-logging 스위치를 같이 지정해야 작동합니다.


clipboard

시스템 클립보드에 복사와 붙여넣기를 수행합니다.

다음 예시는 클립보드에 문자열을 쓰는 방법을 보여줍니다:

const {clipboard} = require('electron')
clipboard.writeText('Example String')

X Window 시스템에선 selection 클립보드도 존재합니다. 이를 사용하려면 인수 뒤에 selection 문자열을 같이 지정해주어야 합니다:

const {clipboard} = require('electron')
clipboard.writeText('Example String', 'selection')
console.log(clipboard.readText('selection'))

Methods

clipboard 모듈은 다음과 같은 메서드를 가지고 있습니다:

참고: Experimental 마크가 붙은 API는 실험적인 기능이며 차후 최신 버전에서 제거될 수 있습니다.

clipboard.readText([type])

Returns String - 일반 텍스트 형식의 클립보드의 내용.

clipboard.writeText(text[, type])

클립보드에 plain text로 문자열을 씁니다.

clipboard.readHTML([type])

returns String - 마크업 형식의 클립보드의 내용.

clipboard.writeHTML(markup[, type])

클립보드에 markup으로 씁니다.

clipboard.readImage([type])

Returns NativeImage - NativeImage 형식의 클립보드의 내용.

clipboard.writeImage(image[, type])

클립보드에 image를 씁니다.

clipboard.readRTF([type])

Returns String - RTF 형식의 클립보드 내용.

clipboard.writeRTF(text[, type])

클립보드에 text를 RTF 형식으로 씁니다.

clipboard.readBookmark() macOS Windows

Returns Object: * title String * url String

클립보드로부터 북마크 형식으로 표현된 titleurl 키를 담은 객체를 반환합니다. titleurl 값들은 북마크를 사용할 수 없을 때 빈 문자열을 포함합니다.

clipboard.writeBookmark(title, url[, type]) macOS Windows

titleurl을 클립보드에 북마크 형식으로 씁니다.

참고: 윈도우의 대부분의 앱은 북마크 붙여넣기를 지원하지 않습니다. clipboard.write 를 통해 북마크와 대체 텍스트를 클립보드에 쓸 수 있습니다.

clipboard.write({
  text: 'http://electron.atom.io',
  bookmark: 'Electron Homepage'
})

clipboard.clear([type])

클립보드에 저장된 모든 콘텐츠를 삭제합니다.

clipboard.availableFormats([type])

Return String[] - 클립보드 type 에 지원되는 형식의 배열.

clipboard.has(data[, type])

Returns Boolean - 클립보드가 지정한 data 의 형식을 지원하는지 여부.

const {clipboard} = require('electron')
console.log(clipboard.has('<p>selection</p>'))

clipboard.read(data[, type]) Experimental

Returns String - 클립보드로부터 data를 읽습니다.

clipboard.write(data[, type]) Experimental

const {clipboard} = require('electron')
clipboard.write({text: 'test', html: '<b>test</b>'})

data를 클립보드에 씁니다.


contentTracing

성능상의 병목 현상과 느린 작업을 찾기 위해 Chromium의 콘텐츠 모듈에서 추적 데이터를 수집합니다.

이 모듈은 웹 인터페이스를 포함하고 있지 않으며 Chrome 브라우저에서 chrome://tracing/ 페이지를 열고 생성된 파일을 로드하면 결과를 볼 수 있습니다.

const {contentTracing} = require('electron')

const options = {
  categoryFilter: '*',
  traceOptions: 'record-until-full,enable-sampling'
}

contentTracing.startRecording(options, () => {
  console.log('Tracing started')

  setTimeout(() => {
    contentTracing.stopRecording('', (path) => {
      console.log('Tracing data recorded to ' + path)
    })
  }, 5000)
})

Methods

content-tracing 모듈은 다음과 같은 메서드를 가지고 있습니다:

contentTracing.getCategories(callback)

카테고리 그룹 세트를 가져옵니다. 카테고리 그룹은 도달된 코드 경로를 변경할 수 있습니다.

모든 child 프로세스가 getCategories 요청을 승인하면 callback이 한 번 호출되며 인수에 카테고리 그룹의 배열이 전달됩니다.

contentTracing.startRecording(options, callback)

모든 프로세스에서 레코딩을 시작합니다.

레코딩은 지역적으로 즉시 실행됩니다. 그리고 비동기로 child 프로세스는 곧 EnableRecording 요청을 받게 됩니다. 모든 child 프로세스가 startRecording 요청을 승인하면 callback이 한 번 호출됩니다.

categoryFilter는 어떤 카테고리 그룹이 트레이싱 되어야 하는지 필터링할 수 있습니다. 필터는 - 접두사를 통해 특정 카테고리 그룹을 제외할 수 있습니다. 카테고리 패턴은 같은 리스트 내에서 포함과 제외를 함께 사용할 수 없습니다.

예시:

traceOptions은 어떤 종류의 트레이싱을 사용할 수 있는지 지정하고 콤마로 리스트를 구분합니다.

사용할 수 있는 옵션은 다음과 같습니다:

첫번째부터 3번째까지의 옵션은 추적 레코딩 모드입니다. 이에 따라 상호 배타적입니다. 만약 레코딩 모드가 한 개 이상 지정되면 마지막 지정한 모드만 사용됩니다. 어떤 모드도 설정되지 않았다면 record-until-full 모드가 기본으로 사용됩니다.

추적 옵션은 traceOptions이 파싱되어 적용되기 전까지 다음과 같은 기본값이 사용됩니다.

record-until-full이 기본 모드, enable-samplingenable-systrace옵션은 포함되지 않음

contentTracing.stopRecording(resultFilePath, callback)

모든 프로세스에서 레코딩을 중지합니다.

Child 프로세스는 일반적으로 추적 데이터와 희귀한 플러시 그리고 추적 데이터를 메인 프로세스로 보내는 작업에 대해 캐싱 합니다. 이러한 일을 하는 이유는 IPC를 통해 추적 데이터를 보내는 작업은 매우 비싼 연산을 동반하기 때문입니다. 우리는 추적에 의한 런타임 오버헤드를 피하고자 합니다. 그래서 추적이 끝나면 모든 child 프로세스에 보류된 추적 데이터를 플러시 할 것인지 물어봅니다.

모든 child 프로세스가 stopRecording 요청을 승인하면 callback에 추적 데이터 파일을 포함하여 한 번 호출됩니다.

추적 데이터는 resultFilePath 해당 경로가 비어있는 경우에 한 해 해당 경로에 작성되거나 임시 파일에 작성됩니다. 실제 파일 경로는 null이 아닌 이상 callback을 통해 전달됩니다.

contentTracing.startMonitoring(options, callback)

모든 프로세스에서 모니터링을 시작합니다.

모니터링은 지역적으로 즉시 시작됩니다. 그리고 이내 자식 프로세스들이 startMonitoring 비동기 요청을 받습니다.

모든 자식 프로세스가 startMonitoring 요청을 승인하면 callback이 한 번 호출됩니다.

contentTracing.stopMonitoring(callback)

모든 프로세스에서 모니터링을 중단합니다.

모든 자식 프로세스가 stopMonitoring 요청을 승인하면 callback이 한 번 호출됩니다.

contentTracing.captureMonitoringSnapshot(resultFilePath, callback)

현재 모니터링 추적 데이터를 가져옵니다.

자식 프로세스들은 일반적으로 추적 데이터를 캐싱하며 드물게 플러시 하거나 메인 프로세스로 추적 데이터를 보냅니다. 왜냐하면 IPC를 통해 추적 데이터를 보내는데에는 많은 자원을 소비하기 때문입니다. 그리고 우리는 추적시 발생하는 불필요한 런타임 오버헤드를 피하고자 합니다. 그래서 추적이 끝나면 반드시 비동기로 자식 프로세스들의 보류된 추적 데이터를 플러시 할 것인지 물어봅니다.

모든 자식 프로세스가 captureMonitoringSnapshot 요청을 승인하면 추적 데이터 파일을 포함하는 callback이 한 번 호출됩니다.

contentTracing.getTraceBufferUsage(callback)

추적 버퍼 % 전체 상태의 프로세스간 최대치를 가져옵니다. TraceBufferUsage 값이 결정되면 callback이 한 번 호출됩니다.

contentTracing.setWatchEvent(categoryName, eventName, callback)

callback은 지정된 이벤트가 어떤 작업을 발생시킬 때마다 호출됩니다.

contentTracing.cancelWatchEvent()

Watch 이벤트를 중단합니다. 만약 추적이 활성화되어 있다면 이 메서드는 watch 이벤트 콜백과 race가 일어날 것입니다.


crashReporter

원격 서버에 오류 보고를 제출합니다.

다음은 윈격 서버에 애플리케이션 오류 보고를 자동으로 제출하는 예시입니다:

const {crashReporter} = require('electron')

crashReporter.start({
  productName: 'YourName',
  companyName: 'YourCompany',
  submitURL: 'https://your-domain.com/url-to-submit',
  autoSubmit: true
})

서버가 오류 보고를 허용하고 처리할 수 있게 설정하기 위해, 다음 프로젝트를 사용할 수 있습니다:

오류 보고서는 애플리케이션에 명시된 로컬 임시 디렉토리 폴더에 저장됩니다. YourNameproductName 의 경우, 오류 보고서는 임시 디렉토리 내의 YourName Crashes 폴더에 저장됩니다. 오류 보고자를 시작하기전에 app.setPath('temp', '/my/custom/temp') API 를 호출하여 이 임시 디렉토리 경로를 정의할 수 있습니다.

Methods

crash-reporter 모듈은 다음과 같은 메서드를 가지고 있습니다:

crashReporter.start(options)

다른 crashReporter API를 사용하기 전에 이 메서드를 먼저 호출해야 합니다.

참고: macOS에선 Windows와 Linux의 breakpad와 달리 새로운 crashpad 클라이언트를 사용합니다. 오류 수집 기능을 활성화 시키려면 오류를 수집하고 싶은 메인 프로세스나 렌더러 프로세스에서 crashReporter.start 메서드를 호출하여 crashpad 를 초기화해야 합니다.

crashReporter.getLastCrashReport()

Returns Object: * date String * ID Integer

마지막 오류 보고의 날짜와 ID를 반환합니다. 이전 오류 보고가 없거나 오류 보고자가 시작되지 않았을 경우 null이 반환됩니다.

crashReporter.getUploadedReports()

Returns Object[]: * date String * ID Integer

모든 업로드된 오류 보고를 반환합니다. 각 보고는 날짜와 업로드 ID를 포함하고 있습니다.

crash-reporter 업로드 형식

오류 보고자는 다음과 같은 데이터를 submitURL multipart/form-data POST 방식으로 전송합니다:


desktopCapturer

멀티미디어 소스에 대해 접근하고 navigator.webkitGetUserMedia API를 통해 오디오나 비디오를 데스크톱으로부터 캡쳐할 수 있도록 합니다.

다음 예시는 창 제목이 Electron인 데스크톱 창에 대해 비디오 캡쳐하는 방법을 보여줍니다.

// 렌더러 프로세스에서.
const {desktopCapturer} = require('electron')

desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => {
  if (error) throw error
  for (let i = 0; i < sources.length; ++i) {
    if (sources[i].name === 'Electron') {
      navigator.webkitGetUserMedia({
        audio: false,
        video: {
          mandatory: {
            chromeMediaSource: 'desktop',
            chromeMediaSourceId: sources[i].id,
            minWidth: 1280,
            maxWidth: 1280,
            minHeight: 720,
            maxHeight: 720
          }
        }
      }, handleStream, handleError)
      return
    }
  }
})

function handleStream (stream) {
  document.querySelector('video').src = URL.createObjectURL(stream)
}

function handleError (e) {
  console.log(e)
}

desktopCapturer로부터 제공된 소스로부터 비디오 캡쳐를 하려면 navigator.webkitGetUserMedia로 전달되는 속성에 chromeMediaSource: 'desktop', 와 audio: false 가 반드시 포함되어야 합니다.

전체 데스크톱의 오디오와 비디오를 모두 캡쳐하려면 navigator.webkitGetUserMedia로 전달되는 속성에 chromeMediaSource: 'screen', 와 audio: true 가 반드시 포함되어야 하지만 chromeMediaSourceId 속성은 포함되어선 안됩니다.

Methods

desktopCapturer 모듈은 다음과 같은 메서드를 가지고 있습니다:

desktopCapturer.getSources(options, callback)

사용할 수 있는 데스크톱 미디어 소스를 가져오기 시작하고 작업이 완료되면 callback(error, sources)가 호출됩니다.

sourcesSource객체의 배열이며, 각 Source는 캡쳐될 수 있는 스크린과 각기 윈도우를 표현합니다. 그리고 다음과 같은 속성을 가지고 있습니다:


dialog

파일을 열거나 저장하고, 알림을 표시하기 위한 네이티브 시스템 대화 상자를 표시합니다.

다음 예시는 파일과 디렉터리를 다중으로 선택하는 대화 상자를 표시하는 예시입니다:

const {dialog} = require('electron')
console.log(dialog.showOpenDialog({properties: ['openFile', 'openDirectory', 'multiSelections']}))

대화 상자는 Electron의 메인 스레드에서 열립니다. 만약 렌더러 프로세스에서 대화 상자 객체를 사용하고 싶다면, remote를 통해 접근하는 방법을 고려해야 합니다:

const {dialog} = require('electron').remote
console.log(dialog)

Methods

dialog 모듈은 다음과 같은 메서드를 가지고 있습니다:

dialog.showOpenDialog([browserWindow, ]options[, callback])

사용할 대화 상자의 기능이 담긴 배열입니다. 다음을 포함할 수 있습니다: openFile, openDirectory, multiSelections, createDirectory

작업에 성공하면 콜백으로 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외의 경우엔 undefined를 반환합니다.

filters를 지정하면 유저가 선택 가능한 파일 형식을 지정할 수 있습니다. 유저가 선택할 수 있는 타입에 제한을 두려면 다음과 같이 할 수 있습니다:

{
  filters: [
    {name: 'Images', extensions: ['jpg', 'png', 'gif']},
    {name: 'Movies', extensions: ['mkv', 'avi', 'mp4']},
    {name: 'Custom File Type', extensions: ['as']},
    {name: 'All Files', extensions: ['*']}
  ]
}

extensions 배열은 반드시 와일드카드와 마침표를 제외한 파일 확장자를 포함시켜야 합니다. (예를 들어 'png'는 가능하지만 '.png''*.png'는 안됩니다) 모든 파일을 보여주려면 '*'와 같은 와일드카드를 사용하면 됩니다. (다른 와일드카드는 지원하지 않습니다)

callback이 전달되면 메서드가 비동기로 작동되며 결과는 callback(filenames)을 통해 전달됩니다.

참고: Windows와 Linux에선 파일 선택 모드, 디렉터리 선택 모드를 동시에 사용할 수 없습니다. 이러한 이유로 properties['openFile', 'openDirectory']로 설정하면 디렉터리 선택 대화 상자가 표시됩니다.

dialog.showSaveDialog([browserWindow, ]options[, callback])

작업에 성공하면 콜백으로 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외엔 undefined를 반환합니다.

filters를 지정하면 유저가 저장 가능한 파일 형식을 지정할 수 있습니다. 사용 방법은 dialog.showOpenDialogfilters 속성과 같습니다.

callback이 전달되면 메서드가 비동기로 작동되며 결과는 callback(filename)을 통해 전달됩니다.

dialog.showMessageBox([browserWindow, ]options[, callback])

대화 상자를 표시합니다. browserWindow를 지정하면 대화 상자가 완전히 닫힐 때까지 지정한 창을 사용할 수 없습니다. 완료 시 유저가 선택한 버튼의 인덱스를 반환합니다.

역자주: 부정을 표현하는 “아니오”, “취소”와 같은 한글 단어는 지원되지 않습니다. 만약 macOS 또는 Windows에서 “확인”, “취소”와 같은 순서로 버튼을 지정하게 될 때 Alt + f4로 해당 대화 상자를 끄게 되면 “확인”을 누른 것으로 판단되어 버립니다. 이를 해결하려면 “Cancel”을 대신 사용하거나 BrowserWindow API를 사용하여 대화 상자를 직접 구현해야 합니다.

callback이 전달되면 메서드가 비동기로 작동되며 결과는 callback(response)을 통해 전달됩니다.

dialog.showErrorBox(title, content)

에러 메시지를 보여주는 대화 상자를 표시합니다.

이 함수는 app 모듈의 ready 이벤트가 발생하기 전까지 사용할 수 있습니다. 이 메서드는 보통 애플리케이션이 시작되기 전에 특정한 에러를 표시하기 위해 사용됩니다. 만약 Linux에서 ready 이벤트가 발생하기 전에 이 API를 호출할 경우, 메시지는 stderr를 통해서 표시되며 GUI 대화 상자는 표시되지 않습니다.

Sheets

macOS에선, browserWindow 인수에 BrowserWindow 객체 참조를 전달하면 대화 상자가 해당 윈도우에 시트처럼 표시되도록 표현할 수 있습니다. 윈도우의 객체 참조가 제공되지 않으면 모달 형태로 표시됩니다.

BrowserWindow.getCurrentWindow().setSheetOffset(offset)을 통해 윈도우에 부착될 시트의 위치를 조정할 수 있습니다.


DownloadItem

원격 소스로부터의 파일 다운로드를 제어합니다.

DownloadItemEventEmitter를 상속받았으며 Electron의 다운로드 아이템을 표현합니다. 이 클래스 객체는 Session 클래스의 will-download 이벤트에 사용되며 사용자가 다운로드 아이템을 다룰 수 있도록 도와줍니다.

// 메인 프로세스
win.webContents.session.on('will-download', (event, item, webContents) => {
  // Set the save path, making Electron not to prompt a save dialog.
  item.setSavePath('/tmp/save.pdf')

  item.on('updated', (event, state) => {
    if (state === 'interrupted') {
      console.log('Download is interrupted but can be resumed')
    } else if (state === 'progressing') {
      if (item.isPaused()) {
        console.log('Download is paused')
      } else {
        console.log(`Received bytes: ${item.getReceivedBytes()}`)
      }
    }
  })
  item.once('done', (event, state) => {
    if (state === 'completed') {
      console.log('Download successfully')
    } else {
      console.log(`Download failed: ${state}`)
    }
  })
})

Events

Event: ‘updated’

Returns:

다운로드가 업데이트되었으며 아직 끝나지 않았을 때 발생하는 이벤트입니다.

state는 다음 중 하나가 될 수 있습니다:

Event: ‘done’

Returns:

다운로드가 종료될 때 발생하는 이벤트입니다. 이 이벤트는 다운로드 중 문제가 발생하여 중단되거나, 모두 성공적으로 완료된 경우, downloadItem.cancel() 같은 메서드를 통해 취소하는 경우의 종료 작업이 모두 포함됩니다.

state는 다음 중 하나가 될 수 있습니다:

Methods

downloadItem 객체는 다음과 같은 메서드를 가지고 있습니다:

downloadItem.setSavePath(path)

이 API는 세션의 will-download 콜백 함수에서만 사용할 수 있습니다. 사용자가 API를 통해 아무 경로도 설정하지 않을 경우 Electron은 기본 루틴 파일 저장을 실행합니다. (파일 대화 상자를 엽니다)

downloadItem.getSavePath()

Returns String - 다운로드 아이템의 저장 경로. 이 경로는 downloadItem.setSavePath(path)로 설정된 경로나 나타난 저장 대화상자에서 선택한 경로 중 하나가 될 수 있습니다.

downloadItem.pause()

다운로드를 일시 중지합니다.

downloadItem.isPaused()

Returns Boolean - 다운로드가 일시 중지되었는지 여부.

downloadItem.resume()

중디된 다운로드를 재개합니다.

downloadItem.canResume()

Returns Boolean - 다운로드를 재개할 수 있는지 여부.

downloadItem.cancel()

다운로드를 취소합니다.

downloadItem.getURL()

Returns String - 아이템을 다운로드 한 URL.

downloadItem.getMimeType()

Returns String - 파일의 MIME 타입.

downloadItem.hasUserGesture()

Returns Boolean - 유저 제스쳐(작업)로인한 다운로드인지 여부.

downloadItem.getFilename()

Returns String - 다운로드 아이템의 파일 이름.

참고: 실제 파일 이름과 로컬 디스크에 저장되는 파일의 이름은 서로 다를 수 있습니다. 예를 들어 만약 사용자가 파일을 저장할 때 파일 이름을 바꿨다면 실제 파일 이름과 저장 파일 이름은 서로 달라지게 됩니다.

downloadItem.getTotalBytes()

Returns Integer - 다운로드 아이템의 바이트 단위의 전체 크기. 크기를 알 수 없으면 0.

downloadItem.getReceivedBytes()

Returns Integer - 다운로드 아이템의 수신된 바이트.

downloadItem.getContentDisposition()

Return String - 응답 헤더의 Content-Disposition 필드.

downloadItem.getState()

Return String - 현재 상태.

값은 다음이 될 수 있습니다:


환경 변수

애플리케이션의 구성과 동작을 코드 변경 없이 제어합니다.

특정 Electron 동작은 명령줄 플래그와 애플리케이션의 코드보다 먼저 초기화되어야 하므로 환경 변수에 의해 작동합니다.

POSIX 쉘의 예시입니다:

$ export ELECTRON_ENABLE_LOGGING=true
$ electron

Windows 콘솔의 예시입니다:

> set ELECTRON_ENABLE_LOGGING=true
> electron

제품 변수

다음 환경 변수는 Electron 애플리케이션 패키지 실행에 우선적으로 사용됩니다.

GOOGLE_API_KEY

Electron 은 하드코딩 된 구글의 위치정보 웹서비스 요청을 위한 API 키를 포함하고 있습니다. 이 API 키가 모든 버전의 Electron 에 포함되어 있기 때문에 종종 사용량을 초과합니다. 이 문제를 해결하기 위해 자신의 구글 API 키를 사용할 수 있습니다. 메인 프로세스 파일에 다음 코드를 위치정보 요청이 있는 브라우저를 열기 전에 넣어주세요.

process.env.GOOGLE_API_KEY = 'YOUR_KEY_HERE'

구글 API 키를 획득하는 방법은 다음 페이지를 참고하세요. https://www.chromium.org/developers/how-tos/api-keys

기본적으로, 새로 생성된 구글 API 키는 위치정보 요청이 허용되지 않습니다. 위치정보 요청을 사용하려면 다음 페이지를 방문하세요: https://console.developers.google.com/apis/api/geolocation/overview

ELECTRON_NO_ASAR

ASAR 지원을 비활성화합니다. 이 변수는 분기된 자식 프로세스와 ELECTRON_RUN_AS_NODE 를 설정하여 생산된 자식 프로세스에서만 지원됩니다.

개발 변수

다음 환경 변수는 개발과 디버깅시 우선적으로 사용됩니다.

ELECTRON_RUN_AS_NODE

프로세스를 일반 Node.js 프로세스처럼 시작합니다. (electron 모듈 제외)

ELECTRON_ENABLE_LOGGING

Chrome의 내부 로그를 콘솔에 출력합니다.

ELECTRON_LOG_ASAR_READS

Electron이 ASAR 파일을 읽을 때, 읽기 오프셋의 로그를 남기고 시스템 tmpdir에 파일로 저장합니다. 결과 파일은 ASAR 모듈의 파일 순서를 최적화 하는데 사용할 수 있습니다.

ELECTRON_ENABLE_STACK_DUMPING

Electron이 크래시되면, 콘솔에 stack trace를 출력합니다.

이 환경 변수는 crashReporter가 시작되지 않았을 경우 작동하지 않습니다.

ELECTRON_DEFAULT_ERROR_MODE Windows

Electron이 크래시되면 스택 출력 정보를 콘솔에 출력합니다.

이 환경 변수는 crashReporter가 시작되지 않았을 경우 작동하지 않습니다.

ELECTRON_NO_ATTACH_CONSOLE Windows

현재 콘솔 세션에 소속시키지 않습니다.

ELECTRON_FORCE_WINDOW_MENU_BAR Linux

Linux의 전역 메뉴바를 사용하지 않습니다.


File 객체

HTML5 File API를 기본적인 파일 시스템의 파일처럼 사용합니다.

DOM의 File 인터페이스는 네이티브 파일을 추상화 합니다. 사용자가 직접 HTML5 File API를 사용하여 작업할 때 선택된 파일의 경로를 알 수 있도록, Electron은 파일의 실제 경로를 담은 path 속성을 File 인터페이스에 추가했습니다.

다음 예시는 앱으로 드래그 앤 드롭한 파일의 실제 경로를 가져옵니다:

<div id="holder">
  Drag your file here
</div>

<script>
  const holder = document.getElementById('holder');
  holder.ondragover = () => {
    return false;
  };
  holder.ondragleave = holder.ondragend = () => {
    return false;
  };
  holder.ondrop = (e) => {
    e.preventDefault();
    for (let f of e.dataTransfer.files) {
      console.log('File(s) you dragged here: ', f.path);
    }
    return false;
  };
</script>

Frameless 윈도우

툴바, 테두리, 시각적인 “chrome” 없이 윈도우를 엽니다.

Frameless 윈도우는 창 테두리가 없는 윈도우를 말합니다. 이 기능은 윈도우의 일부분인 툴바와 같이 웹 페이지의 일부분이 아닌 부분을 보이지 않도록 합니다. BrowserWindow 클래스의 옵션에서 설정할 수 있습니다.

Frameless 윈도우 만들기

Frameless 윈도우를 만드려면 BrowserWindow 객체의 options 객체에서 frame 옵션을 false로 지정하면 됩니다:

const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600, frame: false})

최신 macOS에서 사용할 수 있는 대안

macOS 10.9 Mavericks 이후의 최신 버전부터는 테두리가 없는 창을 만들 때 새로운 방법을 사용할 수 있습니다. frame 옵션을 false로 지정하여 제목과 창 구성 요소를 모두 비활성화하는 대신 새로운 titleBarStyle 옵션을 통해 제목만 숨기고 창 구성 요소 (“신호등 버튼”)의 기능과 창 크기를 그대로 유지할 수 있습니다:

let win = new BrowserWindow({titleBarStyle: 'hidden'})

투명한 창 만들기

Frameless 윈도우 창의 배경을 투명하게 만들고 싶다면 transparent 옵션을 true로 바꿔주기만 하면됩니다:

let win = new BrowserWindow({transparent: true, frame: false})

API의 한계

클릭이 통과될 수 있는 윈도우

클릭이 통과될 수 있는 윈도우를 만드려면, i.e. 모든 마우스 이벤트를 무시하는 윈도우를 만드려면, win.setIgnoreMouseEvents(ignore) API를 사용하여 구현할 수 있습니다:

win.setIgnoreMouseEvents(true)

드래그 가능 위치 지정

기본적으로 Frameless 윈도우는 드래그 할 수 없습니다. 애플리케이션의 CSS에서 특정 범위를 -webkit-app-region: drag로 지정하면 OS의 기본 타이틀 바 처럼 드래그 되도록 할 수 있습니다. 그리고 -webkit-app-region: no-drag를 지정해서 드래그 불가능 영역을 만들 수도 있습니다. 현재 사각형 형태의 범위만 지원합니다.

창 전체를 드래그 가능하게 만드려면 -webkit-app-region: dragbody의 스타일에 지정하면 됩니다:

<body style="-webkit-app-region: drag">
</body>

참고로 창 전체를 드래그 영역으로 지정할 경우 사용자가 버튼을 클릭할 수 없게 되므로 버튼은 드래그 불가능 영역으로 지정해야 합니다:

button {
  -webkit-app-region: no-drag;
}

따로 커스텀 타이틀 바를 만들어 사용할 때는 타이틀 바 내부의 모든 버튼을 드래그 불가 영역으로 지정해야 합니다.

텍스트 선택

Frameless 윈도우에서 텍스트가 선택되는 드래그 동작은 혼란을 야기할 수 있습니다. 예를 들어 타이틀 바를 드래그 할 때 타이틀 바의 텍스트를 실수로 선택할 수 있습니다. 이를 방지하기 위해 다음과 같이 드래그 영역의 텍스트 선택 기능을 비활성화해야 할 필요가 있습니다:

.titlebar {
  -webkit-user-select: none;
  -webkit-app-region: drag;
}

컨텍스트 메뉴

몇몇 플랫폼에선 드래그 가능 영역이 non-client 프레임으로 처리됩니다. 이러한 플랫폼에선 드래그 가능 영역에서 오른쪽 클릭 할 경우 시스템 메뉴가 팝업 됩니다. 이러한 이유로 컨텍스트 메뉴 지정 시 모든 플랫폼에서 정상적으로 작동하게 하려면 커스텀 컨텍스트 메뉴를 드래그 영역 내에 만들어선 안됩니다.


globalSortcut

애플리케이션에 키보드 포커스가 없을 때도 키보드 이벤트를 받을 수 있도록 합니다.

globalShortcut 모듈은 운영체제의 전역 키보드 단축키를 등록/해제 하는 방법을 제공합니다. 이 모듈을 사용하여 사용자가 다양한 작업을 편하게 할 수 있도록 단축키를 정의 할 수 있습니다.

참고: 등록된 단축키는 애플리케이션이 백그라운드로 작동(창이 포커스 되지 않음) 할 때도 계속해서 작동합니다. 이 모듈은 app 모듈의 ready 이벤트가 발생하기 전까지 사용할 수 없습니다.

const {app, globalShortcut} = require('electron')

app.on('ready', () => {
  // 'CommandOrControl+X' 단축키를 리스너에 등록합니다.
  const ret = globalShortcut.register('CommandOrControl+X', () => {
    console.log('CommandOrControl+X is pressed')
  })

  if (!ret) {
    console.log('registration failed')
  }

  // 단축키가 등록되었는지 확인합니다.
  console.log(globalShortcut.isRegistered('CommandOrControl+X'))
})

app.on('will-quit', () => {
  // 단축키의 등록을 해제합니다.
  globalShortcut.unregister('CommandOrControl+X')

  // 모든 단축키의 등록을 해제합니다.
  globalShortcut.unregisterAll()
})

Methods

globalShortcut 모듈은 다음과 같은 메서드를 가지고 있습니다:

globalShortcut.register(accelerator, callback)

accelerator의 전역 단축키를 등록합니다. 유저로부터 등록된 단축키가 눌렸을 경우 callback 함수가 호출됩니다.

accelerator가 이미 다른 애플리케이션에서 사용 중일 경우, 이 작업은 조용히 실패합니다. 이러한 동작은 애플리케이션이 전역 키보드 단축키를 가지고 충돌이 일어나지 않도록 하기 위해 운영체제에 의해 예정된 동작입니다.

globalShortcut.isRegistered(accelerator)

Returns Boolean - accelerator 가 등록되었는지 여부.

Accelerator가 이미 다른 애플리케이션에서 사용 중일 경우, 여전히 false를 반환합니다. 이러한 동작은 애플리케이션이 전역 키보드 단축키를 가지고 충돌이 일어나지 않도록 하기 위해 운영체제에 의해 예정된 동작입니다.

globalShortcut.unregister(accelerator)

accelerator에 해당하는 전역 단축키를 등록 해제합니다.

globalShortcut.unregisterAll()

모든 전역 단축키의 등록을 해제합니다.


ipcMain

메인 프로세스에서 렌더러 프로세스로 비동기 통신을 합니다.

ipcMain 모듈은 EventEmitter 클래스의 인스턴스입니다. 메인 프로세스에서 사용하면, 렌더러 프로세스(웹 페이지)에서 전달된 동기, 비동기 메시지를 주고 받는 방법을 제공합니다. 렌더러 프로세스에서 메시지를 전달하면 이 모듈을 통해 메시지를 받을 수 있습니다.

메시지 전송

물론 메시지를 받는 것 말고도 메인 프로세스에서 렌더러 프로세스로 보내는 것도 가능합니다. 자세한 내용은 webContents.send를 참고하세요.

다음 예시는 렌더러 프로세스와 메인 프로세스간에 메시지를 전달하고 받는 예시입니다:

// 메인 프로세스
const {ipcMain} = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg)  // "ping" 출력
  event.sender.send('asynchronous-reply', 'pong')
})

ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg)  // "ping" 출력
  event.returnValue = 'pong'
})
// 렌더러 프로세스 (웹 페이지)
const {ipcRenderer} = require('electron')
console.log(ipc.sendSync('synchronous-message', 'ping')) // "pong" 출력

ipcRenderer.on('asynchronous-reply', (arg) => {
  console.log(arg) // "pong" 출력
})
ipcRenderer.send('asynchronous-message', 'ping')

메시지 리스닝

ipcMain은 다음과 같은 이벤트 리스닝 메서드를 가지고 있습니다:

ipcMain.on(channel, listener)

channel에 대해 이벤트를 리스닝합니다. 새로운 메시지가 도착하면 listenerlistener(event, args...) 형식으로 호출됩니다.

ipcMain.once(channel, listener)

이벤트에 대해 한 번만 작동하는 listener 함수를 등록합니다. 이 listener는 등록된 후 channel에 보내지는 메시지에 한해 호출됩니다. 호출된 이후엔 리스너가 삭제됩니다.

ipcMain.removeListener(channel, listener)

메시지 수신을 완료한 후, 더 이상의 콜백이 필요하지 않을 때 또는 몇 가지 이유로 채널의 메시지 전송을 멈출수 없을 때, 이 함수를 통해 지정한 채널에 대한 콜백을 삭제할 수 있습니다.

지정한 channel에 대한 리스너를 저장하는 배열에서 지정한 listener를 삭제합니다.

ipcMain.removeAllListeners(channel)

이 ipc 채널에 등록된 모든 핸들러들을 삭제하거나 지정한 channel을 삭제합니다.

Event 객체

callback에서 전달된 event 객체는 다음과 같은 메서드와 속성을 가지고 있습니다:

event.returnValue

이 메시지를 지정하면 동기 메시지를 전달합니다.

event.sender

메시지를 보낸 webContents 객체를 반환합니다. event.sender.send 메서드를 통해 비동기로 메시지를 전달할 수 있습니다. 자세한 내용은 webContents.send를 참고하세요.


ipcRenderer

렌더러 프로세스에서 메인 프로세스로 비동기 통신을 합니다.

ipcRenderer 모듈은 EventEmitter 클래스의 인스턴스입니다. 렌더러 프로세스에서 메인 프로세스로 동기/비동기 메시지를 주고 받는 방법을 제공합니다. 또한 메인 프로세스로부터 받은 메시지에 응답할 수도 있습니다.

ipcMain에서 코드 예시를 확인할 수 있습니다.

메시지 리스닝

ipcRenderer는 다음과 같은 이벤트 리스닝 메서드를 가지고 있습니다:

ipcRenderer.on(channel, listener)

channel에 대해 이벤트를 리스닝합니다. 새로운 메시지가 도착하면 listenerlistener(event, args...) 형식으로 호출됩니다.

ipcRenderer.once(channel, listener)

이벤트에 대해 한 번만 작동하는 listener 함수를 등록합니다. 이 listener는 등록된 후 channel에 보내지는 메시지에 한해 호출됩니다. 호출된 이후엔 리스너가 삭제됩니다.

ipcRenderer.removeListener(channel, listener)

메시지 수신을 완료한 후, 더 이상의 콜백이 필요하지 않을 때 또는 몇 가지 이유로 채널의 메시지 전송을 멈출수 없을 때, 이 함수를 통해 지정한 채널에 대한 콜백을 삭제할 수 있습니다.

지정한 channel에 대한 리스너를 저장하는 배열에서 지정한 listener를 삭제합니다.

ipcRenderer.removeAllListeners(channel)

이 ipc 채널에 등록된 모든 핸들러들을 삭제하거나 지정한 channel을 삭제합니다.

메시지 보내기

ipcRenderer는 다음과 같은 메시지 전송 메서드를 가지고 있습니다:

ipcRenderer.send(channel[, arg1][, arg2][, ...])

channel을 통해 메인 프로세스에 비동기 메시지를 보냅니다. 그리고 필요에 따라 임의의 인수를 사용할 수도 있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와 프로토타입 체인은 포함되지 않게 됩니다.

메인 프로세스는 ipcMain 모듈의 channel 이벤트를 통해 이벤트를 리스닝 할 수 있습니다.

ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])

channel을 통해 메인 프로세스에 동기 메시지를 보냅니다. 그리고 필요에 따라 임의의 인수를 사용할 수도 있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와 프로토타입 체인은 포함되지 않게 됩니다.

메인 프로세스는 ipcMain 모듈을 통해 channel 이벤트를 리스닝 할 수 있고, event.returnValue로 회신 할 수 있습니다.

참고: 동기 메서드는 모든 렌더러 프로세스의 작업을 일시 중단시킵니다. 사용 목적이 확실하지 않다면 사용하지 않는 것이 좋습니다.

ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])

ipcRenderer.send와 비슷하지만 이벤트를 메인 프로세스 대신 호스트 페이지내의 <webview> 요소로 보냅니다.


로케일

app.getLocale()에서 반환되는 로케일 값.

Electron은 로케일을 가져오기 위해 Chromium의 l10n_util 라이브러리를 사용합니다. 반환될 수 있는 값은 다음과 같습니다:

언어 코드 언어 이름
af Afrikaans
ar-AE Arabic (U.A.E.)
ar-IQ Arabic (Iraq)
ar Arabic (Standard)
ar-BH Arabic (Bahrain)
ar-DZ Arabic (Algeria)
ar-EG Arabic (Egypt)
ar Aragonese
ar-JO Arabic (Jordan)
ar-KW Arabic (Kuwait)
ar-LB Arabic (Lebanon)
ar-LY Arabic (Libya)
ar-MA Arabic (Morocco)
ar-OM Arabic (Oman)
ar-QA Arabic (Qatar)
ar-SA Arabic (Saudi Arabia)
ar-SY Arabic (Syria)
ar-TN Arabic (Tunisia)
ar-YE Arabic (Yemen)
as Assamese
ast Asturian
az Azerbaijani
be Belarusian
bg Bulgarian
bg Bulgarian
bn Bengali
br Breton
bs Bosnian
ca Catalan
ce Chechen
ch Chamorro
co Corsican
cr Cree
cs Czech
cv Chuvash
da Danish
de German (Standard)
de-AT German (Austria)
de-CH German (Switzerland)
de-DE German (Germany)
de-LI German (Liechtenstein)
de-LU German (Luxembourg)
el Greek
en-AU English (Australia)
en-BZ English (Belize)
en English
en-CA English (Canada)
en-GB English (United Kingdom)
en-IE English (Ireland)
en-JM English (Jamaica)
en-NZ English (New Zealand)
en-PH English (Philippines)
en-TT English (Trinidad & Tobago)
en-US English (United States)
en-ZA English (South Africa)
en-ZW English (Zimbabwe)
eo Esperanto
et Estonian
eu Basque
fa Persian
fa Farsi
fa-IR Persian/Iran
fi Finnish
fj Fijian
fo Faeroese
fr-CH French (Switzerland)
fr-FR French (France)
fr-LU French (Luxembourg)
fr-MC French (Monaco)
fr French (Standard)
fr-BE French (Belgium)
fr-CA French (Canada)
fur Friulian
fy Frisian
ga Irish
gd-IE Gaelic (Irish)
gd Gaelic (Scots)
gl Galacian
gu Gujurati
he Hebrew
hi Hindi
hr Croatian
ht Haitian
hu Hungarian
hy Armenian
id Indonesian
is Icelandic
it-CH Italian (Switzerland)
it Italian (Standard)
iu Inuktitut
ja Japanese
ka Georgian
kk Kazakh
km Khmer
kn Kannada
ko Korean
ko-KP Korean (North Korea)
ko-KR Korean (South Korea)
ks Kashmiri
ky Kirghiz
la Latin
lb Luxembourgish
lt Lithuanian
lv Latvian
mi Maori
mk FYRO Macedonian
ml Malayalam
mo Moldavian
mr Marathi
ms Malay
mt Maltese
my Burmese
nb Norwegian (Bokmal)
ne Nepali
ng Ndonga
nl Dutch (Standard)
nl-BE Dutch (Belgian)
nn Norwegian (Nynorsk)
no Norwegian
nv Navajo
oc Occitan
om Oromo
or Oriya
sq Albanian
tlh Klingon
zh-TW Chinese (Taiwan)
zh Chinese
zh-CN Chinese (PRC)
zh-HK Chinese (Hong Kong)
zh-SG Chinese (Singapore)

MenuItem

네이티브 애플리케이션 메뉴와 컨텍스트 메뉴에 아이템을 추가합니다.

Menu에서 예시를 확인할 수 있습니다.

Class: MenuItem

MenuItem 인스턴스 객체에서 사용할 수 있는 메서드입니다:

new MenuItem(options)

어떠한 메뉴 아이템이 표준 롤에 일치한다면, role을 지정하는 것이 동작을 click 함수로 일일이 구현하려 시도하는 것 보다 더 좋을 수 있습니다. 빌트-인 role 동작은 더 좋은 네이티브 경험을 제공할 것입니다.

role을 사용하는 동안에는 labelaccelerator는 필수가 아니며 각 플랫폼에 대해 적합한 값이 기본값으로 사용됩니다.

role 속성은 다음 값을 가질 수 있습니다:

macOS에서의 role은 다음 값을 추가로 가질 수 있습니다:

macOS에서는 role을 지정할 때, labelaccelerator만 MenuItem에 효과가 적용되도록 변경되며, 다른 옵션들은 모두 무시됩니다.

Instance Properties

다음은 MenuItem의 인스턴스에서 사용할 수 있는 속성입니다:

아이템이 활성화되어있는지 여부를 표시하는 Boolean 값입니다. 이 속성은 동적으로 변경될 수 있습니다.

아이템이 보여지고있는지 여부를 표시하는 Boolean 값입니다. 이 속성은 동적으로 변경될 수 있습니다.

아이템이 선택되어있는지 여부를 반환하는 Boolean 값입니다. 이 속성은 동적으로 변경될 수 있습니다.

checkbox 메뉴 아이템은 선택되면 checked 속성을 토글합니다.

radio 메뉴 아이템은 클릭되었을 때 checked 속성을 활성화 합니다. 그리고 같은 메뉴의 모든 인접한 아이템에 대한 속성이 꺼집니다.

추가적인 작업을 위해 click 함수를 추가할 수도 있습니다.


Menu

네이티브 애플리케이션 메뉴와 컨텍스트 메뉴를 생성합니다.

각 메뉴는 여러 개의 메뉴 아이템으로 구성되고 서브 메뉴를 가질 수도 있습니다.

예시

Menu 클래스는 메인 프로세스에서만 사용할 수 있지만, remote 모듈을 통해 랜더러 프로세스에서도 사용할 수 있습니다.

메인 프로세스

다음은 템플릿 API를 사용하여 메인 프로세스에서 어플리케이션 메뉴를 생성하는 예시입니다:

const {app, Menu} = require('electron')

const template = [
  {
    label: 'Edit',
    submenu: [
      {
        role: 'undo'
      },
      {
        role: 'redo'
      },
      {
        type: 'separator'
      },
      {
        role: 'cut'
      },
      {
        role: 'copy'
      },
      {
        role: 'paste'
      },
      {
        role: 'pasteandmatchstyle'
      },
      {
        role: 'delete'
      },
      {
        role: 'selectall'
      }
    ]
  },
  {
    label: 'View',
    submenu: [
      {
        label: 'Reload',
        accelerator: 'CmdOrCtrl+R',
        click (item, focusedWindow) {
          if (focusedWindow) focusedWindow.reload()
        }
      },
      {
        label: 'Toggle Developer Tools',
        accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
        click (item, focusedWindow) {
          if (focusedWindow) focusedWindow.webContents.toggleDevTools()
        }
      },
      {
        type: 'separator'
      },
      {
        role: 'resetzoom'
      },
      {
        role: 'zoomin'
      },
      {
        role: 'zoomout'
      },
      {
        type: 'separator'
      },
      {
        role: 'togglefullscreen'
      }
    ]
  },
  {
    role: 'window',
    submenu: [
      {
        role: 'minimize'
      },
      {
        role: 'close'
      }
    ]
  },
  {
    role: 'help',
    submenu: [
      {
        label: 'Learn More',
        click () { require('electron').shell.openExternal('http://electron.atom.io') }
      }
    ]
  }
]

if (process.platform === 'darwin') {
  template.unshift({
    label: app.getName(),
    submenu: [
      {
        role: 'about'
      },
      {
        type: 'separator'
      },
      {
        role: 'services',
        submenu: []
      },
      {
        type: 'separator'
      },
      {
        role: 'hide'
      },
      {
        role: 'hideothers'
      },
      {
        role: 'unhide'
      },
      {
        type: 'separator'
      },
      {
        role: 'quit'
      }
    ]
  })
  // Edit menu.
  template[1].submenu.push(
    {
      type: 'separator'
    },
    {
      label: 'Speech',
      submenu: [
        {
          role: 'startspeaking'
        },
        {
          role: 'stopspeaking'
        }
      ]
    }
  )
  // Window menu.
  template[3].submenu = [
    {
      label: 'Close',
      accelerator: 'CmdOrCtrl+W',
      role: 'close'
    },
    {
      label: 'Minimize',
      accelerator: 'CmdOrCtrl+M',
      role: 'minimize'
    },
    {
      label: 'Zoom',
      role: 'zoom'
    },
    {
      type: 'separator'
    },
    {
      label: 'Bring All to Front',
      role: 'front'
    }
  ]
}

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

렌더러 프로세스

밑은 remote 모듈을 사용하여 동적으로 웹 페이지 (렌더러 프로세스)에서 메뉴를 직접적으로 생성하는 예시이며 오른쪽 클릭을 했을 때 메뉴를 표시합니다.

<!-- index.html -->
<script>
const {remote} = require('electron')
const {Menu, MenuItem} = remote

const menu = new Menu()
menu.append(new MenuItem({label: 'MenuItem1', click() { console.log('item 1 clicked') }}))
menu.append(new MenuItem({type: 'separator'}))
menu.append(new MenuItem({label: 'MenuItem2', type: 'checkbox', checked: true}))

window.addEventListener('contextmenu', (e) => {
  e.preventDefault()
  menu.popup(remote.getCurrentWindow())
}, false)
</script>

Class: Menu

new Menu()

새로운 메뉴를 생성합니다.

Static Methods

menu 클래스는 다음과 같은 정적 메서드를 가지고 있습니다:

지정한 menu를 애플리케이션 메뉴로 만듭니다. macOS에선 상단바에 표시되며 Windows와 Linux에선 각 창의 상단에 표시됩니다.

참고 이 API는 appready 이벤트가 발생한 이후에 호출해야 합니다.

설정되어있는 어플리케이션 메뉴를 반환합니다. (Menu의 인스턴스) 만약 없다면 null을 반환합니다.

action을 애플리케이션의 first responder에 전달합니다. 이 메서드는 Cocoa 메뉴 동작을 에뮬레이트 하는데 사용되며 보통 MenuItemrole 속성에 사용됩니다.

macOS의 네이티브 액션에 대해 자세히 알아보려면 macOS Cocoa Event Handling Guide 문서를 참고하세요.

기본적으로 templateMenuItem을 생성할 때 사용하는 options의 배열입니다. 사용법은 위에서 설명한 것과 같습니다.

또한 template에는 다른 속성도 추가할 수 있으며 메뉴가 만들어질 때 해당 메뉴 아이템의 프로퍼티로 변환됩니다.

Instance Methods

menu 객체는 다음과 같은 인스턴스 메서드를 가지고 있습니다:

메뉴를 browserWindow 내부 팝업으로 표시합니다.

메뉴의 리스트 끝에 menuItem을 삽입합니다.

pos 위치에 menuItem을 삽입합니다.

Instance Properties

menu 객체는 또한 다음과 같은 속성을 가지고 있습니다:

메뉴 아이템을 포함하는 MenuItem[] 배열.

macOS 애플리케이션 메뉴에 대해 알아 둬야 할 것들

macOS에선 Windows, Linux와 달리 완전히 다른 애플리케이션 메뉴 스타일을 가지고 있습니다. 그래서 애플리케이션을 네이티브처럼 작동할 수 있도록 하기 위해 다음 몇 가지 유의 사항을 숙지해야 합니다.

기본 메뉴

macOS엔 ServicesWindows와 같은 많은 시스템 지정 기본 메뉴가 있습니다. 기본 메뉴를 만들려면 반드시 다음 리스트 중 한 가지를 선택하여 메뉴의 role로 지정해야 합니다. 그러면 Electron이 자동으로 인식하여 해당 메뉴를 기본 메뉴로 만듭니다:

메뉴 아이템 기본 동작

macOS는 몇가지 메뉴 아이템에 대해 About xxx, Hide xxx, Hide Others와 같은 기본 동작을 제공하고 있습니다. 메뉴 아이템의 기본 동작을 지정하려면 반드시 메뉴 아이템의 role 속성을 지정해야 합니다.

메인 메뉴의 이름

macOS에선 지정한 애플리케이션 메뉴에 상관없이 메뉴의 첫번째 라벨은 언제나 애플리케이션의 이름이 됩니다. 애플리케이션 이름을 변경하려면 앱 번들내의 Info.plist 파일을 수정해야 합니다. 자세한 내용은 About Information Property List Files 문서를 참고하세요.

지정한 브라우저 윈도우에 메뉴 설정 (Linux Windows)

브라우저 윈도우의 setMenu 메서드는 어떤 브라우저 윈도우의 메뉴를 설정할 수 있습니다.

메뉴 아이템 위치

Menu.buildFromTemplate로 메뉴를 만들 때 positionid를 사용해서 아이템의 위치를 지정할 수 있습니다.

MenuItemposition 속성은 [placement]=[id]와 같은 형식을 가지며 placementbefore, after, endof 속성 중 한가지를 사용할 수 있고 id는 메뉴 아이템이 가지는 유일 ID 입니다:

위치를 지정한 아이템의 뒤에 위치가 지정되지 않은 아이템이 있을 경우 각 아이템의 위치가 지정되기 전까지 모든 아이템이 위치가 지정된 아이템의 뒤에 삽입됩니다. 따라서 위치를 이동하고 싶은 특정 그룹의 아이템들이 있을 경우 해당 그룹의 맨 첫번째 메뉴 아이템의 위치만을 지정하면 됩니다.

예시

메뉴 템플릿:

[
  {label: '4', id: '4'},
  {label: '5', id: '5'},
  {label: '1', id: '1', position: 'before=4'},
  {label: '2', id: '2'},
  {label: '3', id: '3'}
]

메뉴:

- 1
- 2
- 3
- 4
- 5

메뉴 템플릿:

[
  {label: 'a', position: 'endof=letters'},
  {label: '1', position: 'endof=numbers'},
  {label: 'b', position: 'endof=letters'},
  {label: '2', position: 'endof=numbers'},
  {label: 'c', position: 'endof=letters'},
  {label: '3', position: 'endof=numbers'}
]

메뉴:

- ---
- a
- b
- c
- ---
- 1
- 2
- 3

nativeImage

PNG 또는 JPG 파일을 사용하여 트레이, 독, 애플리케이션 아이콘을 생성합니다.

Electron은 파일 경로 또는 NativeImage 인스턴스를 통해 이미지를 사용할 수 있는 API를 가지고 있습니다. null을 전달할 경우 빈 이미지가 생성됩니다.

예를 들어 트레이 메뉴를 만들거나 윈도우의 아이콘을 설정할 때 다음과 같이 파일 경로를 전달하여 이미지를 사용할 수 있습니다:

const appIcon = new Tray('/Users/somebody/images/icon.png')
let win = new BrowserWindow({icon: '/Users/somebody/images/window.png'})

이 예시는 클립보드로부터 가져온 nativeImage로 트레이 메뉴를 생성합니다:

const image = clipboard.readImage()
const appIcon = new Tray(image)

지원하는 포맷

현재 PNGJPEG 이미지 포맷을 지원하고 있습니다. 손실 없는 이미지 압축과 투명도 지원을 위해 PNG 사용을 권장합니다.

Windows에서는 파일 경로로부터 ICO 포맷도 사용할 수 있으며, 가장 좋은 시각적 효과를 얻기 위해 최소한 다음 사이즈를 포함하는 것을 권장합니다:

이 글Size requirements 섹션을 확인하세요.

고해상도 이미지

플랫폼이 Apple Retina 디스플레이와 같이 high-DPI를 지원하는 경우 @2x와 같이 이미지의 파일명 뒤에 접미사를 추가하는 것으로 고해상도 이미지를 지정할 수 있습니다.

예를 들어 icon.png 라는 기본 해상도의 이미지를 기준으로 크기를 두 배로 늘린 이미지를 icon@2x.png 처럼 지정하면 고해상도 이미지로 처리됩니다.

서로 다른 해상도(DPI)의 이미지를 같이 지원하고 싶다면 다중 해상도의 이미지를 접미사를 붙여 한 폴더에 같이 넣으면 됩니다. 이 이미지를 사용(로드)할 땐 따로 접미사를 붙이지 않습니다:

images/
├── icon.png
├── icon@2x.png
└── icon@3x.png
let appIcon = new Tray('/Users/somebody/images/icon.png')

지원하는 DPI 접미사는 다음과 같습니다:

템플릿 이미지

템플릿 이미지는 검은색과 명확한 색상(알파 채널)으로 이루어져 있습니다. 템플릿 이미지는 단독 이미지로 사용되지 않고 다른 콘텐츠와 혼합되어 최종 외관 만드는데 사용됩니다.

가장 일반적으로 템플릿 이미지는 밝고 어두운 테마 색상으로 변경할 수 있는 메뉴 바 아이콘 등에 사용되고 있습니다.

참고: 템플릿 이미지는 macOS 운영체제만 지원합니다.

템플릿 이미지를 지정하려면 다음 예시와 같이 파일명에 Template 문자열을 추가해야 합니다:

Methods

nativeImage 모듈은 다음과 같은 메서드를 가지고 있으며, 모든 메서드는 NativeImage 클래스의 인스턴스를 반환합니다.

nativeImage.createEmpty()

Returns NativeImage

NativeImage 인스턴스를 만듭니다.

nativeImage.createFromPath(path)

Returns NativeImage

path로부터 이미지를 로드하여 새로운 NativeImage 인스턴스를 만듭니다. path 가 존재하지 않거나, 읽을 수 없거나, 유효한 이미지가 아니면 빈 이미지를 반환합니다.

const nativeImage = require('electron').nativeImage
let image = nativeImage.createFromPath('/Users/somebody/images/icon.png')

nativeImage.createFromBuffer(buffer[, scaleFactor])

Returns NativeImage

buffer로부터 이미지를 로드하여 새로운 NativeImage 인스턴스를 만듭니다. scaleFactor의 기본값은 1.0 입니다.

nativeImage.createFromDataURL(dataURL)

dataURL로부터 이미지를 로드하여 새로운 NativeImage 인스턴스를 만듭니다.

Class: NativeImage

네이티브로 랩핑된 트레이, dock, 애플리케이션 아이콘을 위한 이미지입니다.

Instance Methods

NativeImage 클래스 인스턴스 객체에서 사용할 수 있는 메서드입니다.

image.toPNG()

Return Buffer - PNG 로 인코딩된 데이터가 있는 Buffer.

image.toJPEG(quality)

Return Buffer - JPEG 로 인코딩된 데이터가 있는 Buffer.

image.toBitmap()

Return Buffer - 이미지의 raw 비트맵 픽셀 데이터가 있는 Buffer의 복사본.

image.toDataURL()

Returns String - 이미지의 data URL.

image.getBitmap()

Returns Buffer - 이미지의 raw 비트맵 픽셀 데이터가 있는 Buffer.

getBitmap()toBitmap()의 차이는 getBitmap()은 비트맵 데이터를 복사하지 않습니다. 그래서 버퍼를 현재 이벤트 루프 틱에 바로 반환해야 할 경우 유용하게 사용할 수 있습니다. 그렇지 않은 경우 데이터가 변경되거나 소멸될 수 있습니다.

image.getNativeHandle() macOS

Returns Buffer - 이미지의 네이티브 핸들의 C 포인터를 담은 Buffer. macOS에선, NSImage 인스턴스의 포인터가 반환됩니다.

참고로 반환된 포인터는 복사본이 아닌 네이티브 이미지의 밑에 있는 약한 포인터이며, 따라서 반드시 관련된 nativeImage 인스턴스가 확실하게 유지되고 있는지를 인지해야 합니다.

image.isEmpty()

Returns Boolean - 이미지가 비었는지 여부.

image.getSize()

Returns Object:

image.setTemplateImage(option)

해당 이미지를 템플릿 이미지로 설정합니다.

image.isTemplateImage()

Returns Boolean - 이미지가 템플릿 이미지인지 여부.

image.crop(rect)

Returns NativeImage - 잘라낸 이미지.

image.resize(options)

Returns NativeImage - 크기 변경된 이미지.

height 또는 width 하나만 명시한다면 크기가 변경된 이미지에서도 종횡비가 유지될 것 입니다.

image.getAspectRatio()

Returns Float - 이미지의 종횡비.


powerMonitor

파워의 상태 변경을 모니터링합니다.

이 모듈은 메인 프로세스에서만 사용할 수 있습니다. app 모듈의 ready 이벤트가 발생한 이후에만 사용할 수 없습니다.

예시:

const electron = require('electron')
const {app} = electron

app.on('ready', () => {
  electron.powerMonitor.on('suspend', () => {
    console.log('절전모드로 진입합니다!')
  })
})

Events

powerMonitor 모듈은 다음과 같은 이벤트를 가지고 있습니다:

Event: suspend

시스템이 절전모드로 진입할 때 발생하는 이벤트입니다.

Event: resume

시스템의 절전모드가 해제될 때 발생하는 이벤트입니다.

Event: on-ac Windows

시스템이 AC 어뎁터 충전기를 사용하기 시작할 때 발생하는 이벤트입니다.

Event: on-battery Windows

시스템이 배터리를 사용하기 시작할 때 발생하는 이벤트입니다.


powerSaveBlocker

시스템이 저전력 (슬립) 모드로 진입하는 것을 막습니다.

예시:

const {powerSaveBlocker} = require('electron')

const id = powerSaveBlocker.start('prevent-display-sleep')
console.log(powerSaveBlocker.isStarted(id))

powerSaveBlocker.stop(id)

Methods

powerSaveBlocker 모듈은 다음과 같은 메서드를 가지고 있습니다:

powerSaveBlocker.start(type)

시스템이 저전력 모드(슬립)로 진입하는 것을 막기 시작합니다. 정수로 된 식별 ID를 반환합니다.

참고: prevent-display-sleep 모드는 prevent-app-suspension 보다 우선 순위가 높습니다. 두 모드 중 가장 높은 우선 순위의 모드만 작동합니다. 다시 말해 prevent-display-sleep 모드는 언제나 prevent-app-suspension 모드의 효과를 덮어씌웁니다.

예를 들어 A-요청이 prevent-app-suspension 모드를 사용하고 B-요청이 prevent-display-sleep를 사용하는 API 호출이 있었다 하면 prevent-display-sleep 모드를 사용하는 B의 작동이 중단(stop)되기 전까지 작동하다 B가 중단되면 prevent-app-suspension 모드를 사용하는 A가 작동하기 시작합니다.

powerSaveBlocker.stop(id)

설정한 power save blocker를 중지합니다.

powerSaveBlocker.isStarted(id)

Returns Boolean - 지정한 id의 powerSaveBlocker가 실행 중인지 여부.


process

process 객체에 대한 확장 기능.

process 객체는 Electron에서 약간 추가적인 기능이 있으며 API는 다음과 같습니다:

Events

Event: ‘loaded’

Electron 내부 초기화 스크립트의 로드가 완료되고, 웹 페이지나 메인 스크립트를 로드하기 시작할 때 발생하는 이벤트입니다.

이 이벤트는 preload 스크립트를 통해 node 통합이 꺼져있는 전역 스코프에 node의 전역 심볼들을 다시 추가할 때 사용할 수 있습니다:

// preload.js
const _setImmediate = setImmediate
const _clearImmediate = clearImmediate
process.once('loaded', () => {
  global.setImmediate = _setImmediate
  global.clearImmediate = _clearImmediate
})

Properties

process.noAsar

이 속성을 true로 지정하면 Node 빌트인 모듈의 asar 아카이브 지원을 비활성화 시킬 수 있습니다.

process.type

현재 프로세스의 종류입니다. "browser" (메인 프로세스) 또는 "renderer"가 될 수 있습니다.

process.versions.electron

Electron의 버전 문자열입니다.

process.versions.chrome

Chrome의 버전 문자열입니다.

process.resourcesPath

리소스 디렉토리의 경로입니다.

process.mas

Mac App Store 빌드에선 이 속성이 true가 됩니다. 다른 빌드에선 undefined가 됩니다.

process.windowsStore

애플리케이션이 Windows Store 앱 (appx) 형태로 작동하고 있을 경우 이 속성이 true가 됩니다. 그렇지 않은 경우 undefined가 됩니다.

process.defaultApp

애플리케이션이 기본 어플리케이션 형식으로 전달되는 인수와 함께 실행됐을 때, 메인 프로세스에서 이 속성이 true가 되며 다른 경우엔 undefined가 됩니다.

Methods

process 객체는 다음과 같은 메서드를 가지고 있습니다:

process.crash()

현재 프로세스의 메인 스레드에 크래시를 일으킵니다.

process.hang()

현재 프로세스의 메인 스레드를 중단시킵니다.

process.setFdLimit(maxDescriptors) macOS Linux

현재 프로세스 파일 디스크립터의 제한 값을 소프트 제한 maxDescriptors의 값이나 OS 하드 제한 중 낮은 값으로 설정합니다.

process.getProcessMemoryInfo()

Returns Object: * workingSetSize Integer - 현재 실제 물리적 RAM에 예약된 메모리의 양. * peakWorkingSetSize Integer - 물리적 RAM에 예약된 메모리의 최대 사용량. * privateBytes Integer - 다른 프로세스에 공유되지 않은 JS 힙 또는 HTML 콘텐츠와 같은 메모리의 양. * sharedBytes Integer - 다른 프로세스와 공유된, 일반적으로 Electron 코드 자체에서 사용하는 메모리의 양.

현재 프로세스의 메모리 사용량에 대한 정보를 객체 형태로 반환합니다. 참고로 모든 사용량은 킬로바이트로 표기됩니다.

process.getSystemMemoryInfo()

Returns Object: * total Integer - 시스템에서 사용할 수 있는 킬로바이트 단위의 전체 물리적 메모리의 양. * free Integer - 애플리케이션이나 디스크 캐시로 사용되지 않은 메모리의 양. * swapTotal Integer - 시스템에서 사용할 수 있는 킬로바이트 단위의 스왑 메모리 전체 양. Windows Linux * swapFree Integer - 시스템에서 사용할 수 있는 킬로 바이트 단위의 사용되지 않은 스왑 메모리의 양. Windows Linux

전체 시스템의 메모리 사용량에 대한 정보를 객체 형태로 반환합니다. 참고로 모든 사용량은 킬로바이트로 표기됩니다.


protocol

커스텀 프로토콜을 등록하거나 이미 존재하능 프로토콜의 요청의 동작을 변경합니다.

다음 예시는 file:// 프로토콜과 비슷한 일을 하는 커스텀 프로토콜을 설정합니다:

const {app, protocol} = require('electron')
const path = require('path')

app.on('ready', () => {
  protocol.registerFileProtocol('atom', (request, callback) => {
    const url = request.url.substr(7)
    callback({path: path.normalize(`${__dirname}/${url}`)})
  }, function (error) {
    if (error) console.error('프로토콜 등록 실패')
  })
})

참고: 모든 메서드는 따로 표기하지 않는 한 app 모듈의 ready 이벤트가 발생한 이후에만 사용할 수 있습니다.

Methods

protocol 모듈은 다음과 같은 메서드를 가지고 있습니다:

protocol.registerStandardSchemes(schemes)

표준 스킴의 형식은 RFC 3986 일반 URI 문법 표준을 따릅니다. 예를 들어 httphttps 같은 표준 스킴과 file과 같은 표준이 아닌 스킴이 있습니다.

표준 스킴으로 등록하면, 상대, 절대 경로의 리소스를 올바르게 취할 수 있습니다. 다른 경우엔 스킴이 상대 경로 URL에 대한 분석 기능이 제외된 file 프로토콜과 같이 작동합니다.

예를 들어 다음과 같은 페이지에서 표준 스킴 등록 절차 없이 커스텀 프로토콜을 사용하여 이미지를 로드하려 했을 때, 표준 스킴으로 등록되지 않은 상대 경로 URL을 인식하지 못하고 로드에 실패하게 됩니다:

<body>
  <img src='test.png'>
</body>

표준 스킴으로 등록하는 것은 파일 시스템 API를 통해 파일에 접근하는 것을 허용할 것입니다. 그렇지 않은 경우 렌더러는 해당 스킴에 대해 보안 에러를 발생 할 것입니다.

표준 스킴에는 기본적으로 저장 API (localStorage, sessionStorage, webSQL, indexedDB, cookies) 가 비활성화 되어있습니다. 일반적으로 http 프로토콜을 대체하는 커스텀 프로토콜을 등록하고 싶다면, 표준 스킴으로 등록해야 합니다:

const {app, protocol} = require('electron')

protocol.registerStandardSchemes(['atom'])
app.on('ready', () => {
  protocol.registerHttpProtocol('atom', '...')
})

참고: 이 메서드는 app 모듈의 ready 이벤트가 발생하기 이전에만 사용할 수 있습니다.

protocol.registerServiceWorkerSchemes(schemes)

protocol.registerFileProtocol(scheme, handler[, completion])

scheme에 파일을 응답으로 보내는 프로토콜을 등록합니다. handlerscheme와 함께 request가 생성될 때 handler(request, callback) 형식으로 호출됩니다. completion 콜백은 scheme가 성공적으로 등록되었을 때 completion(null) 형식으로 호출되고, 등록에 실패했을 땐 completion(error) 형식으로 에러 내용을 담아 호출됩니다.

uploadDatadata 객체의 배열입니다:

request를 처리할 때 반드시 파일 경로 또는 path 속성을 포함하는 객체를 인수에 포함하여 callback을 호출해야 합니다. 예: callback(filePath) 또는 callback({path: filePath}).

만약 callback이 아무 인수도 없이 호출되거나 숫자나 error 프로퍼티를 가진 객체가 인수로 전달될 경우 request는 지정한 error 코드(숫자)를 출력합니다. 사용할 수 있는 에러 코드는 네트워크 에러 목록에서 확인할 수 있습니다.

기본적으로 schemehttp:와 같이 처리됩니다. file:과 같이 “일반적인 URI 문법” 과는 다르게 인식되는 프로토콜은 protocol.registerStandardSchemes을 사용하여 표준 스킴으로 처리되도록 할 수 있습니다.

protocol.registerBufferProtocol(scheme, handler[, completion])

Buffer를 응답으로 전송하는 scheme의 프로토콜을 등록합니다.

사용법은 callback이 반드시 Buffer 객체 또는 data, mimeType, charset 속성을 포함하는 객체와 함께 호출되어야 한다는 점을 제외하면 registerFileProtocol과 사용법이 같습니다.

예시:

const {protocol} = require('electron')

protocol.registerBufferProtocol('atom', (request, callback) => {
  callback({mimeType: 'text/html', data: new Buffer('<h5>Response</h5>')})
}, (error) => {
  if (error) console.error('Failed to register protocol')
})

protocol.registerStringProtocol(scheme, handler[, completion])

String을 응답으로 전송할 scheme의 프로토콜을 등록합니다.

사용법은 callback이 반드시 String 또는 data, mimeType, charset 속성을 포함하는 객체와 함께 호출되어야 한다는 점을 제외하면 registerFileProtocol과 사용법이 같습니다.

protocol.registerHttpProtocol(scheme, handler[, completion])

HTTP 요청을 응답으로 전송할 scheme의 프로토콜을 등록합니다.

사용법은 callback이 반드시 url, method, referrer, uploadDatasession 속성을 포함하는 redirectRequest 객체와 함께 호출되어야 한다는 점을 제외하면 registerFileProtocol과 사용법이 같습니다.

기본적으로 HTTP 요청은 현재 세션을 재사용합니다. 만약 서로 다른 세션에 요청을 보내고 싶으면 sessionnull로 지정해야 합니다.

POST 요청에는 반드시 uploadData 객체가 제공되어야 합니다.

protocol.unregisterProtocol(scheme[, completion])

scheme의 커스텀 프로토콜 등록을 해제합니다.

protocol.isProtocolHandled(scheme, callback)

scheme에 동작(handler)이 등록되어 있는지 여부를 확인합니다. callback으로 결과(boolean)가 반환됩니다.

protocol.interceptFileProtocol(scheme, handler[, completion])

scheme 프로토콜을 가로채고 handler를 파일 전송에 대한 새로운 동작으로 사용합니다.

protocol.interceptStringProtocol(scheme, handler[, completion])

scheme 프로토콜을 가로채고 handler를 문자열 전송에 대한 새로운 동작으로 사용합니다.

protocol.interceptBufferProtocol(scheme, handler[, completion])

scheme 프로토콜을 가로채고 handlerBuffer 전송에 대한 새로운 동작으로 사용합니다.

protocol.interceptHttpProtocol(scheme, handler[, completion])

scheme 프로토콜을 가로채고 handler를 HTTP 프로토콜의 요청에 대한 새로운 동작으로 사용합니다.

protocol.uninterceptProtocol(scheme[, completion])

가로챈 scheme를 삭제하고 기본 핸들러로 복구합니다.


remote

메인 프로세스 모듈을 렌더러 프로세스에서 사용합니다.

remote 모듈은 메인 프로세스와 렌더러 프로세스(웹 페이지) 사이의 inter-process (IPC) 통신을 간단하게 추상화 한 모듈입니다.

Electron의 메인 프로세스에선 GUI와 관련 있는(dialog, menu등) 모듈만 사용할 수 있습니다. 렌더러 프로세스에서 이러한 모듈들을 사용하려면 ipc 모듈을 통해 메인 프로세스와 inter-process 통신을 해야 합니다. 또한, remote 모듈을 사용하면 inter-process 통신을 하지 않고도 간단한 API를 통해 직접 메인 프로세스의 모듈과 메서드를 사용할 수 있습니다. 이 개념은 Java의 RMI와 비슷합니다.

다음 예시는 렌더러 프로세스에서 브라우저 창을 만드는 예시입니다:

const {BrowserWindow} = require('electron').remote

let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('https://github.com')

참고: 반대로 메인 프로세스에서 렌더러 프로세스에 접근 하려면 webContents.executeJavascript 메서드를 사용하면 됩니다.

Remote 객체

remote 모듈로부터 반환된 각 객체(메서드 포함)는 메인 프로세스의 객체를 추상화 한 객체입니다. (우리는 그것을 remote 객체 또는 remote 함수라고 부릅니다) Remote 모듈의 메서드를 호출하거나, 객체에 접근하거나, 생성자로 객체를 생성하는 등의 작업은 실질적으로 동기형 inter-process 메시지를 보냅니다.

위의 예시에서 사용한 두 BrowserWindowwin은 remote 객체입니다. 그리고 new BrowserWindow이 생성하는 BrowserWindow 객체는 렌더러 프로세스에서 생성되지 않습니다. 대신에 이 BrowserWindow 객체는 메인 프로세스에서 생성되며 렌더러 프로세스에 win 객체와 같이 이에 대응하는 remote 객체를 반환합니다.

참고: remote 객체가 처음 참조될 때 표시되는 enumerable 속성은 remote를 통해서만 접근할 수 있습니다.

참고: 배열과 버퍼는 remote 모듈을 통해 접근할 때 IPC 를 통해 복사됩니다. 렌더러 프로세스에서의 수정은 메인 프로세스의 것을 수정하지 않으며, 반대의 경우도 마찬가지 입니다.

Remote 객체의 생명 주기

Electron은 렌더러 프로세스의 remote 객체가 살아있는 한(다시 말해서 GC(garbage collection)가 일어나지 않습니다) 대응하는 메인 프로세스의 객체는 릴리즈되지 않습니다. Remote 객체가 GC 되려면 대응하는 메인 프로세스 내부 객체의 참조가 해제되어야만 합니다.

만약 remote 객체가 렌더러 프로세스에서 누수가 생겼다면 (예시: 맵에 저장하고 할당 해제하지 않음) 대응하는 메인 프로세스의 객체도 누수가 생깁니다. 그래서 remote 객체를 사용할 땐 메모리 누수가 생기지 않도록 매우 주의해서 사용해야 합니다.

참고로 문자열, 숫자와 같은 원시 값 타입은 복사에 의한 참조로 전달됩니다.

메인 프로세스로 콜백 넘기기

메인 프로세스의 코드는 remote 모듈을 통해 렌더러 프로세스가 전달하는 콜백 함수를 받을 수 있습니다. 하지만 이 작업은 반드시 주의를 기울여 사용해야 합니다.

첫째, 데드락을 피하기 위해 메인 프로세스로 전달된 콜백들은 비동기로 호출됩니다. 이러한 이유로 메인 프로세스에 전달된 콜백의 반환 값을 내부 함수에서 언제나 정상적으로 받을 것이라고 예측해선 안됩니다.

예를 들어 메인 프로세스에서 Array.map 같은 메서드를 사용할 때 렌더러 프로세스에서 전달된 함수를 사용해선 안됩니다:

// mapNumbers.js 메인 프로세스
exports.withRendererCallback = (mapper) => {
  return [1, 2, 3].map(mapper)
}

exports.withLocalCallback = () => {
  return [1, 2, 3].map(x => x + 1)
}
// 렌더러 프로세스
const mapNumbers = require('electron').remote.require('./mapNumbers')

const withRendererCb = mapNumbers.withRendererCallback(x => x + 1)

const withLocalCb = mapNumbers.withLocalCallback()

console.log(withRendererCb, withLocalCb) // [undefined, undefined, undefined], [2, 3, 4]

보다시피 동기적인 렌더러 콜백 함수의 반환 값은 예상되지 않은 값입니다. 그리고 메인 프로세스에서 처리한 함수의 반환 값과 일치하지 않습니다.

둘째, 콜백들은 메인 프로세스로 전달, 호출된 이후에도 자동으로 함수의 참조가 릴리즈 되지 않습니다. 함수 참조는 메인 프로세스에서 GC가 일어나기 전까지 계속 프로세스에 남아있게 됩니다.

다음 코드를 보면 느낌이 올 것입니다. 이 예시는 remote 객체에 close 이벤트 콜백을 등록합니다:

const remote = require('remote')

remote.getCurrentWindow().on('close', () => {
  // blabla...
})

하지만 이 코드와 같이 등록된 이벤트는 명시적으로 제거하지 않는 이상 콜백 함수의 참조가 계속해서 메인 프로세스에 남아있게 됩니다. 만약 명시적으로 콜백을 제거하지 않으면 매 번 창을 새로고침 할 때마다 콜백을 새로 설치합니다. 게다가 이전 콜백이 제거되지 않고 계속해서 쌓이면서 메모리 ���수가 발생합니다.

설상가상으로 이전에 등록된 콜백의 컨텍스트가 릴리즈 되고 난 후 (e.g. 페이지 새로고침) close 이벤트가 발생하면 예외가 발생하고 메인 프로세스가 작동 중지됩니다.

이러한 문제를 피하려면 렌더러 프로세스에서 메인 프로세스로 넘긴 함수의 참조를 사용 후 확실하게 제거해야 합니다. 작업 후 이벤트 콜백을 포함하여 책임 있게 함수의 참조를 제거하거나 메인 프로세스에서 렌더러 프로세스가 종료될 때 내부적으로 함수 참조를 제거하도록 설계해야 합니다.

메인 프로세스의 빌트인 모듈에 접근

메인 프로세스의 빌트인 모듈은 remote 모듈에 getter로 등록되어 있습니다. 따라서 remote 모듈을 electron 모듈처럼 직접 사용할 수 있습니다.

const app = remote.app

Methods

remote 모듈은 다음과 같은 메서드를 가지고 있습니다:

remote.require(module)

Returns Object - 메인 프로세스의 require(module) 에 의해 반환된 객체.

remote.getCurrentWindow()

Returns BrowserWindow - 현재 웹 페이지가 들어있는 BrowserWindow 객체.

remote.getCurrentWebContents()

Returns WebContents - 현재 웹 페이지의 WebContents 객체.

remote.getGlobal(name)

Returns any - 메인 프로세스의 전역 변수 name (예시: global[name]).

Properties

remote.process

메인 프로세스의 process 객체입니다. remote.getGlobal('process')와 같습니다. 하지만 캐시 됩니다.


screen

화면 크기, 디스플레이, 커서 위치 등의 정보를 가져옵니다.

이 모듈은 app 모듈의 ready 이벤트가 발생하기 전까지 포함하거나 사용할 수 없습니다.

screenEventEmitter를 상속 받았습니다.

참고: 렌더러 / DevTools에선 이미 DOM 속성이 window.screen을 가지고 있으므로 screen = require('screen') 형식으로 모듈을 사용할 수 없습니다.

다음 예시는 화면 전체를 채우는 윈도우 창을 생성합니다:

const electron = require('electron')
const {app, BrowserWindow} = electron

let win

app.on('ready', () => {
  const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize
  win = new BrowserWindow({width, height})
})

다음 예시는 확장 디스플레이에 윈도우를 생성합니다:

const electron = require('electron')
const {app, BrowserWindow} = require('electron')

let win

app.on('ready', () => {
  let displays = electron.screen.getAllDisplays()
  let externalDisplay = displays.find((display) => {
    return display.bounds.x !== 0 || display.bounds.y !== 0
  })

  if (externalDisplay) {
    win = new BrowserWindow({
      x: externalDisplay.bounds.x + 50,
      y: externalDisplay.bounds.y + 50
    })
  }
})

Events

screen 모듈은 다음과 같은 이벤트를 가지고 있습니다:

Event: ‘display-added’

Returns:

newDisplay 가 추가되면 발생하는 이벤트입니다.

Event: ‘display-removed’

Returns:

oldDisplay 가 제거되면 발생하는 이벤트입니다.

Event: ‘display-metrics-changed’

Returns:

display에서 하나 또는 다수의 매트릭스가 변경될 때 발생하는 이벤트입니다. changedMetrics는 변경에 대한 정보를 담은 문자열의 배열입니다. bounds, workArea, scaleFactor, rotation등이 변경될 수 있습니다.

Methods

screen 모듈은 다음과 같은 메서드를 가지고 있습니다:

screen.getCursorScreenPoint()

Returns Object: * x Integer * y Integer

현재 마우스 포인터의 절대 위치.

screen.getPrimaryDisplay()

Returns Display - 기본 디스플레이.

screen.getAllDisplays()

Returns Display[] - 사용 가능한 모든 디스플레이의 배열.

screen.getDisplayNearestPoint(point)

Returns Display - 지정한 좌표에 가까운 디스플레이.

screen.getDisplayMatching(rect)

Returns Display - 지정한 범위에 가장 가깝게 교차한 디스플레이.


session

브라우저 세션, 쿠키, 캐시, 프록시 설정 등을 관리합니다.

session 모듈은 새로운 Session 객체를 만드는데 사용할 수 있습니다.

또한 WebContentssession 속성이나 session 모듈을 통해 현재 존재하는 페이지의 session에 접근할 수 있습니다.

const {session, BrowserWindow} = require('electron')

let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('http://github.com')

let ses = win.webContents.session

Methods

session 모듈은 다음과 같은 메서드를 가지고 있습니다:

session.fromPartition(partition[, options])

Returns Session - partition 문자열로부터 만들어진 Session 인스턴스. 이미 partition에 해당하는 Session이 존재할 경우, 해당 세션이 반환됩니다. 그렇지않은 경우 Session 인스턴스가 options에 맞춰 새로 생성됩니다.

partitionpersist:로 시작하면 페이지는 지속성 세션을 사용하며 다른 모든 앱 내의 페이지에서 같은 partition을 사용할 수 있습니다. 만약 persist: 접두어로 시작하지 않으면 페이지는 인-메모리 세션을 사용합니다. partition을 지정하지 않으면 애플리케이션의 기본 세션이 반환됩니다.

options에 맞춰 Session을 생성하려면, partition에 해당하는 Session이 이미 이전에 사용되지 않고 있는지 확인해야 합니다. 이미 존재하는 Session 객체의 options를 변경하는 방법은 없습니다.

Properties

session 모듈은 다음과 같은 속성을 가지고 있습니다:

session.defaultSession

Session 객체, 애플리케이션의 기본 세션 객체.

Class: Session

세션의 속성을 가져오거나 설정합니다.

session 모듈을 사용하여 Session 객체를 생성할 수 있습니다:

const {session} = require('electron')
const ses = session.fromPartition('persist:name')
console.log(ses.getUserAgent())

Instance Events

Session 객체는 다음과 같은 이벤트를 가지고 있습니다:

Event: ‘will-download’

Electron의 webContents에서 item을 다운로드할 때 발생하는 이벤트입니다.

event.preventDefault() 메서드를 호출하면 다운로드를 취소하고, 프로세스의 다음 틱부터 item을 사용할 수 없게 됩니다.

const {session} = require('electron')
session.defaultSession.on('will-download', (event, item, webContents) => {
  event.preventDefault()
  require('request')(item.getURL(), (data) => {
    require('fs').writeFileSync('/somewhere', data)
  })
})

Instance Methods

Session 객체는 다음과 같은 메서드를 가지고 있습니다:

ses.getCacheSize(callback)

세션의 현재 캐시 크기를 반환합니다.

ses.clearCache(callback)

세션의 HTTP 캐시를 비웁니다.

ses.clearStorageData([options, callback])

웹 스토리지의 데이터를 비웁니다.

ses.flushStorageData()

디스크에 사용되지 않은 DOMStorage 데이터를 모두 덮어씌웁니다.

ses.setProxy(config, callback)

프록시 설정을 적용합니다.

pacScriptproxyRules이 같이 제공되면 proxyRules 옵션은 무시되며 pacScript 컨픽만 적용됩니다.

proxyRules는 다음과 같은 규칙을 따릅니다:

proxyRules = schemeProxies[";"<schemeProxies>]
schemeProxies = [<urlScheme>"="]<proxyURIList>
urlScheme = "http" | "https" | "ftp" | "socks"
proxyURIList = <proxyURL>[","<proxyURIList>]
proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]

예시:

proxyBypassRules는 밑에서 묘사된 규칙의 콤마로 구분된 목록입니다:

ses.resolveProxy(url, callback)

url의 프록시 정보를 해석합니다. callback은 요청이 수행되었을 때 callback(proxy) 형태로 호출됩니다.

ses.setDownloadPath(path)

다운로드 저장 위치를 지정합니다. 기본 다운로드 위치는 각 애플리케이션 데이터 디렉터리의 Downloads 폴더입니다.

ses.enableNetworkEmulation(options)

제공된 설정으로 session의 네트워크를 에뮬레이트합니다.

// 50kbps의 처리량과 함께 500ms의 레이턴시로 GPRS 연결을 에뮬레이트합니다.
window.webContents.session.enableNetworkEmulation({
  latency: 500,
  downloadThroughput: 6400,
  uploadThroughput: 6400
})

// 네트워크가 끊긴 상태를 에뮬레이트합니다.
window.webContents.session.enableNetworkEmulation({offline: true})

ses.disableNetworkEmulation()

활성화된 session의 에뮬레이션을 비활성화합니다. 기본 네트워크 설정으로 돌아갑니다.

ses.setCertificateVerifyProc(proc)

session에 인증서의 유효성을 확인하는 프로세스(proc)를 등록합니다. proc은 서버 인증서 유효성 검증 요청이 들어왔을 때 언제나 proc(hostname, certificate, callback) 형식으로 호출됩니다. callback(true)을 호출하면 인증을 승인하고 callback(false)를 호출하면 인증을 거부합니다.

setCertificateVerifyProc(null)을 호출하면 기본 검증 프로세스로 되돌립니다.

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()

win.webContents.session.setCertificateVerifyProc((hostname, cert, callback) => {
  callback(hostname === 'github.com')
})

#### ses.setPermissionRequestHandler(handler)

session의 권한 요청에 응답을 하는데 사용하는 핸들러를 설정합니다. callback(true)를 호출하면 권한 제공을 허용하고 callback(false)를 호출하면 권한 제공을 거부합니다.

const {session} = require('electron')
session.fromPartition('some-partition').setPermissionRequestHandler((webContents, permission, callback) => {
  if (webContents.getURL() === 'some-host' && permission === 'notifications') {
    return callback(false) // 거부됨.
  }

  callback(true)
})

ses.clearHostResolverCache([callback])

호스트 리소버(resolver) 캐시를 지웁니다.

ses.allowNTLMCredentialsForDomains(domains)

동적으로 HTTP NTML 또는 Negotiate 인증을 위해 언제나 자격 증명을 보낼지 여부를 설정합니다.

// 통합 인증을 위해 `example.com`, `foobar.com`, `baz`로 끝나는
// 모든 url을 지정합니다.
session.defaultSession.allowNTLMCredentialsForDomains('*example.com, *foobar.com, *baz')

// 통합 인증을 위해 모든 url을 지정합니다.
session.defaultSession.allowNTLMCredentialsForDomains('*')

ses.setUserAgent(userAgent[, acceptLanguages])

현재 세션에 대해 userAgentacceptLanguages를 덮어씁니다.

acceptLanguages는 반드시 쉼표로 구분된 순서에 맞춘 언어 코드의 리스트여야 하며 예를 들면 "en-US,fr,de,ko,zh-CN,ja" 입니다.

이는 현재 존재하는 WebContents에 적용되지 않으며 각 WebContentswebContents.setUserAgent를 사용하여 세션 전체의 유저 에이전트를 덮어쓸 수 있습니다.

ses.getUserAgent()

Returns String - 현재 세션의 유저 에이전트.

ses.getBlobData(identifier, callback)

Returns Blob - identifier 에 연결된 blob 데이터.

Instance Properties

다음은 Session 인스턴스에서 사용할 수 있는 속성들입니다:

ses.cookies

현재 세션의 Cookies 객체.

ses.webRequest

현재 세션의 WebRequest 객체.

ses.protocol

현재 세션의 Protocol 객체 (protocol 모듈의 인스턴스).

const {app, session} = require('electron')
const path = require('path')

app.on('ready', function () {
  const protocol = session.fromPartition(partitionName).protocol
  protocol.registerFileProtocol('atom', function (request, callback) {
    var url = request.url.substr(7)
    callback({path: path.normalize(`${__dirname}/${url}`)})
  }, function (error) {
    if (error) console.error('Failed to register protocol')
  })
})

Class: Cookies

세션의 쿠키를 변경하거나 요청합니다.

Cookies 클래스의 인스턴스는 Sessioncookies 속성을 통해 접근합니다.

예를 들어:

// 모든 쿠키를 요청합니다.
session.defaultSession.cookies.get({}, (error, cookies) => {
  console.log(error, cookies)
})

// url에 관련된 쿠키를 모두 가져옵니다.
session.defaultSession.cookies.get({url: 'http://www.github.com'}, (error, cookies) => {
  console.log(error, cookies)
})

// 지정한 쿠키 데이터를 설정합니다.
// 동일한 쿠키가 있으면 해당 쿠키를 덮어씁니다.
const cookie = {url: 'http://www.github.com', name: 'dummy_name', value: 'dummy'}
session.defaultSession.cookies.set(cookie, (error) => {
  if (error) console.error(error)
})

Instance Events

다음은 Cookies 의 인스턴스의 이벤트입니다:

Event: ‘changed’

쿠키가 추가, 편집, 삭제, 만료되는 변경이 되면 발생합니다.

Instance Methods

다음은 Cookies 객체에서 사용할 수 있는 메서드들입니다:

ses.cookies.get(filter, callback)

details 객체에서 묘사한 모든 쿠키를 요청합니다. 모든 작업이 끝나면 callbackcallback(error, cookies) 형태로 호출됩니다.

cookiescookie 객체의 배열입니다.

ses.cookies.set(details, callback)

details 객체에 따라 쿠키를 설정합니다. 작업이 완료되면 callbackcallback(error) 형태로 호출됩니다.

ses.cookies.remove(url, name, callback)

urlname에 일치하는 쿠키를 삭제합니다. 작업이 완료되면 callbackcallback() 형식으로 호출됩니다.

Class: WebRequest

생명주기 동안의 다양한 단계를 가지는 요청의 콘텐츠를 가로채고 변경합니다.

WebRequest 클래스의 인스턴스는 SessionwebRequest 속성을 통해 접근할 수 있습니다.

WebRequest의 메서드는 선택적인 filterlistener 속성을 허용하며 listener는 API의 이벤트가 발생했을 때 listener(details) 형식으로 호출되고, details는 요청에 관한 내용을 표현하는 객체입니다. listenernull을 전달하면 이벤트의 구독을 해제합니다.

filterurls 속성을 가진 객체입니다. 이 속성은 URL 규칙의 배열이며 URL 규칙에 일치하지 않는 요청을 모두 거르는데 사용됩니다. 만약 filter가 생략되면 모든 요청을 여과 없이 통과시킵니다.

어떤 listener의 이벤트들은 callback을 같이 전달하는데, 이벤트 처리시 listener의 작업을 완료한 후 response 객체를 포함하여 호출해야 합니다.

다음은 요청에 User-Agent 헤더를 추가하는 예시입니다:

// 다음 url에 대한 User Agent를 조작합니다.
const filter = {
  urls: ['https://*.github.com/*', '*://electron.github.io']
}

session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
  details.requestHeaders['User-Agent'] = 'MyAgent'
  callback({cancel: false, requestHeaders: details.requestHeaders})
})

Instance Methods

다음은 WebRequest 객체에서 사용할 수 있는 메서드들입니다:

webRequest.onBeforeRequest([filter, ]listener)

요청이 발생하면 listenerlistener(details, callback) 형태로 호출됩니다.

uploadDatadata 객체의 배열입니다:

callbackresponse 객체와 함께 호출되어야 합니다:

webRequest.onBeforeSendHeaders([filter, ]listener)

HTTP 요청을 보내기 전 요청 헤더를 사용할 수 있을 때 listenerlistener(details, callback) 형태로 호출됩니다. 이 이벤트는 서버와의 TCP 연결이 완료된 후에 발생할 수도 있지만 http 데이터가 전송되기 전에 발생합니다.

callbackresponse 객체와 함께 호출되어야 합니다:

webRequest.onSendHeaders([filter, ]listener)

서버에 요청이 전송되기 바로 전에 listenerlistener(details) 형태로 호출됩니다. 이전 onBeforeSendHeaders의 response와 다른점은 리스너가 호출되는 시간으로 볼 수 있습니다.

webRequest.onHeadersReceived([filter, ]listener)

요청의 HTTP 응답 헤더를 받았을 때 listenerlistener(details, callback) 형태로 호출됩니다.

callbackresponse 객체와 함께 호출되어야 합니다:

webRequest.onResponseStarted([filter, ]listener)

요청 본문의 첫 번째 바이트를 받았을 때 listenerlistener(details) 형태로 호출됩니다. 이는 HTTP 요청에서 상태 줄과 요청 헤더가 사용 가능한 상태를 의미합니다.

webRequest.onBeforeRedirect([filter, ]listener)

서버에서 시작된 리다이렉트가 발생했을 때 listenerlistener(details) 형태로 호출됩니다.

webRequest.onCompleted([filter, ]listener)

요청이 완료되면 listenerlistener(details) 형태로 호출됩니다.

webRequest.onErrorOccurred([filter, ]listener)

에러가 발생하면 listenerlistener(details) 형태로 호출됩니다.


shell

파일과 URL을 각 기본 애플리케이션을 통해 관리합니다.

shell 모듈은 데스크톱 환경 통합에 관련한 유틸리티를 제공하는 모듈입니다.

다음 예시는 설정된 URL을 유저의 기본 브라우저로 엽니다:

const {shell} = require('electron')

shell.openExternal('https://github.com')

Methods

shell 모듈은 다음과 같은 메서드를 가지고 있습니다:

shell.showItemInFolder(fullPath)

Returns Boolean - 아이템 성공적으로 보여졌는지 여부.

지정한 파일을 파일 매니저에서 보여줍니다. 가능한 경우 파일을 선택합니다.

shell.openItem(fullPath)

Returns Boolean - 아이템 성공적으로 열렸는지 여부.

지정한 파일을 데스크톱 기본 프로그램으로 엽니다.

shell.openExternal(url[, options])

Returns Boolean - 애플리케이션이 URL 을 열 수 있었는지 여부.

제공된 외부 프로토콜 URL을 기반으로 데스크톱의 기본 프로그램으로 엽니다. (예를 들어 mailto: URL은 유저의 기본 이메일 에이전트로 URL을 엽니다).

역자주: 탐색기로 폴더만 표시하려면 'file://경로'와 같이 지정하여 열 수 있습니다.

shell.moveItemToTrash(fullPath)

Returns Boolean - 아이템이 성공적으로 휴지통으로 이동되었는지 여부.

지정한 파일을 휴지통으로 이동시키고 작업의 상태를 boolean 형으로 반환합니다.

shell.beep()

비프음을 재생합니다.

shell.writeShortcutLink(shortcutPath[, operation], options) Windows

Returns Boolean - 바로가기 생성 여부.

shortcutPath에 바로가기 링크를 생성하거나 갱신합니다.

shell.readShortcutLink(shortcutPath) Windows

Returns structures/shortcut-details

Resolves the shortcut link at shortcutPath. shortcutPath에 위치한 바로가기 링크를 해석합니다. shell.writeShortcutLink 메서드의 options에 묘사된 속성을 포함하는 객체를 반환합니다.

오류가 발생하면 예외가 throw됩니다.


Certificate Object


Display Object

Display 객체는 시스템에 연결된 물리 디스플레이입니다. 머리가 없는 시스템에서는 가짜 Display 가 존재할 수 있습니다. 또는 Display 는 원격 가상 디스플레이일 수 있습니다.


JumpListCategory Object

참고: JumpListCategory 객체가 type, name 속성 둘 다 없다면 typetasks 로 가정합니다. name 속성이 설정되었지만 type 속성이 생략된 경우 typecustom 으로 가정합니다.


JumpListItem Object


MemoryUsageDetails Object


Rectangle Object


ShortcutDetails Object


Task Object


ThumbarButton Object

flags 는 다음 String 들을 포함할 수 있는 배열입니다:


개요

Node.js와 Electron API를 사용하는 방법.

Electron은 모든 Node.js의 built-in 모듈과 third-party node 모듈을 완벽하게 지원합니다. (네이티브 모듈 포함)

또한 Electron은 네이티브 데스크톱 애플리케이션을 개발 할 수 있도록 추가적인 built-in 모듈을 제공합니다. 몇몇 모듈은 메인 프로세스에서만 사용할 수 있고 어떤 모듈은 렌더러 프로세스(웹 페이지)에서만 사용할 수 있습니다. 또한 두 프로세스 모두 사용할 수 있는 모듈도 있습니다.

기본적인 규칙으로 GUI와 저 수준 시스템에 관련된 모듈들은 오직 메인 프로세스에서만 사용할 수 있습니다. 메인 프로세스 vs. 렌더러 프로세스 컨셉에 익숙해야 모듈을 다루기 쉬우므로 관련 문서를 읽어 보는 것을 권장합니다.

메인 프로세스 스크립트는 일반 Node.js 스크립트와 비슷합니다:

const {app, BrowserWindow} = require('electron')

let win = null

app.on('ready', () => {
  win = new BrowserWindow({width: 800, height: 600})
  win.loadURL('https://github.com')
})

렌더러 프로세스도 예외적인 node module들을 사용할 수 있다는 점을 제외하면 일반 웹 페이지와 크게 다를게 없습니다:

<!DOCTYPE html>
<html>
<body>
<script>
  const {app} = require('electron').remote;
  console.log(app.getVersion());
</script>
</body>
</html>

애플리케이션을 실행하려면 앱 실행하기 문서를 참고하기 바랍니다.

분리 할당

0.37 버전부터, 분리 할당을 통해 빌트인 모듈을 더 직관적으로 사용할 수 있습니다:

const {app, BrowserWindow} = require('electron')

let win

app.on('ready', () => {
  win = new BrowserWindow()
  win.loadURL('https://github.com')
})

모든 electron 모듈이 필요하다면, 먼저 require한 후 각 독립적인 모듈을 electron에서 분리 할당함으로써 모듈을 사용할 수 있습니다.

const electron = require('electron')
const {app, BrowserWindow} = electron

let win

app.on('ready', () => {
  win = new BrowserWindow()
  win.loadURL('https://github.com')
})

위 코드는 다음과 같습니다:

const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
let win

app.on('ready', () => {
  win = new BrowserWindow()
  win.loadURL('https://github.com')
})

systemPreferences

시스템 설정을 가져옵니다.

const {systemPreferences} = require('electron')
console.log(systemPreferences.isDarkMode())

Events

systemPreferences 객체는 다음 이벤트를 발생시킵니다:

Event: ‘accent-color-changed’ Windows

Returns:

Event: ‘color-changed’ Windows

Returns:

Event: ‘inverted-color-scheme-changed’ Windows

Returns:

Methods

systemPreferences.isDarkMode() macOS

Returns Boolean - 시스템이 어두운 모드인지 여부.

systemPreferences.isSwipeTrackingFromScrollEventsEnabled() macOS

Returns Boolean - 페이지 간의 스와이프가 설정되어 있는지 여부.

systemPreferences.postNotification(event, userInfo) macOS

macOS 의 기본 알림으로 event 를 전달합니다. userInfo 는 알림과 함께 전송되는 사용자 정보 딕셔너리를 포함하는 객체입니다.

systemPreferences.postLocalNotification(event, userInfo) macOS

macOS 의 기본 알림으로 event 를 전달합니다. userInfo 는 알림과 함께 전송되는 사용자 정보 딕셔너리를 포함하는 객체입니다.

systemPreferences.subscribeNotification(event, callback) macOS

macOS의 기본 알림을 구독하며, 해당하는 event가 발생하면 callbackcallback(event, userInfo) 형태로 호출됩니다. userInfo는 알림과 함께 전송되는 사용자 정보 딕셔너리를 포함하는 객체입니다.

구독자의 id가 반환되며 event를 구독 해제할 때 사용할 수 있습니다.

이 API는 후드에서 NSDistributedNotificationCenter를 구독하며, event의 예시 값은 다음과 같습니다:

systemPreferences.unsubscribeNotification(id) macOS

id와 함께 구독자를 제거합니다.

systemPreferences.subscribeLocalNotification(event, callback) macOS

subscribeNotification와 같습니다. 하지만 로컬 기본값에 대해 NSNotificationCenter를 사용합니다. 이는 NSUserDefaultsDidChangeNotification와 같은 이벤트에 대해 필수적입니다.

systemPreferences.unsubscribeLocalNotification(id) macOS

unsubscribeNotification와 같지만, NSNotificationCenter에서 구독자를 제거합니다.

systemPreferences.getUserDefault(key, type) macOS

시스템 설정에서 key에 해당하는 값을 가져옵니다.

macOS에선 API가 NSUserDefaults를 읽어들입니다. 유명한 keytype은 다음과 같습니다:

systemPreferences.isAeroGlassEnabled() Windows

이 메서드는 DWM 컴포지션 (Aero Glass)가 활성화 되어있을 때 true를 반환합니다. 아닌 경우 false를 반환합니다.

다음은 투명한 윈도우를 만들지, 일반 윈도우를 만들지를 판단하여 윈도우를 생성하는 예시입니다 (투명한 윈도우는 DWM 컴포지션이 비활성화되어있을 시 작동하지 않습니다):

const {BrowserWindow, systemPreferences} = require('electron')
let browserOptions = {width: 1000, height: 800}

// 플랫폼이 지원하는 경우에만 투명 윈도우를 생성.
if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) {
  browserOptions.transparent = true
  browserOptions.frame = false
}

// 원도우 생성
let win = new BrowserWindow(browserOptions)

// 페이지 로드.
if (browserOptions.transparent) {
  win.loadURL(`file://${__dirname}/index.html`)
} else {
  // 투명 윈도우 상태가 아니라면, 기본적인 스타일 사용
  win.loadURL(`file://${__dirname}/fallback.html`)
}

systemPreferences.getAccentColor() Windows

Returns String - 사용자 현재 시스템 전체 강조 색상 설정의 16진수 형식 RGBA 값.

const color = systemPreferences.getAccentColor() // `"aabbccdd"`
const red = color.substr(0, 2) // "aa"
const green = color.substr(2, 2) // "bb"
const blue = color.substr(4, 2) // "cc"
const alpha = color.substr(6, 2) // "dd"

systemPreferences.getColor(color) Windows

Returns String - 16진수 RGB 형식 (#ABCDEF) 의 시스템 색상 설정. 자세한 내용은 윈도우 문서를 보세요.

systemPreferences.isInvertedColorScheme() Windows

Returns Boolean - 고대비 테마 같은 반전된 색상 스킴이 활성화 되있다면 true, 아니면 false.


Tray

아이콘과 컨텍스트 메뉴를 시스템 알림 영역에 추가합니다.

const {app, Menu, Tray} = require('electron')

let tray = null
app.on('ready', () => {
  tray = new Tray('/path/to/my/icon') // 현재 애플리케이션 디렉터리를 기준으로 하려면 `__dirname + '/images/tray.png'` 형식으로 입력해야 합니다.
  const contextMenu = Menu.buildFromTemplate([
    {label: 'Item1', type: 'radio'},
    {label: 'Item2', type: 'radio'},
    {label: 'Item3', type: 'radio', checked: true},
    {label: 'Item4', type: 'radio'}
  ])
  tray.setToolTip('이것은 나의 애플리케이션 입니다!')
  tray.setContextMenu(contextMenu)
})

플랫폼별 한계:

contextMenu.items[2].checked = false
appIcon.setContextMenu(contextMenu)

이러한 이유로 Tray API가 모든 플랫폼에서 똑같이 작동하게 하고 싶다면 click 이벤트에 의존해선 안되며 언제나 컨텍스트 메뉴를 포함해야 합니다.

Class: Tray

TrayEventEmitter를 상속 받았습니다.

new Tray(image)

전달된 image를 이용하여 트레이 아이콘을 만듭니다.

Instance Events

Tray 모듈은 다음과 같은 이벤트를 가지고 있습니다:

Event: ‘click’

트레이 아이콘이 클릭될 때 발생하는 이벤트입니다.

Event: ‘right-click’ macOS Windows

트레이 아이콘을 오른쪽 클릭될 때 호출 됩니다.

Event: ‘double-click’ macOS Windows

트레이 아이콘이 더블 클릭될 때 발생하는 이벤트입니다.

Event: ‘balloon-show’ Windows

풍선 팝업이 보여질 때 발생하는 이벤트입니다.

Event: ‘balloon-click’ Windows

풍선 팝업이 클릭될 때 발생하는 이벤트입니다.

Event: ‘balloon-closed’ Windows

풍선 팝업이 시간이 지나 사라지거나 유저가 클릭하여 닫을 때 발생하는 이벤트입니다.

Event: ‘drop’ macOS

드래그 가능한 아이템이 트레이 아이콘에 드롭되면 발생하는 이벤트입니다.

Event: ‘drop-files’ macOS

트���이 아이콘에 파일이 드롭되면 발생하는 이벤트입니다.

Event: ‘drop-text’ macOS

드래그된 텍스트가 트레이 아이콘에 드롭되면 발생하는 이벤트입니다.

Event: ‘drag-enter’ macOS

트레이 아이콘에 드래그 작업이 시작될 때 발생하는 이벤트입니다.

Event: ‘drag-leave’ macOS

트레이 아이콘에 드래그 작업이 종료될 때 발생하는 이벤트입니다.

Event: ‘drag-end’ macOS

트레이 아이콘에 드래그 작업이 종료되거나 다른 위치에서 종료될 때 발생하는 이벤트입니다.

Instance Methods

Tray 클래스는 다음과 같은 메서드를 가지고 있습니다:

tray.destroy()

트레이 아이콘을 즉시 삭제시킵니다.

tray.setImage(image)

image를 사용하여 트레이 아이콘의 이미지를 설정합니다.

tray.setPressedImage(image) macOS

image를 사용하여 트레이 아이콘이 눌렸을 때의 이미지를 설정합니다.

tray.setToolTip(toolTip)

트레이 아이콘의 툴팁 텍스트를 설정합니다.

tray.setTitle(title) macOS

상태바에서 트레이 아이콘 옆에 표시되는 제목 텍스트를 설정합니다.

tray.setHighlightMode(mode) macOS

트레이 아이콘의 배경이 하이라이팅될 때를 지정합니다. (파란색)

참고: BrowserWindow와 함께 highlightMode를 윈도우 가시성에 따라 'never''always' 사이에서 키거나 끌 수 있습니다.

const {BrowserWindow, Tray} = require('electron')

const win = new BrowserWindow({width: 800, height: 600})
const tray = new Tray('/path/to/my/icon')

tray.on('click', () => {
  win.isVisible() ? win.hide() : win.show()
})
win.on('show', () => {
  tray.setHighlightMode('always')
})
win.on('hide', () => {
  tray.setHighlightMode('never')
})

tray.displayBalloon(options) Windows

트레이에 풍선 팝업을 생성합니다.

tray.popUpContextMenu([menu, position]) macOS Windows

트레이 아이콘의 컨텍스트 메뉴를 팝업시킵니다. menu가 전달되면, menu가 트레이 아이콘의 컨텍스트 메뉴 대신 표시됩니다.

position은 Windows에서만 사용할 수 있으며 기본값은 (0, 0)입니다.

tray.setContextMenu(menu)

트레이에 컨텍스트 메뉴를 설정합니다.

tray.getBounds() macOS Windows

Returns structures/rectangle

이 트레이 아이콘의 Object 형식의 bounds.

tray.isDestroyed()

Returns Boolean - 트레이 아이콘이 소멸되었는지 여부.


webContents

웹 페이지를 렌더링하고 제어합니다.

webContentsEventEmitter를 상속받았습니다. 웹 페이지의 렌더링과 관리를 책임지며 BrowserWindow의 속성입니다. 다음은 webContents 객체에 접근하는 예시입니다:

const {BrowserWindow} = require('electron')

let win = new BrowserWindow({width: 800, height: 1500})
win.loadURL('http://github.com')

let contents = win.webContents
console.log(contents)

Methods

다음 메서드는 webContents 모듈에서 접근할 수 있는 메서드입니다:

const {webContents} = require('electron')
console.log(webContents)

webContents.getAllWebContents()

Returns WebContents[] - 모든 WebContents 인스턴스의 배열. 이 배열은 윈도우, 웹뷰, 열린 개발자 도구 그리고 백그라운드 페이지의 개발자 도구 확장 기능의 모든 웹 콘텐츠를 포함합니다.

webContents.getFocusedWebContents()

Returns WebContents - 이 애플리케이션에서 포커스되어있는 웹 콘텐츠. 없을 경우 null 을 반환합니다.

webContents.fromId(id)

Returns WebContents - ID 에 해당하는 WebContens 인스턴스.

Class: WebContents

BrowserWindow 인스턴스의 콘텐츠를 표시하고 제어합니다.

Instance Events

Event: ‘did-finish-load’

탐색 작업이 끝났을 때 발생하는 이벤트입니다. 브라우저의 탭의 스피너가 멈추고 onload 이벤트가 발생했을 때를 말합니다.

Event: ‘did-fail-load’

Returns:

이 이벤트는 did-finish-load와 비슷하나, 로드가 실패했거나 취소되었을 때 발생합니다. 예를 들면 window.stop()이 실행되었을 때 발생합니다. 발생할 수 있는 전체 에러 코드의 목록과 설명은 여기서 확인할 수 있습니다. 참고로 리다이렉트 응답은 errorCode -3과 함께 발생합니다; 이 에러는 명시적으로 무시할 수 있습니다.

Event: ‘did-frame-finish-load’

Returns:

프레임(Frame)이 탐색을 끝냈을 때 발생하는 이벤트입니다.

Event: ‘did-start-loading’

브라우저 탭의 스피너가 회전을 시작한 때와 같은 시점에 대응하는 이벤트입니다.

Event: ‘did-stop-loading’

브라우저 탭의 스피너가 회전을 멈추었을 때와 같은 시점에 대응하는 이벤트입니다.

Event: ‘did-get-response-details’

Returns:

요청한 리소스에 관련된 자세한 정보를 사용할 수 있을 때 발생하는 이벤트입니다. status는 리소스를 다운로드하기 위한 소켓 연결을 나타냅니다.

Event: ‘did-get-redirect-request’

Returns:

리소스를 요청하는 동안에 리다이렉트 응답을 받았을 때 발생하는 이벤트입니다.

Event: ‘dom-ready’

Returns:

주어진 프레임의 문서가 로드되었을 때 발생하는 이벤트입니다.

Event: ‘page-favicon-updated’

Returns:

페이지가 favicon(파비콘) URL을 받았을 때 발생하는 이벤트입니다.

Event: ‘new-window’

Returns:

페이지가 url에 대하여 새로운 윈도우를 열기위해 요청한 경우 발생하는 이벤트입니다. window.open이나 <a target='_blank'>과 같은 외부 링크에 의해 요청될 수 있습니다.

기본값으로 BrowserWindowurl을 기반으로 생성됩니다.

event.preventDefault()를 호출하면 새로운 창이 생성되는 것을 방지할 수 있습니다. 이 경우, event.newGuest 는 Electron 의 런타임에 의해 사용할 수 있게 BrowserWindow 인스턴스에 대한 참조를 설정할 수 있습니다.

Event: ‘will-navigate’

Returns:

사용자 또는 페이지가 새로운 페이지로 이동할 때 발생하는 이벤트입니다. window.location 객체가 변경되거나 사용자가 페이지의 링크를 클릭했을 때 발생합니다.

이 이벤트는 webContents.loadURLwebContents.back 같은 API를 이용한 프로그램적으로 시작된 탐색에 대해서는 발생하지 않습니다.

이 이벤트는 앵커 링크를 클릭하거나 window.location.hash의 값을 변경하는 등의 페이지 내 탐색시엔 발생하지 않습니다. 대신 did-navigate-in-page 이벤트를 사용해야 합니다.

event.preventDefault()를 호출하면 탐색을 방지할 수 있습니다.

Event: ‘did-navigate’

Returns:

탐색이 완료되면 발생하는 이벤트입니다.

이 이벤트는 앵커 링크를 클릭하거나 window.location.hash의 값을 변경하는 등의 페이지 내 탐색시엔 발생하지 않습니다. 대신 did-navigate-in-page 이벤트를 사용해야 합니다.

Event: ‘did-navigate-in-page’

Returns:

페이지 내의 탐색이 완료되면 발생하는 이벤트입니다.

페이지 내의 탐색이 발생하면 페이지 URL이 변경되지만 페이지 밖으로의 탐색은 일어나지 않습니다. 예를 들어 앵커 링크를 클릭했을 때, 또는 DOM hashchange 이벤트가 발생했을 때로 볼 수 있습니다.

Event: ‘crashed’

Returns:

렌더러 프로세스가 충돌하거나 종료될 때 발생되는 이벤트입니다.

Event: ‘plugin-crashed’

Returns:

플러그인 프로세스가 예기치 못하게 종료되었을 때 발생되는 이벤트입니다.

Event: ‘destroyed’

webContents가 소멸될 때 발생되는 이벤트입니다.

Event: ‘devtools-opened’

개발자 도구가 열렸을 때 발생되는 이벤트입니다.

Event: ‘devtools-closed’

개발자 도구가 닫혔을 때 발생되는 이벤트입니다.

Event: ‘devtools-focused’

개발자 도구에 포커스가 가거나 개발자 도구가 열렸을 때 발생되는 이벤트입니다.

Event: ‘certificate-error’

Returns:

url에 대한 certificate 인증서의 유효성 검증에 실패했을 때 발생하는 이벤트입니다.

사용법은 appcertificate-error 이벤트와 같습니다.

Event: ‘select-client-certificate’

Returns:

클라이언트 인증이 요청되었을 때 발생하는 이벤트입니다.

사용법은 appselect-client-certificate 이벤트와 같습니다.

Event: ‘login’

Returns:

webContents가 기본 인증을 수행하길 원할 때 발생되는 이벤트입니다.

applogin이벤트와 사용 방법은 같습니다.

Event: ‘found-in-page’

Returns:

webContents.findInPage 요청의 결과를 사용할 수 있을 때 발생하는 이벤트입니다.

Event: ‘media-started-playing’

미디어가 재생되기 시작할 때 발생하는 이벤트입니다.

Event: ‘media-paused’

미디어가 중지되거나 재생이 완료되었을 때 발생하는 이벤트입니다.

Event: ‘did-change-theme-color’

페이지의 테마 색이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 보통 meta 태그에 의해서 발생합니다:

<meta name='theme-color' content='#ff0000'>

Event: ‘update-target-url’

Returns:

마우스나 키보드를 사용해 링크에 포커스할 때 발생하는 이벤트입니다.

Event: ‘cursor-changed’

Returns:

커서 종류가 변경될 때 발생하는 이벤트입니다. type 인수는 다음 값이 될 수 있습니다: default, crosshair, pointer, text, wait, help, e-resize, n-resize, ne-resize, nw-resize, s-resize, se-resize, sw-resize, w-resize, ns-resize, ew-resize, nesw-resize, nwse-resize, col-resize, row-resize, m-panning, e-panning, n-panning, ne-panning, nw-panning, s-panning, se-panning, sw-panning, w-panning, move, vertical-text, cell, context-menu, alias, progress, nodrop, copy, none, not-allowed, zoom-in, zoom-out, grab, grabbing, custom.

만약 type 인수가 custom 이고 image 인수가 NativeImage를 통한 커스텀 커서를 지정했을 때, 해당 이미지로 커서가 변경됩니다. 또한 scale, size 그리고 hotspot 인수는 커스텀 커서의 추가적인 정보를 포함합니다.

Event: ‘context-menu’

Returns:

mediaFlags는 다음과 같은 속성을 가지고 있습니다:

editFlags는 다음과 같은 속성을 가지고 있습니다:

새로운 컨텍스트 메뉴의 제어가 필요할 때 발생하는 이벤트입니다.

Event: ‘select-bluetooth-device’

Returns:

navigator.bluetooth.requestDevice의 호출에 의해 블루투스 기기가 선택되어야 할 때 발생하는 이벤트입니다. navigator.bluetooth API를 사용하려면 webBluetooth가 활성화되어 있어야 합니다. 만약 event.preventDefault이 호출되지 않으면, 첫 번째로 사용 가능한 기기가 선택됩니다. callback은 반드시 선택될 deviceId와 함께 호출되어야 하며, 빈 문자열을 callback에 보내면 요청이 취소됩니다.

const {app, webContents} = require('electron')
app.commandLine.appendSwitch('enable-web-bluetooth')

app.on('ready', () => {
  webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
    event.preventDefault()
    let result = deviceList.find((device) => {
      return device.deviceName === 'test'
    })
    if (!result) {
      callback('')
    } else {
      callback(result.deviceId)
    }
  })
})

Event: ‘paint’

Returns:

새 프레임이 생성되었을 때 발생하는 이벤트입니다. Dirty 영역만이 버퍼로 전달됩니다.

const {BrowserWindow} = require('electron')

let win = new BrowserWindow({webPreferences: {offscreen: true}})
win.webContents.on('paint', (event, dirty, image) => {
  // updateBitmap(dirty, image.toBitmap())
})
win.loadURL('http://github.com')

Instance Methods

contents.loadURL(url[, options])

윈도우에 웹 페이지 url을 로드합니다. urlhttp://, file://과 같은 프로토콜 접두사를 가지고 있어야 합니다. 만약 반드시 http 캐시를 사용하지 않고 로드해야 하는 경우 pragma 헤더를 사용할 수 있습니다.

const {webContents} = require('electron')
const options = {extraHeaders: 'pragma: no-cache\n'}
webContents.loadURL(url, options)

contents.downloadURL(url)

url의 리소스를 탐색 없이 다운로드를 시작합니다. sessionwill-download 이벤트가 발생합니다.

contents.getURL()

현재 웹 페이지의 URL을 반환합니다.

const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('http://github.com')

let currentURL = win.webContents.getURL()
console.log(currentURL)

contents.getTitle()

현재 웹 페이지의 제목을 반환합니다.

win.isDestroyed()

윈도우가 소멸되었는지 여부를 반환합니다.

contents.isFocused()

웹 페이지가 포커스되어있는지 여부를 반환합니다.

contents.isLoading()

현재 웹 페이지가 리소스를 로드중인지 여부를 반환합니다.

contents.isLoadingMainFrame()

메인 프레임이 여전히 로딩중인지 여부를 반환합니다. (내부 iframe 또는 frame 포함)

contents.isWaitingForResponse()

현재 웹 페이지가 페이지의 메인 리소스로부터 첫 응답을 기다리고있는지 여부를 반환합니다.

contents.stop()

대기중인 탐색 작업을 모두 멈춥니다.

contents.reload()

현재 웹 페이지를 새로고침합니다.

contents.reloadIgnoringCache()

현재 웹 페이지의 캐시를 무시한 채로 새로고침합니다.

contents.canGoBack()

브라우저가 이전 웹 페이지로 돌아갈 수 있는지 여부를 반환합니다.

contents.canGoForward()

브라우저가 다음 웹 페이지로 이동할 수 있는지 여부를 반환합니다.

contents.canGoToOffset(offset)

웹 페이지가 offset로 이동할 수 있는지 여부를 반환합니다.

contents.clearHistory()

탐색 기록을 삭제합니다.

contents.goBack()

브라우저가 이전 웹 페이지로 이동하게 합니다.

contents.goForward()

브라우저가 다음 웹 페이지로 이동하게 합니다.

contents.goToIndex(index)

브라우저가 지정된 절대 웹 페이지 인덱스로 탐색하게 합니다.

contents.goToOffset(offset)

“current entry”에서 지정된 offset으로 탐색합니다.

contents.isCrashed()

렌더러 프로세스가 예기치 않게 종료되었는지 여부를 반환합니다.

contents.setUserAgent(userAgent)

현재 웹 페이지의 유저 에이전트를 덮어씌웁니다.

contents.getUserAgent()

현재 웹 페이지의 유저 에이전트 문자열을 반환합니다.

contents.insertCSS(css)

CSS 코드를 현재 웹 페이지에 삽입합니다.

contents.executeJavaScript(code[, userGesture, callback])

페이지에서 자바스크립트 코드를 실행합니다.

기본적으로 requestFullScreen와 같은 몇몇 HTML API들은 사용자의 조작에 의해서만 호출될 수 있습니다. userGesturetrue로 설정하면 이러한 제약을 무시할 수 있습니다.

contents.setAudioMuted(muted)

현재 웹 페이지의 소리를 음소거합니다.

contents.isAudioMuted()

현재 페이지가 음소거 되어있는지 여부를 반환합니다.

contents.setZoomFactor(factor)

지정한 수치로 줌 수치를 변경합니다. 줌 수치는 100으로 나눈 값이며 300%는 3.0이 됩니다.

contents.getZoomFactor(callback)

현재 줌 수치 값을 요청합니다. callbackcallback(zoomFactor) 형태로 호출됩니다.

contents.setZoomLevel(level)

지정한 수준으로 줌 수준을 변경합니다. 원본 크기는 0이고 각 값의 증가와 감소는 현재 줌을 20% 크거나 작게 표현하고 각 크기는 원본 크기의 300%와 50%로 제한됩니다.

contents.getZoomLevel(callback)

현재 줌 수준 값을 요청합니다. callbackcallback(zoomLevel) 형태로 호출됩니다.

contents.setZoomLevelLimits(minimumLevel, maximumLevel)

최대와 최소 값의 줌 수준 값을 지정합니다.

contents.undo()

웹 페이지에서 undo 편집 커맨드를 실행합니다.

contents.redo()

웹 페이지에서 redo 편집 커맨드를 실행합니다.

contents.cut()

웹 페이지에서 cut 편집 커맨드를 실행합니다.

contents.copy()

웹 페이지에서 copy 편집 커맨드를 실행합니다.

contents.copyImageAt(x, y)

주어진 위치에 있는 이미지를 클립보드로 복사합니다.

contents.paste()

웹 페이지에서 paste 편집 커맨드를 실행합니다.

contents.pasteAndMatchStyle()

웹 페이지에서 pasteAndMatchStyle 편집 커맨드를 실행합니다.

contents.delete()

웹 페이지에서 delete 편집 커맨드를 실행합니다.

contents.selectAll()

웹 페이지에서 selectAll 편집 커맨드를 실행합니다.

contents.unselect()

웹 페이지에서 unselect 편집 커맨드를 실행합니다.

contents.replace(text)

웹 페이지에서 replace 편집 커맨드를 실행합니다.

contents.replaceMisspelling(text)

웹 페이지에서 replaceMisspelling 편집 커맨드를 실행합니다.

contents.insertText(text)

포커스된 요소에 text를 삽입합니다.

contents.findInPage(text[, options])

웹 페이지에서 text에 일치하는 모든 대상을 찾는 요청을 시작하고 요청에 사용된 요청을 표현하는 정수(integer)를 반환합니다. 요청의 결과는 found-in-page 이벤트를 통해 취득할 수 있습니다.

contents.stopFindInPage(action)

제공된 action에 대한 webContents의 모든 findInPage 요청을 중지합니다.

const {webContents} = require('electron')
webContents.on('found-in-page', (event, result) => {
  if (result.finalUpdate) webContents.stopFindInPage('clearSelection')
})

const requestId = webContents.findInPage('api')
console.log(requestId)

contents.capturePage([rect, ]callback)

페이지의 스크린샷을 rect에 설정한 만큼 캡처합니다. 캡처가 완료되면 callbackcallback(image) 형식으로 호출됩니다. imageNativeImage의 인스턴스이며 스크린샷 데이터를 담고있습니다. rect를 생략하면 페이지 전체를 캡처합니다.

contents.hasServiceWorker(callback)

ServiceWorker가 등록되어있는지 확인하고 callback에 대한 응답으로 boolean 값을 반환합니다.

contents.unregisterServiceWorker(callback)

ServiceWorker가 존재하면 모두 등록을 해제하고 JS Promise가 만족될 때 callback에 대한 응답으로 boolean을 반환하거나 JS Promise가 만족되지 않을 때 false를 반환합니다.

contents.print([options])

options Object (optional) * silent Boolean - 사용자에게 프린트 설정을 묻지 않습니다. 기본값을 false입니다. * printBackground Boolean - 웹 페이지의 배경 색과 이미지를 출력합니다. 기본값은 false입니다.

윈도우의 웹 페이지를 프린트합니다. silenttrue로 지정되어있을 땐, Electron이 시스템의 기본 프린터와 기본 프린터 설정을 가져옵니다.

웹 페이지에서 window.print()를 호출하는 것은 webContents.print({silent: false, printBackground: false})를 호출하는 것과 같습니다.

contents.printToPDF(options, callback)

Chromium의 미리보기 프린팅 커스텀 설정을 이용하여 윈도우의 웹 페이지를 PDF로 프린트합니다.

callback은 작업이 완료되면 callback(error, data) 형식으로 호출됩니다. data는 생성된 PDF 데이터를 담고있는 Buffer입니다.

기본으로 비어있는 options은 다음과 같이 여겨지게 됩니다:

{
  marginsType: 0,
  printBackground: false,
  printSelectionOnly: false,
  landscape: false
}

다음은 webContents.printToPDF의 예시입니다:

const {BrowserWindow} = require('electron')
const fs = require('fs')

let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('http://github.com')

win.webContents.on('did-finish-load', () => {
  // 기본 프린트 옵션을 사용합니다
  win.webContents.printToPDF({}, (error, data) => {
    if (error) throw error
    fs.writeFile('/tmp/print.pdf', data, (error) => {
      if (error) throw error
      console.log('Write PDF successfully.')
    })
  })
})

contents.addWorkSpace(path)

특정 경로를 개발자 도구의 워크스페이스에 추가합니다. 반드시 개발자 도구의 생성이 완료된 이후에 사용해야 합니다.

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.webContents.on('devtools-opened', () => {
  win.webContents.addWorkSpace(__dirname)
})

contents.removeWorkSpace(path)

특정 경로를 개발자 도구의 워크스페이스에서 제거합니다.

contents.openDevTools([options])

개발자 도구를 엽니다.

contents.closeDevTools()

개발자 도구를 닫습니다.

contents.isDevToolsOpened()

개발자 도구가 열려있는지 여부를 반환합니다.

contents.isDevToolsFocused()

개발자 도구에 포커스 되어있는지 여부를 반환합니다.

contents.toggleDevTools()

개발자 도구를 토글합니다.

contents.inspectElement(x, y)

(x, y)위치의 요소를 조사합니다.

contents.inspectServiceWorker()

서비스 워커 컨텍스트(service worker context)를 위한 개발자 도구를 엽니다.

contents.send(channel[, arg1][, arg2][, ...])

channel을 통하여 렌더러 프로세스에 비동기 메시지를 보냅니다. 임의의 인수를 보낼수도 있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와 프로토타입 체인은 포함되지 않게 됩니다.

렌더러 프로세스는 ipcRenderer 모듈을 통하여 channel를 리스닝하여 메시지를 처리할 수 있습니다.

메인 프로세스에서 렌더러 프로세스로 메시지를 보내는 예시 입니다:

// In the main process.
const {app, BrowserWindow} = require('electron')
let win = null
app.on('ready', () => {
  win = new BrowserWindow({width: 800, height: 600})
  win.loadURL(`file://${__dirname}/index.html`)
  win.webContents.on('did-finish-load', () => {
    win.webContents.send('ping', 'whoooooooh!')
  })
})
<!-- index.html -->
<html>
<body>
  <script>
    require('electron').ipcRenderer.on('ping', (event, message) => {
      console.log(message)  // "whoooooooh!" 출력
    });
  </script>
</body>
</html>

contents.enableDeviceEmulation(parameters)

parameters로 디바이스 에뮬레이션을 사용합니다.

contents.disableDeviceEmulation()

webContents.enableDeviceEmulation로 활성화된 디바이스 에뮬레이선을 비활성화 합니다.

contents.sendInputEvent(event)

Input event를 웹 페이지로 전송합니다.

키보드 이벤트들에 대해서는 event 객체는 다음 속성들을 사용할 수 있습니다:

마우스 이벤트들에 대해서는 event 객체는 다음 속성들을 사용할 수 있습니다:

mouseWheel 이벤트에 대해서는 event 객체는 다음 속성들을 사용할 수 있습니다:

contents.beginFrameSubscription([onlyDirty ,]callback)

캡처된 프레임과 프레젠테이션 이벤트를 구독하기 시작합니다. callback은 프레젠테이션 이벤트가 발생했을 때 callback(frameBuffer, dirtyRect) 형태로 호출됩니다.

frameBuffer는 raw 픽셀 데이터를 가지고 있는 Buffer 객체입니다. 많은 장치에서 32비트 BGRA 포맷을 사용하여 효율적으로 픽셀 데이터를 저장합니다. 하지만 실질적인 데이터 저장 방식은 프로세서의 엔디안 방식에 따라서 달라집니다. (따라서 현대의 많은 프로세서에선 little-endian 방식을 사용하므로 위의 포맷을 그대로 표현합니다. 하지만 몇몇 프로세서는 big-endian 방식을 사용하는데, 이 경우 32비트 ARGB 포맷을 사용합니다)

dirtyRect는 페이지의 어떤 부분이 다시 그려졌는지를 표현하는 x, y, width, height 속성을 포함하는 객체입니다. 만약 onlyDirtytrue로 지정되어 있으면, frameBuffer가 다시 그려진 부분만 포함합니다. onlyDirty의 기본값은 false입니다.

contents.endFrameSubscription()

프레임 프레젠테이션 이벤트들에 대한 구독을 중지합니다.

contents.startDrag(item)

현재 진행중인 드래그-드롭에 item을 드래그 중인 아이템으로 설정합니다. file은 드래그될 파일의 절대 경로입니다. 그리고 icon은 드래그 도중 커서 밑에 표시될 이미지입니다.

contents.savePage(fullPath, saveType, callback)

만약 페이지를 저장하는 프로세스가 성공적으로 끝났을 경우 true를 반환합니다.

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()

win.loadURL('https://github.com')

win.webContents.on('did-finish-load', () => {
  win.webContents.savePage('/tmp/test.html', 'HTMLComplete', (error) => {
    if (!error) console.log('Save page successfully')
  })
})

contents.showDefinitionForSelection() macOS

페이지에서 선택된 단어에 대한 사전 검색 결과 팝업을 표시합니다.

contents.isOffscreen()

오프 스크린 렌더링 이 활성화되었는지 여부를 표시합니다.

contents.startPainting()

오프 스크린 렌더링 이 활성화되었고 페인팅 상태가 아니라면 페인팅을 시작합니다.

contents.stopPainting()

오프 스크린 렌더링 이 활성화되었고 페인팅 상태라면 페인팅을 중지합니다.

contents.isPainting()

오프 스크린 렌더링 이 활성화된 경우 현재 패인팅 상태를 반환합니다.

contents.setFrameRate(fps)

오프 스크린 렌더링 이 활성화된 경우 프레임 레이트를 지정한 숫자로 지정합니다. 1과 60 사이의 값만 사용할 수 있습니다.

contents.getFrameRate()

오프 스크린 렌더링 이 활성화된 경우 현재 프레임 레이트를 반환합니다.

contents.invalidate()

오프 스크린 렌더링 이 활성화된 경우 프레임을 무효화 하고 'paint' 이벤트를 통해 새로 만듭니다.

Instance Properties

contents.id

이 WebContents의 유일 ID.

contents.session

이 webContents에서 사용하는 session 객체를 반환합니다.

contents.hostWebContents

현재 WebContents를 소유하는 WebContents를 반환합니다.

contents.devToolsWebContents

WebContents에 대한 개발자 도구의 WebContents를 가져옵니다.

참고: 사용자가 절대로 이 객체를 저장해서는 안 됩니다. 개발자 도구가 닫혔을 때, null이 반환될 수 있습니다.

contents.debugger

현재 webContents에 대한 디버거 인스턴스를 가져옵니다.

Class: Debugger

Chrome의 원격 디버깅 프로토콜에 대한 대체 접근자입니다.

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()

try {
  win.webContents.debugger.attach('1.1')
} catch (err) {
  console.log('Debugger attach failed : ', err)
}

win.webContents.debugger.on('detach', (event, reason) => {
  console.log('Debugger detached due to : ', reason)
})

win.webContents.debugger.on('message', (event, method, params) => {
  if (method === 'Network.requestWillBeSent') {
    if (params.request.url === 'https://www.github.com') {
      win.webContents.debugger.detach()
    }
  }
})

win.webContents.debugger.sendCommand('Network.enable')

Instance Methods

debugger.attach([protocolVersion])

webContents에 디버거를 부착합니다.

debugger.isAttached()

디버거가 webContents에 부착되어 있는지 여부를 반환합니다.

debugger.detach()

webContents로부터 디버거를 분리시킵니다.

debugger.sendCommand(method[, commandParams, callback])

지정한 커맨드를 디버깅 대상에게 전송합니다.

Instance Events

Event: ‘detach’

디버깅 세션이 종료될 때 발생하는 이벤트입니다. webContents가 닫히거나 개발자 도구가 부착된 webContents에 대해 호출될 때 발생합니다.

Event: ‘message’

디버깅 타겟이 관련 이벤트를 발생시킬 때 마다 발생하는 이벤트입니다.


webFrame

현재 웹 페이지의 렌더링 상태를 커스터마이즈합니다.

다음 예시는 현재 페이지를 200% 줌 합니다:

const {webFrame} = require('electron')

webFrame.setZoomFactor(2)

Methods

webFrame 모듈은 다음과 같은 메서드를 가지고 있습니다:

webFrame.setZoomFactor(factor)

지정한 값으로 페이지를 줌 합니다. 줌 값은 퍼센트를 100으로 나눈 값입니다. (예시: 300% = 3.0)

webFrame.getZoomFactor()

Returns Number - 현재 줌 값.

webFrame.setZoomLevel(level)

지정한 레벨로 줌 레벨을 변경합니다. 0은 “기본 크기” 입니다. 그리고 각각 레벨 값을 올리거나 내릴 때마다 20%씩 커지거나 작아지고 기본 크기의 50%부터 300%까지 조절 제한이 있습니다.

webFrame.getZoomLevel()

Returns Number - 현재 줌 레벨.

webFrame.setZoomLevelLimits(minimumLevel, maximumLevel)

줌 레벨의 최대, 최소치를 지정합니다.

webFrame.setSpellCheckProvider(language, autoCorrectWord, provider)

Input field나 text area에 철자 검사(spell checking) 제공자를 설정합니다.

provider는 반드시 전달된 단어의 철자가 맞았는지 검사하는 spellCheck 메소드를 가지고 있어야 합니다.

node-spellchecker를 철자 검사 제공자로 사용하는 예시입니다:

const {webFrame} = require('electron')
webFrame.setSpellCheckProvider('en-US', true, {
  spellCheck (text) {
    return !(require('spellchecker').isMisspelled(text))
  }
})

webFrame.registerURLSchemeAsSecure(scheme)

scheme을 보안 스킴으로 등록합니다.

보안 스킴은 혼합된 콘텐츠 경고를 발생시키지 않습니다. 예를 들어 httpsdata는 네트워크 공격자로부��� 손상될 가능성이 없기 때문에 보안 스킴이라고 할 수 있습니다.

webFrame.registerURLSchemeAsBypassingCSP(scheme)

현재 페이지 콘텐츠의 보안 정책에 상관없이 scheme로부터 리소스가 로드됩니다.

webFrame.registerURLSchemeAsPrivileged(scheme)

scheme를 보안된 스킴으로 등록합니다. 리소스에 대해 보안 정책을 우회하며, ServiceWorker의 등록과 fetch API를 사용할 수 있도록 지원합니다.

webFrame.insertText(text)

포커스된 요소에 text를 삽입합니다.

webFrame.executeJavaScript(code[, userGesture])

페이지에서 code를 실행합니다.

브라우저 윈도우에서 어떤 requestFullScreen 같은 HTML API는 사용자의 승인이 필요합니다. userGesturetrue로 설정하면 이러한 제약을 제거할 수 있습니다.

webFrame.getResourceUsage()

Returns Object: * images structures/memory-usage-details * cssStyleSheets structures/memory-usage-details * xslStyleSheets structures/memory-usage-details * fonts structures/memory-usage-details * other structures/memory-usage-details

Blink의 내부 메모리 캐시 사용 정보를 담고있는 객체를 반환합니다.

const {webFrame} = require('electron')
console.log(webFrame.getResourceUsage())

다음이 출력됩니다:

{
  images: {
    count: 22,
    size: 2549,
    liveSize: 2542,
    decodedSize: 478,
    purgedSize: 0,
    purgeableSize: 0
  },
  cssStyleSheets: { /* same with "images" */ },
  xslStyleSheets: { /* same with "images" */ },
  fonts: { /* same with "images" */ },
  other: { /* same with "images" */ }
}

webFrame.clearCache()

(이전 페이지의 이미지 등) 사용하지 않는 메모리 해제를 시도합니다.

참고로 맹목적으로 이 메서드를 호출하는 것은 이 빈 캐시를 다시 채워야하기 때문에 Electron을 느리게 만듭니다. 따라서 이 메서드는 페이지가 예상했던 것 보다 실질적으로 더 적은 메모리를 사용하게 만드는 애플리케이션 이벤트가 발생했을 때만 호출해야 합니다. (i.e. 아주 무거운 페이지에서 거의 빈 페이지로 이동한 후 계속 유지할 경우)


<webview> 태그

외부 웹 콘텐츠를 고립된 프레임과 프로세스에서 표시합니다.

guest 콘텐츠(웹 페이지)를 Electron 앱 페이지에 삽입하기 위해 webview 태그를 사용할 수 있습니다. 게스트 콘텐츠는 webview 컨테이너에 담겨 대상 페이지에 삽입되고 해당 페이지에선 게스트 콘텐츠의 배치 및 렌더링 과정을 조작할 수 있습니다.

iframe과는 달리 webview는 애플리케이션과 분리된 프로세스에서 작동합니다. 이는 웹 페이지와 같은 권한을 가지지 않고 앱과 임베디드(게스트) 콘텐츠간의 모든 상호작용이 비동기로 작동한다는 것을 의미합니다. 따라서 임베디드 콘텐츠로부터 애플리케이션을 안전하게 유지할 수 있습니다.

보안상의 이유로, webviewnodeIntegration이 활성화된 BrowserWindow에서만 사용할 수 있습니다.

예시

웹 페이지를 애플리케이션에 삽입하려면 webview 태그를 사용해 원하는 타겟 페이지에 추가하면 됩니다. (게스트 콘텐츠가 앱 페이지에 추가 됩니다) 간단한 예로 webview 태그의 src 속성에 페이지를 지정하고 css 스타일을 이용해서 컨테이너의 외관을 설정할 수 있습니다:

<webview id="foo" src="https://www.github.com/" style="display:inline-flex; width:640px; height:480px"></webview>

게스트 콘텐츠를 조작하기 위해 자바스크립트로 webview 태그의 이벤트를 리스닝 하여 응답을 받을 수 있습니다. 다음 예시를 참고하세요: 첫번째 리스너는 페이지 로딩 시작시의 이벤트를 확인하고 두번째 리스너는 페이지의 로딩이 끝난시점을 확인합니다. 그리고 페이지를 로드하는 동안 “loading…” 메시지를 표시합니다.

<script>
  onload = () => {
    const webview = document.getElementById('foo')
    const indicator = document.querySelector('.indicator')

    const loadstart = () => {
      indicator.innerText = 'loading...'
    }

    const loadstop = () => {
      indicator.innerText = ''
    }

    webview.addEventListener('did-start-loading', loadstart)
    webview.addEventListener('did-stop-loading', loadstop)
  }
</script>

CSS 스타일링 참고

주의할 점은 webview 태그의 스타일은 전통적인 flexbox 레이아웃을 사용했을 때 자식 object 요소가 해당 webview 컨테이너의 전체 높이와 넓이를 확실히 채우도록 내부적으로 display:flex;를 사용합니다. (v0.36.11 부터) 따라서 인라인 레이아웃을 위해 display:inline-flex;를 쓰지 않는 한, 기본 display:flex; CSS 속성을 덮어쓰지 않도록 주의해야 합니다.

webviewhidden 또는 display: none; 속성을 사용할 때 발생하는 문제를 한 가지 가지고 있습니다. 자식 browserplugin 객체 내에서 비정상적인 랜더링 동작을 발생시킬 수 있으며 웹 페이지가 로드되었을 때, webview가 숨겨지지 않았을 때, 반대로 그냥 바로 다시 보이게 됩니다. webview를 숨기는 방법으로 가장 권장되는 방법은 width & height를 0으로 지정하는 CSS를 사용하는 것이며 flex를 통해 0px로 요소를 수축할 수 있도록 합니다.

<style>
  webview {
    display:inline-flex;
    width:640px;
    height:480px;
  }
  webview.hide {
    flex: 0 1;
    width: 0px;
    height: 0px;
  }
</style>

태그 속성

webview 태그는 다음과 같은 속성을 가지고 있습니다:

src

<webview src="https://www.github.com/"></webview>

지정한 URL을 페이지 소스로 사용합니다. 이 속성을 지정할 경우 webview의 최상위 페이지가 됩니다.

src에 같은 페이지를 지정하면 페이지를 새로고침합니다.

src 속성은 data:text/plain,Hello, world! 같은 data URL도 사용할 수 있습니다.

autosize

<webview src="https://www.github.com/" autosize="on" minwidth="576" minheight="432"></webview>

“on” 으로 지정하면 webview 컨테이너는 minwidth, minheight, maxwidth, maxheight에 맞춰서 자동으로 크기를 조절합니다. 이 속성들은 autosize가 활성화되어있지 않는 한 프레임에 영향을 주지 않습니다. autosize가 활성화 되어있으면 webview 컨테이너의 크기는 각각의 지정한 최대, 최소값에 따라 조절됩니다.

nodeintegration

<webview src="http://www.google.com/" nodeintegration></webview>

“on”으로 지정하면 webview 페이지 내에서 requireprocess 객체같은 node.js API를 사용할 수 있습니다. 이를 지정하면 내부에서 로우레벨 리소스에 접근할 수 있습니다.

plugins

<webview src="https://www.github.com/" plugins></webview>

“on”으로 지정하면 webview 내부에서 브라우저 플러그인을 사용할 수 있습니다.

preload

<webview src="https://www.github.com/" preload="./test.js"></webview>

페이지가 로드되기 전에 실행할 스크립트를 지정합니다. 스크립트 URL은 file: 또는 asar: 프로토콜 중 하나를 반드시 사용해야 합니다. 왜냐하면 페이지 내에서 require를 사용하여 스크립트를 로드하기 때문입니다.

페이지가 nodeintegration을 활성화 하지 않아도 지정한 스크립트는 정상적으로 작동합니다. 하지만 스크립트 내에서 사용할 수 있는 global 객체는 스크립트 작동이 끝나면 삭제됩니다.

httpreferrer

<webview src="https://www.github.com/" httpreferrer="http://cheng.guru"></webview>

페이지의 referrer URL을 설정합니다.

useragent

<webview src="https://www.github.com/" useragent="Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko"></webview>

페이지의 User-Agent를 설정합니다. 페이지가 로드된 후엔 setUserAgent 메소드를 사용해서 변경할 수 있습니다.

disablewebsecurity

<webview src="https://www.github.com/" disablewebsecurity></webview>

“on”으로 지정하면 페이지의 웹 보안을 해제합니다.

partition

<webview src="https://github.com" partition="persist:github"></webview>
<webview src="http://electron.atom.io" partition="electron"></webview>

페이지에서 사용하는 세션을 설정합니다. 만약 partition 속성이 persist: 접두사를 시작하면 같은 partition 속성을 가진 앱 내 모든 페이지가 공유하는 영구 세션을 사용합니다. persist: 접두사가 없을 경우 페이지는 인 메모리 세션을 사용합니다. 동일한 partition을 지정하여 다중 페이지에서 동일한 세션을 공유할 수 있도록 할 수 있습니다. 만약 partition이 지정되지 않으면 앱의 기본 세션을 사용합니다.

이 값은 첫 탐색 이전에만 지정할 수 있습니다. 즉. 작동중인 렌더러 프로세스의 세션은 변경할 수 없습니다. 이후 이 값을 바꾸려고 시도하면 DOM 예외를 발생시킵니다.

allowpopups

<webview src="https://www.github.com/" allowpopups></webview>

“on”으로 지정하면 페이지에서 새로운 창을 열 수 있도록 허용합니다.

blinkfeatures

<webview src="https://www.github.com/" blinkfeatures="PreciseMemoryInfo, CSSVariables"></webview>

활성화할 blink 기능을 지정한 ,로 구분된 문자열의 리스트입니다. 지원하는 기능 문자열의 전체 목록은 RuntimeEnabledFeatures.in 파일에서 찾을 수 있습니다.

disableblinkfeatures

<webview src="https://www.github.com/" disableblinkfeatures="PreciseMemoryInfo, CSSVariables"></webview>

비활성화할 blink 기능을 지정한 ,로 구분된 문자열의 리스트입니다. 지원하는 기능 문자열의 전체 목록은 RuntimeEnabledFeatures.in 파일에서 찾을 수 있습니다.

guestinstance

<webview src="https://www.github.com/" guestinstance="3"></webview>

webview 를 특정 webContents 와 연결해주는 값 입니다. webview 가 처음 로드될 때 새 webContents 가 생성되고 이 속성이 그 인스턴스의 식별자로 설정됩니다. 새로운 또는 기존 webview 에 이 속성을 설정하면 다른 webview 에서 현재 렌더링하는 기존 webContents 와 연결합니다.

기존 webview 는 destroy 이벤트가 발생하고 새 URL 이 로드될 때 새 webContens 가 생성될 것 입니다.

Methods

webview 태그는 다음과 같은 메서드를 가지고 있습니다:

참고: 태그 객체의 메서드는 페이지 로드가 끝난 뒤에만 사용할 수 있습니다.

예시

const webview = document.getElementById('foo')
webview.addEventListener('dom-ready', () => {
  webview.openDevTools()
})

<webview>.loadURL(url[, options])

Webview에 웹 페이지 url을 로드합니다. urlhttp://, file://과 같은 프로토콜 접두사를 가지고 있어야 합니다.

<webview>.getURL()

페이지의 URL을 반환합니다.

<webview>.getTitle()

페이지의 제목을 반환합니다.

<webview>.isLoading()

페이지가 아직 리소스를 로딩하고 있는지 확인합니다. 불린 값을 반환합니다.

<webview>.isWaitingForResponse()

페이지가 메인 리소스의 첫 응답을 기다리고 있는지 확인합니다. 불린 값을 반환합니다.

<webview>.stop()

모든 탐색을 취소합니다.

<webview>.reload()

페이지를 새로고침합니다.

<webview>.reloadIgnoringCache()

캐시를 무시하고 페이지를 새로고침합니다.

<webview>.canGoBack()

페이지 히스토리를 한 칸 뒤로 가기를 할 수 있는지 확인합니다. 불린 값을 반환합니다.

<webview>.canGoForward()

페이지 히스토리를 한 칸 앞으로 가기를 할 수 있는지 확인합니다. 불린 값을 반환합니다.

<webview>.canGoToOffset(offset)

페이지 히스토리를 offset 만큼 이동할 수 있는지 확인합니다. 불린값을 반환합니다.

<webview>.clearHistory()

탐색 히스토리를 비웁니다.

<webview>.goBack()

페이지 뒤로 가기를 실행합니다.

<webview>.goForward()

페이지 앞으로 가기를 실행합니다.

<webview>.goToIndex(index)

페이지를 지정한 index로 이동합니다.

<webview>.goToOffset(offset)

페이지로부터 offset 만큼 이동합니다.

<webview>.isCrashed()

렌더러 프로세스가 크래시 됬는지 확인합니다.

<webview>.setUserAgent(userAgent)

User-Agent를 지정합니다.

<webview>.getUserAgent()

페이지의 User-Agent 문자열을 가져옵니다.

<webview>.insertCSS(css)

페이지에 CSS를 삽입합니다.

<webview>.executeJavaScript(code[, userGesture, callback])

페이지에서 자바스크립트 코드를 실행합니다.

만약 userGesturetrue로 설정되어 있으면 페이지에 유저 제스쳐 컨텍스트를 만듭니다. 이 옵션을 활성화 시키면 requestFullScreen와 같은 HTML API에서 유저의 승인을 무시하고 개발자가 API를 바로 사용할 수 있도록 허용합니다.

역자주: 기본적으로 브라우저에선 전체화면, 웹캠, 파일 열기등의 API를 사용하려면 유저의 승인(이벤트)이 필요합니다.

<webview>.openDevTools()

페이지에 대한 개발자 도구를 엽니다.

<webview>.closeDevTools()

페이지에 대한 개발자 도구를 닫습니다.

<webview>.isDevToolsOpened()

페이지에 대한 개발자 도구가 열려있는지 확인합니다. 불린 값을 반환합니다.

<webview>.isDevToolsFocused()

페이지의 개발자 도구에 포커스 되어있는지 여부를 반화합니다.

<webview>.inspectElement(x, y)

(x, y) 위치에 있는 엘리먼트를 inspect합니다.

<webview>.inspectServiceWorker()

Service worker��� 대한 개발자 도구를 엽니다.

<webview>.setAudioMuted(muted)

게스트 페이지 음소거 설정.

<webview>.isAudioMuted()

Returns Boolean - 게스트 페이지 음소거 여부.

<webview>.undo()

페이지에서 실행 취소 커맨드를 실행합니다.

<webview>.redo()

페이지에서 다시 실행 커맨드를 실행합니다.

<webview>.cut()

페이지에서 잘라내기 커맨드를 실행합니다.

<webview>.copy()

페이지에서 복사 커맨드를 실행합니다.

<webview>.paste()

페이지에서 붙여넣기 커맨드를 실행합니다.

<webview>.pasteAndMatchStyle()

페이지에서 pasteAndMatchStyle 편집 커맨드를 실행합니다.

<webview>.delete()

페이지에서 삭제 커맨드를 실행합니다.

<webview>.selectAll()

페이지에서 전체 선택 커맨드를 실행합니다.

<webview>.unselect()

페이지에서 unselect 커맨드를 실행합니다.

<webview>.replace(text)

페이지에서 replace 커맨드를 실행합니다.

<webview>.replaceMisspelling(text)

페이지에서 replaceMisspelling 커맨드를 실행합니다.

<webview>.insertText(text)

포커스된 요소에 text를 삽입합니다.

webContents.findInPage(text[, options])

웹 페이지에서 text에 일치하는 모든 대상을 찾는 요청을 시작하고 요청에 사용된 요청을 표현하는 정수(integer)를 반환합니다. 요청의 결과는 found-in-page 이벤트를 통해 취득할 수 있습니다.

webContents.stopFindInPage(action)

제공된 action에 대한 webContents의 모든 findInPage 요청을 중지합니다.

<webview>.print([options])

webview 페이지를 인쇄합니다. webContents.print([options]) 메서드와 같습니다.

<webview>.printToPDF(options, callback)

webview 페이지를 PDF 형식으로 인쇄합니다. webContents.printToPDF(options, callback) 메서드와 같습니다.

<webview>.capturePage([rect, ]callback)

webview의 페이지의 스냅샷을 캡쳐합니다. webContents.printToPDF(options, callback) 메서드와 같습니다.

<webview>.send(channel[, arg1][, arg2][, ...])

channel을 통해 렌더러 프로세스로 비동기 메시지를 보냅니다. 또한 args를 지정하여 임의의 인수를 보낼 수도 있습니다. 렌더러 프로세스는 ipcRenderer 모듈의 channel 이벤트로 이 메시지를 받아 처리할 수 있습니다.

예시는 webContents.send를 참고하세요.

<webview>.sendInputEvent(event)

페이지에 입력 event를 보냅니다.

event 객체에 대해 자세히 알아보려면 webContents.sendInputEvent를 참고하세요.

<webview>.setZoomFactor(factor)

지정한 수치로 줌 수치를 변경합니다. 줌 수치는 100으로 나눈 값이며 300%는 3.0이 됩니다.

<webview>.setZoomLevel(level)

지정한 수준으로 줌 수준을 변경합니다. 원본 크기는 0이고 각 값의 증가와 감소는 현재 줌을 20% 크거나 작게 표현하고 각 크기는 원본 크기의 300%와 50%로 제한됩니다.

<webview>.showDefinitionForSelection() macOS

페이지에서 선택된 단어에 대한 사전 검색 결과 팝업을 표시합니다.

<webview>.getWebContents()

webview에 해당하는 WebContents를 반환합니다.

DOM 이벤트

webview 태그는 다음과 같은 DOM 이벤트를 가지고 있습니다:

Event: ‘load-commit’

Returns:

로드가 시작됬을 때 발생하는 이벤트입니다. 이 이벤트는 현재 문서내의 탐색뿐만 아니라 서브 프레임 문서 레벨의 로드도 포함됩니다. 하지만 비동기 리소스 로드는 포함되지 않습니다.

Event: ‘did-finish-load’

탐색이 끝나면 발생하는 이벤트입니다. 브라우저 탭의 스피너가 멈추고 onload 이벤트가 발생할 때를 생각하면 됩니다.

Event: ‘did-fail-load’

Returns:

did-finish-load와 비슷합니다. 하지만 이 이벤트는 window.stop()과 같이 취소 함수가 호출되었거나 로드에 실패했을 때 발생하는 이벤트입니다.

Event: ‘did-frame-finish-load’

Returns:

프레임의 탐색이 끝나면 발생하는 이벤트입니다.

Event: ‘did-start-loading’

브라우저 탭의 스피너가 돌기 시작할 때 처럼 페이지의 로드가 시작될 때 발생하는 이벤트입니다.

Event: ‘did-stop-loading’

브라우저 탭의 스피너가 멈출 때 처럼 페이지의 로드가 끝나면 발생하는 이벤트입니다.

Event: ‘did-get-response-details’

Returns:

요청한 리소스에 관해 자세한 내용을 알 수 있을 때 발생하는 이벤트입니다. status는 리소스를 다운로드할 소켓 커낵션을 나타냅니다.

Event: ‘did-get-redirect-request’

Returns:

리소스를 요청하고 받는 도중에 리다이렉트가 생기면 발생하는 이벤트입니다.

Event: ‘dom-ready’

프레임 문서의 로드가 끝나면 발생하는 이벤트입니다.

Event: ‘page-title-updated’

Returns:

탐색하는 동안에 페이지의 제목이 설정되면 발생하는 이벤트입니다. explicitSet는 파일 URL에서 합성(synthesised)된 제목인 경우 false로 표시됩니다.

Event: ‘page-favicon-updated’

Returns:

페이지가 favicon URL을 받았을 때 발생하는 이벤트입니다.

Event: ‘enter-html-full-screen’

페이지가 HTML API에 의해 전체 화면 모드에 돌입했을 때 발생하는 이벤트입니다.

Event: ‘leave-html-full-screen’

페이지의 전체 화면 모드가 해제됬을 때 발생하는 이벤트입니다.

Event: ‘console-message’

Returns:

console.log API에 의해 로깅될 때 발생하는 이벤트입니다.

다음 예시는 모든 로그 메시지를 로그 레벨이나 다른 속성에 관련 없이 호스트 페이지의 콘솔에 다시 로깅하는 예시입니다.

const webview = document.getElementById('foo')
webview.addEventListener('console-message', (e) => {
  console.log('Guest page logged a message:', e.message)
})

Event: ‘found-in-page’

Returns:

webContents.findInPage 요청의 결과를 사용할 수 있을 때 발생하는 이벤트입니다.

const webview = document.getElementById('foo')
webview.addEventListener('found-in-page', (e) => {
  webview.stopFindInPage('keepSelection')
})

const requestId = webview.findInPage('test')
console.log(requestId)

Event: ‘new-window’

Returns:

페이지가 새로운 브라우저 창을 생성할 때 발생하는 이벤트입니다.

다음 예시 코드는 새 URL을 시스템의 기본 브라우저로 여는 코드입니다.

const {shell} = require('electron')
const webview = document.getElementById('foo')

webview.addEventListener('new-window', (e) => {
  const protocol = require('url').parse(e.url).protocol
  if (protocol === 'http:' || protocol === 'https:') {
    shell.openExternal(e.url)
  }
})

Event: ‘will-navigate’

Returns:

사용자 또는 페이지가 새로운 페이지로 이동할 때 발생하는 이벤트입니다. window.location 객체가 변경되거나 사용자가 페이지의 링크를 클릭했을 때 발생합니다.

이 이벤트는 <webview>.loadURL<webview>.back 같은 API를 이용한 프로그램적으로 시작된 탐색에 대해서는 발생하지 않습니다.

이 이벤트는 앵커 링크를 클릭하거나 window.location.hash의 값을 변경하는 등의 페이지 내 탐색시엔 발생하지 않습니다. 대신 did-navigate-in-page 이벤트를 사용해야 합니다.

event.preventDefault()를 호출하는 것은 아무 효과도 내지 않습니다.

Event: ‘did-navigate’

Returns:

탐색이 완료되면 발생하는 이벤트입니다.

이 이벤트는 앵커 링크를 클릭하거나 window.location.hash의 값을 변경하는 등의 페이지 내 탐색시엔 발생하지 않습니다. 대신 did-navigate-in-page 이벤트를 사용해야 합니다.

Event: ‘did-navigate-in-page’

Returns:

페이지 내의 탐색이 완료되면 발생하는 이벤트입니다.

페이지 내의 탐색이 발생하면 페이지 URL이 변경되지만 페이지 밖으로의 탐색은 일어나지 않습니다. 예를 들어 앵커 링크를 클릭했을 때, 또는 DOM hashchange 이벤트가 발생했을 때로 볼 수 있습니다.

Event: ‘close’

페이지가 자체적으로 닫힐 때 발생하는 이벤트입니다.

다음 예시 코드는 페이지가 자체적으로 닫힐 때 webviewabout:blank 페이지로 이동시키는 예시입니다.

const webview = document.getElementById('foo')
webview.addEventListener('close', () => {
  webview.src = 'about:blank'
})

Event: ‘ipc-message’

Returns:

호스트 페이지에서 비동기 IPC 메시지를 보낼 때 발생하는 이벤트입니다.

sendToHost 메소드와 ipc-message 이벤트로 호스트 페이지와 쉽게 통신을 할 수 있습니다:

// In embedder page.
const webview = document.getElementById('foo')
webview.addEventListener('ipc-message', (event) => {
  console.log(event.channel)
  // Prints "pong"
})
webview.send('ping')
// In guest page.
const {ipcRenderer} = require('electron')
ipcRenderer.on('ping', () => {
  ipcRenderer.sendToHost('pong')
})

Event: ‘crashed’

렌더러 프로세스가 크래시 되었을 때 발생하는 이벤트입니다.

Event: ‘gpu-crashed’

GPU 프로세스가 크래시 되었을 때 발생하는 이벤트입니다.

Event: ‘plugin-crashed’

Returns:

플러그인 프로세스가 크래시 되었을 때 발생하는 이벤트입니다.

Event: ‘destroyed’

WebContents가 소멸될 때 발생하는 이벤트입니다.

Event: ‘media-started-playing’

미디어가 재생되기 시작할 때 발생하는 이벤트입니다.

Event: ‘media-paused’

미디어가 중지되거나 재생이 완료되었을 때 발생하는 이벤트입니다.

Event: ‘did-change-theme-color’

Returns:

페이지의 테마 색이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 보통 meta 태그에 의해서 발생합니다:

<meta name='theme-color' content='#ff0000'>

Event: ‘update-target-url’

Returns:

마우스나 키보드를 사용해 링크에 포커스할 때 발생하는 이벤트입니다.

Event: ‘devtools-opened’

개발자 도구가 열렸을 때 발생하는 이벤트입니다.

Event: ‘devtools-closed’

개발자 도구가 닫혔을 때 발생하는 이벤트입니다.

Event: ‘devtools-focused’

개발자 도구가 포커스되거나 열렸을 때 발생하는 이벤트입니다.


window.open 함수

새 윈도우를 열고 URL을 로드합니다.

window.open 함수가 호출되면 새 창을 생성하고 url 페이지를 불러옵니다. 이 창은 지정한 url을 로드하여 만들어진 BrowserWindow의 새 인스턴스이며 본래 창 객체 대신 페이지의 컨트롤이 제한된 프록시 객체를 반환합니다.

프록시 객체는 브라우저의 웹 페이지 창과 호환될 수 있도록 일부 제한된 표준 기능만 가지고 있습니다. 창의 모든 컨트롤 권한을 가지려면 BrowserWindow를 직접 생성해서 사용해야 합니다.

새롭게 생성된 BrowserWindow는 기본적으로 부모 창의 옵션을 상속합니다. 이 옵션을 변경하려면 새 창을 열 때 features 인수를 지정해야 합니다.

window.open(url[, frameName][, features])

BrowserWindowProxy 클래스의 객체를 반환하는 새로운 윈도우를 생성합니다.

features 문자열은 표준 브라우저의 포맷을 따르고 있지만, 각 기능은 BrowserWindow의 옵션이어야 합니다.

참고: * Node 통합 기능은 열린 window 에서 부모 윈도우가 해당 옵션이 비활성화 되어있는 경우 항상 비활성화됩니다. * features 에 있는 (Chromium 또는 Electron 에 의해 처리되지 않는) 비표준 기능은 webContent 에 등록된 new-window 이벤트 핸들러에 additionalFeatures 인수로 전달될 것이다.

window.opener.postMessage(message, targetOrigin)

부모 윈도우에 메시지를 보냅니다. origin을 특정할 수 있으며 *를 지정하면 따로 origin 설정을 사용하지 않습니다.

Class: BrowserWindowProxy

자식 브라우저 윈도우를 조작합니다

Instance Methods

BrowserWindowProxy 객체는 다음과 같은 인스턴스 메서드를 가지고 있습니다:

win.blur()

자식 윈도우의 포커스를 해제합니다.

win.close()

자식 윈도우를 강제로 닫습니다. unload 이벤트가 발생하지 않습니다.

win.eval(code)

자식 윈도우에서 특정 스크립트를 실행합니다.

win.focus()

자식 윈도우에 포커스를 맞춥니다. (창을 맨 앞으로 가져옵니다)

win.print()

자식 윈도우에 프린트 대화 상자를 호출합니다.

win.postMessage(message, targetOrigin)

자식 윈도우에 메시지를 보냅니다. origin을 특정할 수 있으며 *를 지정하면 따로 origin 설정을 사용하지 않습니다.

참고로 자식 윈도우의 window.opener 객체에는 다른 속성 없이 이 메서드 한 개만 구현되어 있습니다.

Instance Properties

BrowserWindowProxy 객체는 다음과 같은 인스턴스 속성을 가지고 있습니다:

win.closed

자식 윈도우가 닫히면 true로 설정됩니다.


Electron이 NW.js(node-webkit)와 기술적으로 다른점

참고: Electron은 Atom Shell의 새로운 이름입니다.

NW.js 처럼 Electron은 JavaScript와 HTML 그리고 Node 통합 환경을 제공함으로써 웹 페이지에서 저 수준 시스템에 접근할 수 있도록 하여 웹 기반 데스크탑 애플리케이션을 작성할 수 있도록 하는 프레임워크 입니다.

하지만 Electron과 NW.js는 근본적인 개발흐름의 차이도 있습니다:

1. 애플리케이션의 엔트리 포인트

NW.js에선 애플리케이션의 엔트리 포인트로 웹 페이지를 사용합니다. package.json내의 main 필드에 메인 웹 페이지(index.html) URL을 지정하면 애플리케이션의 메인 윈도우로 열리게 됩니다.

Electron에선 JavaScript를 엔트리 포인트로 사용합니다. URL을 직접 제공하는 대신 API를 사용하여 직접 브라우저 창과 HTML 파일을 로드할 수 있습니다. 또한 윈도우의 종료시기를 결정하는 이벤트를 리스닝해야 합니다.

Electron은 Node.js 런타임과 비슷하게 작동합니다. Electron의 API는 저수준이기에 브라우저 테스팅을 위해 PhantomJS를 사용할 수도 있습니다.

2. 빌드 시스템

Electron은 Chromium의 모든것을 빌드하는 복잡성을 피하기 위해 libchromiumcontent를 사용하여 Chromium의 Content API에 접근합니다. libchromiumcontent은 단일 공유 라이브러리이고 Chromium Content 모듈과 의존성 라이브러리들을 포함합니다. 유저는 Electron을 빌드 하기 위해 높은 사양의 빌드용 컴퓨터를 구비할 필요가 없습니다.

3. Node 통합

NW.js는 웹 페이지에서 require를 사용할 수 있도록 Chromium을 패치했습니다. 한편 Electron은 Chromium의 해킹을 방지하기 위해 libuv loop와 각 플랫폼의 메시지 루프에 통합하는 다른 방법을 채택하였습니다. node_bindings의 코드를 보면 이 부분이 어떻게 구현됬는지 알 수 있습니다.

4. 다중 컨텍스트

만약 NW.js를 사용해본 적이 있다면 Node context와 Web context의 개념을 잘 알고 있을 겁니다. 이러한 개념은 NW.js가 구현되기 위해 만들어졌습니다.

Node의 다중 컨텍스트를 사용하기 때문에 Electron은 웹 페이지의 새로운 JavaScript 컨텍스트를 생성하지 않습니다.

참고: NW.js는 0.13 버전부터 선택적으로 다중 컨텍스트를 지원합니다.


빌드 설명서 (Linux)

이 가이드는 Linux 운영체제에서 Electron을 빌드하는 방법을 설명합니다.

빌드전 요구사양

Ubuntu를 사용하고 있다면 다음과 같이 라이브러리를 설치해야 합니다:

$ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \
                       libnotify-dev libgnome-keyring-dev libgconf2-dev \
                       libasound2-dev libcap-dev libcups2-dev libxtst-dev \
                       libxss1 libnss3-dev gcc-multilib g++-multilib curl \
                       gperf bison

Fedora를 사용하고 있다면 다음과 같이 라이브러리를 설치해야 합니다:

$ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring-devel \
                   xorg-x11-server-utils libcap-devel cups-devel libXtst-devel \
                   alsa-lib-devel libXrandr-devel GConf2-devel nss-devel bison \
                   gperf

다른 배포판의 경우 pacman 같은 패키지 매니저를 통해 패키지를 설치 할 수 있습니다. 패키지의 이름은 대부분 위 예시와 비슷할 것입니다. 또는 소스 코드를 내려받아 직접 빌드하는 방법도 있습니다.

코드 가져오기

$ git clone https://github.com/electron/electron.git

부트 스트랩

부트스트랩 스크립트는 필수적인 빌드 의존성 라이브러리들을 모두 다운로드하고 프로젝트 파일을 생성합니다. 스크립트가 정상적으로 작동하기 위해선 Python 2.7.x 버전이 필요합니다. 아마 다운로드 작업이 상당히 많은 시간을 소요할 것입니다. 참고로 Electron은 ninja를 빌드 툴체인으로 사용하므로 Makefile은 생성되지 않습니다.

$ cd electron
$ ./script/bootstrap.py -v

크로스 컴파일

arm 아키텍쳐로 빌드 하려면 다음 의존성 라이브러리를 설치해야 합니다:

$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \
                       g++-arm-linux-gnueabihf

그리고 bootstrap.py 스크립트의 --target_arch 파라미터에 arm 또는 ia32 아키텍쳐를 지정하여 크로스 컴파일 할 수 있습니다:

$ ./script/bootstrap.py -v --target_arch=arm

빌드하기

ReleaseDebug 두 타겟 모두 빌드 합니다:

$ ./script/build.py

이 스크립트는 out/R 디렉터리에 크기가 매우 큰 Electron 실행 파일을 배치합니다. 파일 크기는 1.3GB를 초과합니다. 이러한 문제가 발생하는 이유는 Release 타겟 바이너리가 디버그 심볼을 포함하기 때문입니다. 파일 크기를 줄이려면 create-dist.py 스크립트를 실행하세요:

$ ./script/create-dist.py

이 스크립트는 매우 작은 배포판을 dist 디렉터리에 생성합니다. create-dist.py 스크립트를 실행한 이후부턴 1.3GB에 육박하는 공간을 차지하는 out/R 폴더의 바이너리는 삭제해도 됩니다.

또는 Debug 타겟만 빌드 할 수 있습니다:

$ ./script/build.py -c D

빌드가 모두 끝나면 out/D 디렉터리에서 electron 디버그 바이너리를 찾을 수 있습니다.

정리하기

빌드 파일들을 정리하려면:

$ npm run clean

문제 해결

libtinfo.so.5 동적 링크 라이브러리를 로드하는 도중 에러가 발생할 경우

미리 빌드된 clanglibtinfo.so.5로 링크를 시도합니다. 따라서 플랫폼에 따라 적당한 libncurses symlink를 추가하세요:

$ sudo ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5

테스트

빌드 시스템 개요: 테스트를 보세요.

고급 주제

기본적인 빌드 구성은 가장 주력인 Linux 배포판에 초점이 맞춰져있으며, 특정 배포판이나 기기에 빌드할 계획이라면 다음 정보들이 도움이 될 것입니다.

로컬에서 libchromiumcontent 빌드하기

미리 빌드된 libchromiumcontent를 사용하는 것을 피하기 위해, bootstrap.py 스크립트에 --build_libchromiumcontent 스위치를 추가할 수 있습니다:

$ ./script/bootstrap.py -v --build_libchromiumcontent

참고로 shared_library 구성은 기본적으로 빌드되어있지 않으며, 다음 모드를 사용하면 Release 버전의 Electron만 빌드할 수 있습니다:

$ ./script/build.py -c R

다운로드된 clang 바이너리 대신 시스템의 clang 사용하기

기본적으로 Electron은 Chromium 프로젝트에서 제공하는 미리 빌드된 clang 바이너리를 통해 빌드됩니다. 만약 어떤 이유로 시스템에 설치된 clang을 사용하여 빌드하고 싶다면, bootstrap.py--clang_dir=<path> 스위치와 함께 실행함으로써 해결할 수 있습니다. 빌드 스크립트를 이 스위치와 함께 실행할 때 스크립트는 <path>/bin/와 같은 경로로 clang 바이너리를 찾습니다.

예를 들어 clang/user/local/bin/clang에 설치했다면 다음과 같습니다:

$ ./script/bootstrap.py -v --build_libchromiumcontent --clang_dir /usr/local
$ ./script/build.py -c R

clang 대신 다른 컴파일러 사용하기

Electron을 g++과 같은 다른 컴파일러로 빌드하려면, 먼저 --disable_clang 스위치를 통해 clang을 비활성화 시켜야 하고, 필요하다면 CCCXX 환경 변수도 설정합니다.

예를 들어 GCC 툴체인을 사용하여 빌드한다면 다음과 같습니다:

$ env CC=gcc CXX=g++ ./script/bootstrap.py -v --build_libchromiumcontent --disable_clang
$ ./script/build.py -c R

환경 변수

또한 CCCXX와는 별개로, 빌드 구성을 변경하기 위해 다음 환경 변수들을 사용할 수 있습니다:

이 환경 변수는 bootstrap.py 스크립트를 실행할 때 설정되어야 하며, build.py 스크립트에선 작동하지 않습니다.


빌드 설명서 (macOS)

이 가이드는 macOS 운영체제에서 Electron을 빌드하는 방법을 설명합니다.

빌드전 요구 사항

만약 Homebrew 를 이용해 파이썬을 설치했다면 다음 파이썬 모듈도 같이 설치해야 합니다:

코드 가져오기

$ git clone https://github.com/electron/electron

부트 스트랩

부트스트랩 스크립트는 필수적인 빌드 의존성 라이브러리들을 모두 다운로드하고 프로젝트 파일을 생성합니다. 참고로 Electron은 ninja 를 빌드 툴체인으로 사용하므로 Xcode 프로젝트는 생성되지 않습니다.

$ cd electron
$ ./script/bootstrap.py -v

빌드하기

ReleaseDebug 두 타겟 모두 빌드 합니다:

$ ./script/build.py

또는 Debug 타겟만 빌드 할 수 있습니다:

$ ./script/build.py -c D

빌드가 모두 끝나면 out/D 디렉터리에서 Electron.app 실행 파일을 찾을 수 있습니다.

32비트 지원

Electron은 현재 macOS 64비트만 지원하고 있습니다. 그리고 앞으로도 macOS 32비트는 지원할 계획이 없습니다.

정리하기

빌드 파일들을 정리하려면:

$ npm run clean

테스트

빌드 시스템 개요: 테스트를 보세요.


빌드 설명서 (Windows)

이 가이드는 Windows 운영체제에서 Electron을 빌드하는 방법을 설명합니다.

빌드전 요구 사항

현재 사용하고 있는 PC에 Windows를 설치하지 않았다면 dev.microsoftedge.com에서 사용 기한이 정해져있는 무료 가상머신 버전의 Windows를 받아 Electron을 빌드하는 방법도 있습니다.

Electron은 모든 빌드를 command-line 스크립트를 통해 빌드합니다. 따라서 빌드에 Visual Studio를 사용할 수 없습니다. 하지만 여전히 Electron을 개발할 땐 어떤 에디터든 사용이 가능합니다. 그리고 빠른 시일내에 Visual Studio를 이용한 빌드도 지원할 계획입니다.

참고: Visual Studio가 직접 빌드에 사용되지 않더라도 IDE와 같이 제공된 빌드 툴체인이 빌드에 반드시 사용되므로 여전히 필요합니다.

참고: Visual Studio 2013은 사용할 수 없습니다 MSVS 2015 을 사용하고 있는지 확인해주세요.

코드 가져오기

$ git clone https://github.com/electron/electron.git

부트 스트랩

부트스트랩 스크립트는 필수적인 빌드 의존성 라이브러리들을 모두 다운로드하고 프로젝트 파일을 생성합니다. 참고로 Electron은 ninja를 빌드 툴체인으로 사용하므로 Visual Studio 프로젝트는 생성되지 않습니다.

$ cd electron
$ python script\bootstrap.py -v

빌드하기

ReleaseDebug 두 타겟 모두 빌드 합니다:

$ python script\build.py

또는 Debug 타겟만 빌드 할 수 있습니다:

$ python script\build.py -c D

빌드가 모두 끝나면 out/D (디버그 타겟) 또는 out/R (릴리즈 타겟) 디렉터리에서 electron.exe 실행 파일을 찾을 수 있습니다.

32비트 빌드

32비트를 타겟으로 빌드 하려면 부트스트랩 스크립트를 실행할 때 --target_arch=ia32 인수를 같이 넘겨주면 됩니다:

$ python script\bootstrap.py -v --target_arch=ia32

다른 빌드 단계도 정확하게 같습니다.

Visual Studio 프로젝트

Visual Studio 프로젝트를 생성하려면, --msvs 인수를 전달할 수 있습니다:

$ python script\bootstrap.py --msvs

정리하기

빌드 파일들을 정리하려면:

$ npm run clean

테스트

빌드 시스템 개요: 테스트를 보세요.

문제 해결

Command xxxx not found

만약 Command xxxx not found와 같은 형식의 에러가 발생했다면 VS2015 Command Prompt 콘솔로 빌드 스크립트를 실행해 보는게 좋습니다.

Fatal internal compiler error: C1001

Visual Studio가 업데이트까지 완벽하게 설치된 최신버전인지 확인하세요.

Assertion failed: ((handle))->activecnt >= 0

Cygwin에서 빌드 할 경우 bootstrap.py 스크립트가 다음의 에러와 함께 빌드에 실패할 수 있습니다:

Assertion failed: ((handle))->activecnt >= 0, file src\win\pipe.c, line 1430

Traceback (most recent call last):
  File "script/bootstrap.py", line 87, in <module>
    sys.exit(main())
  File "script/bootstrap.py", line 22, in main
    update_node_modules('.')
  File "script/bootstrap.py", line 56, in update_node_modules
    execute([NPM, 'install'])
  File "/home/zcbenz/codes/raven/script/lib/util.py", line 118, in execute
    raise e
subprocess.CalledProcessError: Command '['npm.cmd', 'install']' returned non-zero exit status 3

이 버그는 Cygwin Python과 Win32 Node를 같이 사용할 때 발생합니다. 부트스트랩 스크립트에서 Win32 Python을 사용함으로써 이 문제를 해결할 수 있습니다. C:\Python27 디렉터리에 Python이 설치되었다는 가정하에 다음 명령을 실행하면 됩니다:

$ /cygdrive/c/Python27/python.exe script/bootstrap.py

LNK1181: cannot open input file ‘kernel32.lib’

32비트 Node.js를 다시 설치하세요.

Error: ENOENT, stat ‘C:\Users\USERNAME\AppData\Roaming\npm’

간단하게 해당 디렉터리를 생성하면 문제가 해결될 겁니다:

$ mkdir ~\AppData\Roaming\npm

node-gyp is not recognized as an internal or external command

Git Bash로 빌드 했을 때 이러한 에러가 발생할 수 있습니다. 반드시 PowerShell이나 VS2015 Command Prompt에서 빌드를 진행해야 합니다.


빌드 시스템 개요

Electron은 프로젝트 생성을 위해 gyp를 사용하며 ninja를 이용하여 빌드합니다. 프로젝트 설정은 .gyp.gypi 파일에서 볼 수 있습니다.

gyp 파일

Electron을 빌드 할 때 gyp 파일들은 다음과 같은 규칙을 따릅니다:

구성요소 빌드

Chromium은 꽤나 큰 프로젝트입니다. 이러한 이유로 인해 최종 링킹 작업은 상당한 시간이 소요될 수 있습니다. 보통 이런 문제는 개발을 어렵게 만듭니다. 우리는 이 문제를 해결하기 위해 Chromium의 “component build” 방식을 도입했습니다. 이는 각각의 컴포넌트를 각각 따로 분리하여 공유 라이브러리로 빌드 합니다. 하지만 이 빌드 방식을 사용하면 링킹 작업은 매우 빨라지지만 실행 파일 크기가 커지고 성능이 저하됩니다.

Electron도 이러한 방식에 상당히 비슷한 접근을 했습니다: Debug 빌드 시 바이너리는 공유 라이브러리 버전의 Chromium 컴포넌트를 사용함으로써 링크 속도를 높이고, Release 빌드 시 정적 라이브러리 버전의 컴포넌트를 사용합니다. 이렇게 각 빌드의 단점을 상호 보완하여 디버그 시 빌드 속도는 향상되고 배포판 빌드의 공유 라이브러리의 단점은 개선했습니다.

부트스트랩 최소화

Prebuilt된 모든 Chromium 바이너리들은 부트스트랩 스크립트가 실행될 때 다운로드됩니다. 기본적으로 공유 라이브러리와 정적 라이브러리 모두 다운로드되며 최종 전체 파일 크기는 플랫폼에 따라 800MB에서 2GB까지 차지합니다.

기본적으로 (libchromiumcontent)는 Amazon Web Service를 통해 다운로드 됩니다. 만약 LIBCHROMIUMCONTENT_MIRROR 환경 변수가 설정되어 있으면 부트스트랩은 해당 링크를 사용하여 바이너리를 다운로드 합니다. libchromiumcontent-qiniu-mirror는 libchromiumcontent의 미러입니다. 만약 AWS에 접근할 수 없다면 export LIBCHROMIUMCONTENT_MIRROR=http://7xk3d2.dl1.z0.glb.clouddn.com/ 미러를 통해 다운로드 할 수 있습니다.

만약 빠르게 Electron의 개발 또는 테스트만 하고 싶다면 --dev 플래그를 추가하여 공유 라이브러리만 다운로드할 수 있습니다:

$ ./script/bootstrap.py --dev
$ ./script/build.py -c D

두 절차에 따른 프로젝트 생성

Electron은 ReleaseDebug 빌드가 서로 다른 라이브러리 링크 방식을 사용합니다. 하지만 gyp는 따로 빌드 설정을 분리하여 라이브러리 링크 방식을 정의하는 방법을 지원하지 않습니다.

이 문제를 해결하기 위해 Electron은 링크 설정을 제어하는 gyp 변수 libchromiumcontent_component를 사용하고 gyp를 실행할 때 단 하나의 타겟만을 생성합니다.

타겟 이름

많은 프로젝트에서 타겟 이름을 ReleaseDebug를 사용하는데 반해 Electron은 RD를 대신 사용합니다. 이유는 가끔 알 수 없는 이유(randomly)로 ReleaseDebug 중 하나만 빌드 설정에 정의되어 있을때 gyp가 크래시를 일으키는데 이유는 앞서 말한 바와 같이 Electron은 한번에 한개의 타겟만을 생성할 수 있기 때문입니다.

이 문제는 개발자에게만 영향을 미칩니다. 만약 단순히 Electron을 rebranding 하기 위해 빌드 하는 것이라면 이 문제에 신경 쓸 필요가 없습니다.

테스트

변경사항이 프로젝트 코딩 스타일을 준수하는지 테스트하려면 다음 명령을 사용하세요:

$ npm run lint

기능을 테스트하려면 다음 명령을 사용하세요:

$ npm test

Electron 소스 코드를 변경할 때 마다, 테스트 전에 빌드를 다시 실행해야 합니다:

$ npm run build && npm test

모카의 전용 테스트 기능을 사용해서 특정 테스트 또는 블록을 분리하여 테스트 세트 실행을 빠르게 할 수 있습니다.describe 또는 it 함수 호출에 .only 만 붙이세요:

describe.only('some feature', function () {
  // ... 이 블록에서는 테스트만 실행될 것 입니다.
})

또는, 주어진 정규 표현 패턴에 일치하는 경우에만 테스트를 실행하기 위해 모카의 grep 을 사용할 수 있습니다:

$ npm test -- --grep child_process

테스트시 (runas 같은) 네이티브 모듈을 포함하면 디버그 빌드에서 실행할 수 없습니다. (자세한 것은 #2558 를 보세요). 그러나 릴리즈 빌드에서는 작동할 것 입니다.

릴리즈 빌드로 테스트를 실행하려면 다음 명령을 사용하세요:

$ npm test -- -R

C++ 코드에서 clang-format 사용하기

clang-format 은 C/C++/Objective-C 코드 자동 서식 맞춤 도구입니다. 그래서 개발자들은 코드 검토시에 스타일 문제에 대해 걱정할 필요가 없습니다.

풀 리퀘스트를 하기 전에 변경된 C++ 코드의 서식을 맞추는 것이 좋습니다. 이것은 당신과 검토자들의 시간을 절약해 줄 것입니다.

npm install -g clang-format 으로 clang-formatgit-clang-format 을 설치할 수 있습니다.

Electron C++ 코드 형식에 따라 자동 서식 맞춤을 하려면, 간단하게 clang-format -i path/to/electron/file.cc 를 실행하면 됩니다. 이것은 macOS/Linux/Windows 에서 작동합니다.

변경된 코드를 서식에 맞추는 작업 흐름:

  1. Electron 저장소의 코드를 변경합니다.
  2. git add your_changed_file.cc 를 실행합니다.
  3. git-clang-format 를 실행하면, your_changed_file.cc 에서 변경을 확인할 수 있습니다. 이 변경은 clang-format 에서 생성됩니다.
  4. git add your_changed_file.cc 를 실행하고, 변경사항을 커밋합니다.
  5. 이제 브랜치를 풀 리퀘스트 할 수 있습니다.

마지막 git 커밋 (HEAD) 의 변경된 내용의 서식을 맞추려면, git-clang-format HEAD~1 을 실행하면 됩니다. 자세한 내용은 git-clang-format -h 를 보세요.

편집기 통합

clang-format 을 당신이 선호하는 편집기에 통합할 수 있습니다. 편집기 통합을 설정하는 방법에 대한 자세한 지침은 다음 페이지를 참조하세요:


코딩 스타일

이 가이드는 Electron의 코딩 스타일에 관해 설명합니다.

npm run lint를 실행하여 cpplinteslint를 통해 어떤 코딩 스타일 이슈를 확인할 수 있습니다.

C++과 Python

C++과 Python 스크립트는 Chromium의 코딩 스타일을 따릅니다. 자동으로 C++ 코드 형식을 맞추기 위해 clang-format 을 사용할 수 있습니다. 파이선 스크립트 script/cpplint.py를 사용하여 모든 파일이 해당 코딩스타일에 맞게 코딩 했는지 확인할 수 있습니다.

Python 버전은 2.7을 사용합니다.

C++ 코드는 많은 Chromium의 추상화와 타입을 사용합니다. 따라서 Chromium 코드에 대해 잘 알고 있어야 합니다. 이와 관련하여 시작하기 좋은 장소로 Chromium의 Important Abstractions and Data Structures 문서가 있습니다. 이 문서에선 몇가지 특별한 타입과 스코프 타입(스코프 밖으로 나가면 자동으로 메모리에서 할당을 해제합니다. 스마트 포인터와 같습니다) 그리고 로깅 메커니즘 등을 언급하고 있습니다.

JavaScript

이름 짓기

Electron API는 Node.js와 비슷한 명명법을 사용합니다:

새로운 API를 만들 땐 jQuery의 one-function 스타일 대신 getter, setter스타일을 사용해야 합니다. 예를 들어 .text([text]) 대신 .getText().setText(text) 형식으로 함수를 설계하면 됩니다. 포럼에서 이 문제에 대한 논의가 진행되고 있습니다.


macOS 에서 디버깅하기

만약 작성한 Javascript 애플리케이션이 아닌 Electron 자체의 크래시나 문제를 경험하고 있다면, 네이티브/C++ 디버깅에 익숙하지 않은 개발자는 디버깅이 약간 까다로울 수 있습니다. 그렇다 해도, lldb, Electron 소스 코드가 중단점을 통해 순차적으로 쉽게 디버깅할 수 있느 환경을 제공합니다.

요구사항

Electron에 디버거 연결하고 디버깅하기

디버깅 작업을 시작하려면, Terminal 을 열고 디버그 빌드 상태의 Electron 을 전달하여 lldb 를 시작합니다.

$ lldb ./out/D/Electron.app
(lldb) target create "./out/D/Electron.app"
Current executable set to './out/D/Electron.app' (x86_64).

중단점 설정

LLDB 는 강력한 도구이며 코드 검사를 위한 다양한 전략을 제공합니다. 간단히 소개하자면, JavaScript 에서 올바르지 않은 명령을 호출한다고 가정합시다 - 당신은 명령의 C++ 부분에서 멈추길 원하며 그것은 Electron 소스 내에 있습니다.

관련 코드는 ./atom/ 에서 찾을 수 있으며 마찬가지로 Brightray 도 ./vendor/brightray/browser./vendor/brightray/common 에서 찾을 수 있습니다. 당신이 열정적이라면, Chromium 을 직접 디버깅할 수 있으며, chromium_src 에서 찾을 수 있습니다.

app.setName() 을 디버깅한다고 가정합시다, 이것은 browser.cc 에 Browser::SetName() 으로 정의되어있습니다. breakpoint 명령으로 멀추려는 파일과 줄을 명시하여 중단점을 설정합시다:

(lldb) breakpoint set --file browser.cc --line 117
Breakpoint 1: where = Electron Framework``atom::Browser::SetName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 20 at browser.cc:118, address = 0x000000000015fdb4

그리고 Electron 을 시작하세요:

(lldb) run

Electron 이 시작시에 앱의 이름을 설정하기때문에, 앱은 즉시 중지됩니다:

(lldb) run
Process 25244 launched: '/Users/fr/Code/electron/out/D/Electron.app/Contents/MacOS/Electron' (x86_64)
Process 25244 stopped
* thread #1: tid = 0x839a4c, 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118
   115 	}
   116
   117 	void Browser::SetName(const std::string& name) {
-> 118 	  name_override_ = name;
   119 	}
   120
   121 	int Browser::GetBadgeCount() {
(lldb)

현재 매개변수와 지역 변수를 보기위해, frame variable (또는 fr v) 를 실행하면, 현재 앱 이름이 “Electron” 인 것을 불 수 있습니다.

(lldb) frame variable
(atom::Browser *) this = 0x0000000108b14f20
(const string &) name = "Electron": {
    [...]
}

현재 선택된 쓰레드에서 소스 수준 한단계를 실행하기위해, step (또는 s) 를 실행하세요. name_override_.empty() 로 들어가게 됩니다. 스텝 오버 실행은, next (또는 n) 을 실행하세요.

(lldb) step
Process 25244 stopped
* thread #1: tid = 0x839a4c, 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119, queue = 'com.apple.main-thread', stop reason = step in
    frame #0: 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119
   116
   117 	void Browser::SetName(const std::string& name) {
   118 	  name_override_ = name;
-> 119 	}
   120
   121 	int Browser::GetBadgeCount() {
   122 	  return badge_count_;

디버깅을 끝내려면, process continue 를 실행하세요. 또한 쓰레드에서 실행 줄 수를 지정할 수 있습니다 (thread until 100). 이 명령은 현재 프레임에서 100 줄에 도달하거나 현재 프레임을 나가려고 할 때 까지 쓰레드를 실행합니다.

이제, Electron 의 개발자 도구를 열고 setName 을 호출하면, 다시 중단점을 만날 것 입니다.

더 읽을거리

LLDB 는 훌륭한 문서가 있는 강력한 도구입니다. 더 학습하기 위해, LLDB 명령 구조 참고LLDB 를 독립 실행 디버거로 사용하기 같은 애플의 디버깅 문서를 고려하세요.

LLDB 의 환상적인 설명서와 학습서 를 확인할 수 있습니다. 그것은 더 복잡한 디버깅 시나리오를 설명합니다.


Windows에서 Electron 디버깅하기

만약 작성한 Javascript 애플리케이션이 아닌 Electron 자체의 크래시나 문제를 경험하고 있다면, 네이티브/C++ 디버깅에 익숙하지 않은 개발자는 디버깅이 약간 까다로울 수 있습니다. 그렇다 해도, Visual Studio, GitHub의 Electron이 호스팅하는 심볼 서버, Electron 소스 코드가 중단점을 통해 순차적으로 쉽게 디버깅할 수 있는 환경을 제공합니다.

요구 사항

Electron에 디버거 연결하고 디버깅하기

디버깅 작업을 시작하려면, PowerShell/CMD 중 한 가지를 열고 디버그 빌드 상태의 Electron에 인수로 애플리케이션을 전달하여 실행합니다:

$ ./out/D/electron.exe ~/my-electron-app/

중단점 설정

그리고, Visual Studio를 엽니다. Electron은 Visual Studio로 만들어지지 않았으며 이러한 이유로 인해 프로젝트 파일을 가지고 있지 않습니다. 하지만 “파일로 열기”를 통해 소스 코드 파일들을 열 수 있습니다. Visual Studio가 각각의 파일을 따로 연다는 것입니다. 여전히 중단점을 설정할 수 있습니다. Visual Studio는 현재 소스 코드와 일치하는 작동 중인 프로세스와 중단점을 자동으로 찾아냅니다.

관련된 코드 파일들은 ./atom/에서 찾을 수 있으며 또한 Brightray 안 ./vendor/brightray/browser./vendor/brightray/common에서도 찾을 수 있습니다. 만약 하드코어를 좋아한다면, Chromium을 직접 디버깅할 수도 있습니다. 확실히 chromium_src 안에서 찾을 수 있습니다.

디버거 연결

로컬에서 작동 중인 프로세스 또는 원격 컴퓨터에 Visual Studio 디버거를 적용시킬 수 있습니다. 프로세스의 실행이 끝난 후, 디버그 / 프로세스에 연결을 (또는 Ctrl+Alt+P 입력) 클릭하면 “프로세스에 연결” 대화 상자가 열립니다. 이 도구를 통해 로컬 또는 원격에서 작동 중인 애플리케이션을 디버깅할 수 있으며 여러 프로세스를 동시에 디버깅할 수도 있습니다.

만약 Electron이 서로 다른 유저 계정에서 실행 중이라면, 모든 사용자의 프로세스 보이기를 선택하면 됩니다. 참고로 이는 BrowserWindow가 열린 개수에 따라 달라질 수 있으며 아마 다수의 프로세스를 발견할 수 있을 것입니다. 전형적인 one-window 애플리케이션은 Visual Studio에서 두 개의 Electron.exe 항목으로 표시됩니다. 하나는 메인 프로세스이며 다른 하나는 렌더러 프로세스입니다. 리스트는 단지 이름 하나만 제공하기 때문에 현재까지는 다른 적절한 프로세스 판별법이 없습니다.

어떤 프로세스에 디버거를 적용해야 하나요?

코드는 메인 프로세스 내에서 실행되며 (이는 코드를 안에서 찾을 수 있거나, 결국 메인 Javascript 파일에 의해 실행) remote (require('electron').remote)를 사용하여 코드를 실행하는 것 또한 메인 프로세스 내에서 실행됩니다. 다른 코드는 각각의 렌더러 프로세스 내에서 실행됩니다.

디버깅할 때 여러 프로그램에 디버거를 적용할 수 있지만, 언제나 한 개의 프로그램만 디버거에서 활성화되어야 합니다. 디버그 경로 툴바 또는 프로세스 창에서 활성화 프로그램을 설정할 수 있습니다.

프로세스를 관찰하기 위해 ProcMon 사용

Visual Studio는 특정 코드 경로를 탐색하는것에 대해 환상적인 기능을 제공하고 ProcMon은 애플리케이션이 운영체제와 하는 일의 모든 것을 관찰하는데 강력한 기능을 가지고 있습니다. 이 툴은 프로세스의 파일, 레지스트리, 네트워킹, 프로세스, 프로파일링 상세를 포착할 수 있으며 강력하게 모든 이벤트의 발생을 로깅을 시도합니다. 만약 애플리케이션이 운영체제에 대해 무슨 일을 하고 있는지 이해하고 싶다면 이는 좋은 자원이 될 것입니다.

ProcMon의 기본적인 디버깅 기능을 알아보고 싶다면 Microsoft에서 제공하는 동영상 강좌를 참고하세요.


디버거에서 디버그 심볼 서버 설정

디버그 심볼은 디버깅 세션을 더 좋게 개선해 줍니다. 디버그 심볼은 실행 파일과 동적 링크 라이브러리에서 메서드에 대한 정보를 담고 있으며 명료한 함수 호출 스텍 정보를 제공합니다. 심볼 서버는 유저가 크기가 큰 디버깅용 파일을 필수적으로 다운로드 받지 않고도 디버거가 알맞은 심볼, 바이너리 그리고 소스를 자동적으로 로드할 수 있도��� 해줍니다. 서버 사용법은 Microsoft의 심볼 서버와 비슷합니다. 사용법을 알아보려면 이 문서를 참조하세요.

참고로 릴리즈된 Electron 빌드는 자체적으로 많은 최적화가 되어 있는 관계로 경우에 따라 디버깅이 쉽지 않을 수 있습니다. Inlining, tail call 등 컴파일러 최적화에 의해 디버거가 모든 변수의 콘텐츠를 보여줄 수 없는 경우도 있고 실행 경로가 이상하게 보여지는 경우도 있습니다. 유일한 해결 방법은 최적화되지 않은 로컬 빌드를 하는 것입니다.

공식적인 Electron의 심볼 서버의 URL은 http://54.249.141.255:8086/atom-shell/symbols 입니다. 일단 이 URL에 직접적으로 접근할 수는 없습니다: 디버깅 툴에 심볼의 경로를 추가해야 합니다. 아래의 예시를 참고하면 로컬 캐시 디렉터리는 서버로부터 중복되지 않게 PDB를 가져오는데 사용됩니다. c:\code\symbols 캐시 디렉터리를 사용중인 OS에 맞춰 적당한 경로로 변경하세요.

Windbg에서 심볼 서버 사용하기

Windbg 심볼 경로는 구분자와 * 문자로 설정되어 있습니다. Electron 심볼 서버만 사용하려면 심볼 경로의 엔트리를 추가해야 합니다. (참고: c:\code\symbols 디렉터리 경로를 PC가 원하는 경로로 수정할 수 있습니다):

SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols

Windbg 메뉴 또는 .sympath 커맨드를 이용하여 환경에 _NT_SYMBOL_PATH 문자열을 설정합니다. 만약 Microsoft의 심볼서버로부터 심볼을 받아오려면 다음과 같이 리스팅을 먼저해야 합니다:

SRV*c:\code\symbols\*http://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols

Visual Studio에서 심볼 서버 사용하기

문제 해결: Symbols will not load

Windbg에서 다음의 커맨드를 입력하여 왜 심볼이 로드되지 않았는지에 대한 오류 내역을 출력합니다:

> !sym noisy
> .reload /f electron.exe

소스 코드 디렉터리 구조

Electron의 소스 코드는 몇 개의 파트로 분리되어 있습니다. 그리고 Chromium의 분리 규칙(separation conventions)을 주로 따르고 있습니다.

이미 Chromium의 멀티 프로세스 아키텍쳐에 익숙해져 있다면 소스 코드를 이해하기 쉬울 것입니다.

소스 코드 구조

Electron
├── atom/ - C++ 소스 코드.
|   ├── app/ - 시스템 엔트리 코드.
|   ├── browser/ - 주 윈도우를 포함한 프론트엔드, UI, 그리고 메인 프로세스에 관련된
|   |   코드와 렌더러 및 웹 페이지 관리 관련 코드.
|   |   ├── ui/ - 서로 다른 플랫폼에 대한 UI 관련 구현 코드.
|   |   |   ├── cocoa/ - Cocoa 특정 소스 코드.
|   |   |   ├── win/ - Windows GUI 특정 소스 코드.
|   |   |   └── x/ - X11 특정 소스 코드.
|   |   ├── api/ - 메인 프로세스 API의 구현.
|   |   ├── net/ - 네트워킹 관련 코드.
|   |   ├── mac/ - Mac 특정 Objective-C 소스 코드.
|   |   └── resources/ - 아이콘들, 플랫폼 의존성 파일들, 기타 등등..
|   ├── renderer/ - 렌더러 프로세스에서 작동하는 코드.
|   |   └── api/ - 렌더러 프로세스 API의 구현.
|   └── common/ - 메인과 렌더러 프로세스에서 모두 사용하는 코드, 몇가지 유틸리티
|       함수들이 포함되어 있고 node의 메시지 루프와 Chromium의 메시지 루프를 통합.
|       └── api/ - 공통 API 구현들, 기초 Electron 빌트-인 모듈들.
├── chromium_src/ - Chromium에서 복사하여 가져온 소스 코드.
├── default_app/ - Electron에 앱이 제공되지 않았을 때 보여지는 기본 페이지.
├── docs/ - 참조 문서.
├── lib/ - JavaScript 소스 코드.
|   ├── browser/ - Javascript 메인 프로세스 초기화 코드.
|   |   └── api/ - Javascript API 구현 코드.
|   ├── common/ - 메인과 렌더러 프로세스에서 모두 사용하는 JavaScript
|   |   └── api/ - Javascript API 구현 코드.
|   └── renderer/ - Javascript 렌더러 프로세스 초기화 코드.
|       └── api/ - Javascript API 구현 코드.
├── spec/ - 자동화 테스트.
├── electron.gyp - Electron의 빌드 규칙.
└── common.gypi - 컴파일러 설정 및 `node` 와 `breakpad` 등의 구성요소를 위한 빌드
    규칙.

그외 디렉터리 구조

Git 서브 모듈 최신 버전으로 유지

Electron 저장소는 몇 가지 외부 벤더 의존성을 가지고 있으며 /vendor 디렉터리에서 확인할 수 있습니다. 때때로 git status를 실행했을 때 아마 다음과 같은 메시지를 흔히 목격할 것입니다:

$ git status

	modified:   vendor/brightray (new commits)
	modified:   vendor/node (new commits)

이 외부 의존성 모듈들을 업데이트 하려면, 다음 커맨드를 실행합니다:

git submodule update --init --recursive

만약 자기 자신이 너무 이 커맨드를 자주 사용하는 것 같다면, ~/.gitconfig 파일을 생성하여 편하게 업데이트할 수 있습니다:

[alias]
	su = submodule update --init --recursive

Electron FAQ

언제 Electron이 최신 버전의 Chrome으로 업그레이드 되나요?

Electron의 Chrome 버전은 보통 새로운 Chrome 안정 버전이 릴리즈 된 이후 1주 내지 2주 내로 업데이트됩니다. 하지만 이러한 업데이트 주기는 보장되지 않으며 업그레이드에 필요한 작업의 양에 따라 달라집니다.

Electron은 크롬이 사용하는 안정된 채널만을 이용합니다, 만약 중요한 수정이 베타 또는 개발 채널에 패치된 경우, 이전 버전의 채널로 롤백합니다.

자세한 내용은 tutorial/security을 참고하세요.

Electron은 언제 최신 버전의 Node.js로 업그레이드 하나요?

새로운 버전의 Node.js가 릴리즈 되면, 보통 Electron을 업그레이드 하기 전에 한 달 정도 대기합니다. 이렇게 하면 새로운 Node.js 버전을 업데이트 함으로써 발생하는 버그들을 피할 수 있기 때문입니다. 이러한 상황은 자주 발생합니다.

Node.js의 새로운 기능은 보통 V8 업그레이드에서 가져옵니다. Electron은 Chrome 브라우저에 탑재된 V8을 사용하고 있습니다. 눈부신 새로운 Node.js 버전의 자바스크립트 기능은 보통 이미 Electron에 있습니다.

어떻게 웹 페이지 간에 데이터를 공유할 수 있나요?

두 웹페이지 간에 (렌더러 프로세스) 데이터를 공유하려면 간단히 이미 모든 브라우저에서 사용할 수 있는 HTML5 API들을 사용하면 됩니다. 가장 좋은 후보는 Storage API, localStorage, sessionStorage, 그리고 IndexedDB가 있습니다.

또는 Electron에서만 사용할 수 있는 IPC 시스템을 사용하여 메인 프로세스의 global 변수에 데이터를 저장한 후 다음과 같이 렌더러 프로세스에서 electron 모듈의 remote 속성을 통하여 접근할 수 있습니다:

// 메인 프로세스에서
global.sharedObject = {
  someProperty: 'default value'
}
// 첫 번째 페이지에서
require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'
// 두 번째 페이지에서
console.log(require('electron').remote.getGlobal('sharedObject').someProperty)

제작한 애플리케이션의 윈도우/트레이가 몇 분 후에나 나타납니다.

이러한 문제가 발생하는 이유는 보통 윈도우/트레이를 담은 변수에 가비지 컬렉션이 작동해서 그럴 가능성이 높습니다.

이러한 문제를 맞닥뜨린 경우 다음 문서를 읽어보는 것이 좋습니다:

만약 빠르게 고치고 싶다면, 다음과 같이 변수를 전역 변수로 만드는 방법이 있습니다:

app.on('ready', () => {
  const tray = new Tray('/path/to/icon.png')
})

를 이렇게:

let tray = null
app.on('ready', () => {
  tray = new Tray('/path/to/icon.png')
})

Electron에서 jQuery/RequireJS/Meteor/AngularJS를 사용할 수 없습니다.

Node.js가 Electron에 합쳐졌기 때문에, DOM에 module, exports, require 같은 몇 가지 심볼들이 추가됬습니다. 따라서 같은 이름의 심볼을 사용하는 몇몇 라이브러리들과 충돌이 발생할 수 있습니다.

이러한 문제를 해결하려면, Electron에서 node 포함을 비활성화시켜야 합니다:

// 메인 프로세스에서.
let win = new BrowserWindow({
  webPreferences: {
    nodeIntegration: false
  }
})

하지만 Node.js의 기능과 Electron API를 유지하고 싶다면 페이지에 다른 라이브러리를 추가하기 전에 심볼들의 이름을 변경해야 합니다:

<head>
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script type="text/javascript" src="jquery.js"></script>
</head>

require('electron').xxx가 undefined를 반환합니다.

Electron의 빌트인 모듈을 사용할 때, 다음과 같은 오류가 발생할 수 있습니다:

> require('electron').webFrame.setZoomFactor(1.0);
Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined

이러한 문제가 발생하는 이유는 npm의 electron 모듈이 로컬 또는 전역 중 한 곳에 설치되어, Electron의 빌트인 모듈을 덮어씌우는 바람에 빌트인 모듈을 사용할 수 없기 때문입니다.

올바른 빌트인 모듈을 사용하고 있는지 확인하고 싶다면, electron 모듈의 경로를 출력하는 방법이 있습니다:

console.log(require.resolve('electron'))

그리고 다음과 같은 경로를 가지는지 점검하면 됩니다:

"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js"

하지만 node_modules/electron/index.js와 같은 경로로 되어있을 경우, electron 모듈을 지우거나 이름을 바꿔야만 합니다.

npm uninstall electron
npm uninstall -g electron

그런데 여전히 빌트인 모듈이 계속해서 문제를 발생시키는 경우, 아마 모듈을 잘못 사용하고 있을 가능성이 큽니다. 예를 들면 electron.app은 메인 프로세스에서만 사용할 수 있는 모듈이며, 반면 electron.webFrame 모듈은 렌더러 프로세스에서만 사용할 수 있는 모듈입니다.


Electron 에 대하여

Electron 은 HTML, CSS 와 Javascript 로 크로스플랫폼 데스크톱 애플리케이션을 위해 Github 에서 개발한 오픈소스 라이브러리 입니다. Electron 은 ChromiumNode.js 를 단일 실행으로 합치고 앱을 Mac, Windows 와 Linux 용으로 패키지화 할 수 있게 함으로써 이것을 가능하게 합니다.

Electron 은 2013년에 Github 의 해킹 가능한 텍스트 편집기 Atom 의 프레임워크로 시작하였습니다. 이 둘은 2014년에 오픈소스화 됩니다.

그후로 오픈소스 개발자, 스타트업과 안정된 회사에서 인기있는 도구가 되었습니다. Electron 을 사용하는 곳을 보세요.

Electron 의 기여자와 릴리즈에 대한 자세한 내용이나 개발을 시작하려면 Quick Start Guide 를 읽어보세요.

코어 팀과 기여자

Electron 은 Gihub 의 팀과 커뮤니티에서 활동중인 기여자 그룹에 의해 유지됩니다. 일부 기여자는 개인이고, 일부는 Electron 으로 개발을 하는 큰 회사입니다. 프로젝트에 자주 공여하는 분은 기꺼이 메인테이너로 추가하겠습니다. Electron 에 기여하기를 참고하세요.

출시

Electron 은 빈번하게 출시 됩니다. 중요한 버그 수정, 새 API 추가 또는 Chromium 이나 Node.js 의 업데이트시에 출시합니다.

업데이트 의존성

Electron 의 Chromium 버전은 보통 새 버전 출시 이후 1~2 주 후에 업데이트 하는데, 이는 업그레이드에 필요한 작업의 양에 따라 달라집니다.

Node.js 의 새버전이 출시되면, Electron 은 더 안정된 버전을 가져오기 위해 약 한달정도 기다립니다.

Electron 에서, Node.js 와 Chromium 은 단일 V8 인스턴스를 공유합니다–보통 Chromium 이 사용하는 버전. 대부분은 동작하지만 가끔 Node.js 를 패치해야 합니다.

버전 관리

Node.js 와 Chromium 에 대한 의존성이 강해서, Electron 은 버전관리가 까다롭고 semver을 따르지 않습니다. 그러므로 항상 Electron 의 특정 버전을 참조해야 합니다. [Electron 의 버전관리] (http://electron.atom.io/docs/tutorial/electron-versioning/)를 읽거나 현재 쓰이는 버전을 보세요.

LTS

현재 Electron 의 구버전에 대한 장기 지원은 없습니다. Electron 현재 버전이 잘 동작한다면, 그것을 원하는 만큼 유지하세요. 새로운 기능들을 사용하려면 새버전으로 업그레이드 해야합니다.

주 버전은 v1.0.0 입니다. 아직 이 버전을 사용중이지 않다면, v1.0.0 변화에 대해 읽어보세요.

중심 철학

Electron 을 작고 (파일 크기) 지속가능하게 (의존성 및 API 의 확산) 할 목적으로 중심 프로젝트의 범위를 제한합니다.

예를 들어, Electron 은 Chromium 전체가 아닌 렌더링 라이브러리만 사용합니다. 이것은 Chromium 업그레이드를 쉽게 하지만 Google Chrome 에서 볼 수 있는 몇몇 브라우저 기능이 Electron 에서는 빠집니다.

Electron 에 추가된 새로운 기능은 주로 네이티브 API 입니다. 기능은 가능한한 Node.js 모듈로 해야합니다. [커뮤니티에 의해 개발된 Electron 도구들] (http://electron.atom.io/community)을 보세요.

이력

다음은 Electron 이력의 주요 시점입니다.

:calendar: :tada:
2013년 4월 Atom Shell 탄생.
2014년 5월 Atom Shell 오픈소스화.
2015년 4월 Electron 으로 개명.
2016년 5월 Electron v1.0.0 출시.
2016년 5월 Electron 앱이 Mac App Store 와 호환.
2016년 8월 Windows Store 의 Electron 앱 지원.

접근성

접근 가능한 애플리케이션을 만드는 것은 중요합니다. 우리는 새 기능 DevtronSpectron 을 소개할 수 있어 기쁩니다. 이것들은 개발자가 모두에게 더 좋은 앱을 만들 수 있는 기회를 제공합니다.


Electron 애플리케이션의 접근성에 대한 관심은 두 웹사이트가 유사하며 궁극적으로 HTML 입니다. 그러나 검사를 위한 URL 이 없기 때문에 Electron 앱에서 접근성 검사에 온라인 자원을 사용할 수 없습니다.

이 새 기능들은 Electron 앱에 검사 도구를 제공합니다. Spectron 으로 테스트 하기 위한 검사를 추가 하거나 Devtron 으로 개발자 도구의 것을 사용할 수 있습니다. 자세한 정보는 도구의 요약이나 접근성 문서 를 읽어보세요.

Spectron

테스트 프레임워크 Spectron 을 통해 애플리케이션의 각 창과 <webview> 태그를 검사할 수 있습니다. 예시입니다:

app.client.auditAccessibility().then(function (audit) {
  if (audit.failed) {
    console.error(audit.message)
  }
})

이 기능에 대한 자세한 내용은 Spectron 의 문서 를 참고하세요.

Devtron

Devtron 에서 앱의 페이지를 검사할 수 있는 접근성 탭이 생겼으며, 결과를 정렬하고 필터할 수 있습니다.

devtron screenshot

이 두 도구들은 구글이 크롬을 위해 개발한 접근성 개발자 도구 라이브러리를 사용합니다. 이 라이브러리에서 사용한 접근성 검사 규칙은 저장소의 위키를 통해 더 알아볼 수 있습니다.

Electron 을 위한 다른 훌륭한 접근성 도구를 알고계시다면, 접근성 문서 에 풀 요청과 함께 추가해 주세요.


애플리케이션 배포

Electron 애플리케이션을 배포하는 방법은 간단합니다.

먼저 폴더 이름을 app로 지정한 후 Electron 리소스 디렉터리에 폴더를 통째로 집어넣기만 하면 됩니다. 리소스 디렉터리는 macOS의 경우: Electron.app/Contents/Resources/ Windows와 Linux의 경우: resources/ 입니다.

macOS의 경우:

electron/Electron.app/Contents/Resources/app/
├── package.json
├── main.js
└── index.html

Windows와 Linux의 경우:

electron/resources/app
├── package.json
├── main.js
└── index.html

그리고 Electron.app을 실행하면(Linux에선 electron Windows에선 electron.exe 입니다) Electron 앱이 실행됩니다. 최종 사용자에겐 이 electron 폴더(Electron.app)를 배포하면 됩니다.

asar로 앱 패키징 하기

소스파일 전체를 복사해서 배포하는 것과는 별개로 asar 아카이브를 통해 애플리케이션의 소스 코드가 사용자에게 노출되는 것을 방지할 수 있습니다.

asar 아카이브를 사용할 땐 단순히 app 폴더 대신에 애플리케이션을 패키징한 app.asar 파일로 대체하면됩니다. Electron은 자동으로 app폴더 대신 asar 아카이브를 기반으로 애플리케이션을 실행합니다.

macOS의 경우:

electron/Electron.app/Contents/Resources/
└── app.asar

Windows 와 Linux의 경우:

electron/resources/
└── app.asar

자세한 내용은 애플리케이션 패키징에서 찾아볼 수 있습니다.

다운로드한 바이너리의 리소스를 앱에 맞게 수정하기

애플리케이션을 Electron에 번들링한 후 해당 애플리케이션에 맞게 리브랜딩 할 수 있습니다.

Windows

rcedit를 통해 electron.exe을 원하는 이름으로 변경할 수 있고, 또한 아이콘과 기타 정보도 변경할 수 있습니다.

macOS

Electron.app을 원하는 이름으로 변경할 수 있습니다. 그리고 다음 표시된 애플리케이션 내부 파일에서 CFBundleDisplayName, CFBundleIdentifier 그리고 CFBundleName 필드를 원하는 이름으로 변경해야 합니다:

또한 helper 앱이 프로세스 모니터에 Electron Helper로 나오지 않도록 이름을 변경할 수 있습니다. 하지만 반드시 내부 및 모든 helper 앱의 이름을 변경해야 합니다.

애플리케이션 아이콘은 Electron.app/Contents/Resources/atom.icns을 원하는 아이콘으로 변경하면 됩니다.

애플리케이션 이름을 원하는 이름으로 변경한 예시:

MyApp.app/Contents
├── Info.plist
├── MacOS/
│   └── MyApp
└── Frameworks/
    ├── MyApp Helper EH.app
    |   ├── Info.plist
    |   └── MacOS/
    |       └── MyApp Helper EH
    ├── MyApp Helper NP.app
    |   ├── Info.plist
    |   └── MacOS/
    |       └── MyApp Helper NP
    └── MyApp Helper.app
        ├── Info.plist
        └── MacOS/
            └── MyApp Helper

Linux

실행파일 electron의 이름을 원하는 대로 바꿀 수 있습니다. 리눅스 애플리케이션의 아이콘은 .desktop 파일을 사용하여 지정할 수 있습니다.

패키징 툴

애플리케이션을 일일이 수동으로 패키지로 만드는 대신, 서드 파티 패키징 툴을 사용하며 이러한 작업을 자동화 시킬 수 있습니다:

Electron 소스 코드를 다시 빌드하여 리소스 수정하기

또한 Electron 소스 코드를 다시 빌드할 때 애플리케이션 이름을 변경할 수 있습니다.

atom.gyp 파일을 수정하여 다음과 같이 다시 빌드할 수 있습니다:

grunt-build-atom-shell

Electron의 소스 코드를 수정하고 다시 빌드하는 작업은 상당히 복잡합니다. 일일이 소스 코드를 수정하는 대신 grunt-build-atom-shell을 사용하여 빌드를 자동화 시킬 수 있습니다.

이 툴을 사용하면 자동으로 .gyp파일을 수정하고 다시 빌드합니다. 그리고 애플리케이션의 네이티브 Node 모듈 또한 새로운 실행파일 이름으로 일치시킵니다.

Electron 커스텀 포크 만들기

Electron의 커스텀 포크를 만드는 것은 거의 확실히 앱을 만드는데 있어서 필요한 작업이 아닐 수 있으며, 심지어 “제품 등급”의 애플리케이션이라도 필요하지 않습니다. electron-packager 또는 electron-builder와 같은 도구를 사용하면 다른 특별한 과정 없이 Electron을 “Rebrand” 할 수 있습니다.

업스트림 단에서 추가될 수 없는 기능이나 이미 공식 버전에서 거부된 기능을 Electron에 직접적으로 패치하기 위해 커스텀 C++를 추가해야 한다면 Electron을 포크해야 합니다. Electron의 개발자로써, Electron을 매우 많은 시나리오에서도 작동하도록 만들려고 합니다. 따라서 가능한한 변경 사항을 공식 버전의 Electron에 추가할 수 있도록 시도해 주길 바라며, 당신에겐 아주 아주 쉬운 작업일 것이고 이러한 당신의 도움에 대해 감사하게 생각합니다.

surf-build와 함께 커스텀 릴리즈 만들기

  1. npm을 통해 Surf를 설치합니다: npm install -g surf-build@latest

  2. 새로운 S3 bucket을 만들고 다음과 같은 빈 디렉토리 구조를 만듭니다:

- atom-shell/
  - symbols/
  - dist/
  1. 다음의 환경 변수들을 설정합니다:
  1. Electron에 기여를 하는 기여자라면, 반드시 script/upload.py에서 포크를 위해 ELECTRON_REPO를 설정해야 합니다. (MYORG/electron)

  2. surf-build -r https://github.com/MYORG/electron -s YOUR_COMMIT -n 'surf-PLATFORM-ARCH'

  3. 빌드가 완료될 때까지 아주 아주 긴 시간을 기다립니다.


애플리케이션 패키징

Windows에서 일어나는 긴 경로 이름에 대한 issues를 완화하고 require 속도를 약간 빠르게 하며 애플리케이션의 리소스와 소스 코드를 좋지 않은 사용자로부터 보호하기 위해 애플리케이션을 asar 아카이브로 패키징 할 수 있습니다.

asar 아카이브 생성

asar 아카이브는 tar과 비슷한 포맷으로 모든 리소스를 하나의 파일로 만듭니다. 그리고 Electron은 압축해제 없이 임의로 모든 파일을 읽어들일 수 있습니다.

간단한 작업을 통해 애플리케이션을 asar 아카이브로 압축할 수 있습니다:

1. asar 유틸리티 설치

$ npm install -g asar

2. asar pack 커맨드로 앱 패키징

$ asar pack your-app app.asar

asar 아카이브 사용하기

Electron은 Node.js로부터 제공된 Node API와 Chromium으로부터 제공된 Web API 두 가지 API를 가지고 있습니다. 따라서 asar 아카이브는 두 API 모두 사용할 수 있도록 지원합니다.

Node API

Electron에선 fs.readFilerequire 같은 Node API들을 지원하기 위해 asar 아카이브가 가상의 디렉터리 구조를 가지도록 패치했습니다. 그래서 아카이브 내부 리소스들을 정상적인 파일 시스템처럼 접근할 수 있습니다.

예를 들어 /path/to라는 경로에 example.asar라는 아카이브가 있다고 가정하면:

$ asar list /path/to/example.asar
/app.js
/file.txt
/dir/module.js
/static/index.html
/static/main.css
/static/jquery.min.js

asar 아카이브에선 다음과 같이 파일을 읽을 수 있습니다:

const fs = require('fs')
fs.readFileSync('/path/to/example.asar/file.txt')

아카이브 내의 루트 디렉터리를 리스팅합니다:

const fs = require('fs')
fs.readdirSync('/path/to/example.asar')

아카이브 안의 모듈 사용하기:

require('/path/to/example.asar/dir/module.js')

BrowserWindow 클래스를 이용해 원하는 웹 페이지도 표시할 수 있습니다:

const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('file:///path/to/example.asar/static/index.html')

Web API

웹 페이지 내에선 아카이브 내의 파일을 file: 프로토콜을 사용하여 요청할 수 있습니다. 이 또한 Node API와 같이 가상 디렉터리 구조를 가집니다.

예를 들어 jQuery의 $.get을 사용하여 파일을 가져올 수 있습니다:

<script>
let $ = require('./jquery.min.js')
$.get('file:///path/to/example.asar/file.txt', (data) => {
  console.log(data)
})
</script>

asar 아카이브를 일반 파일로 취급하기

asar 아카이브의 체크섬(checksum)을 검사하는 작업등을 하기 위해선 asar 아카이브를 파일 그대로 읽어야 합니다. 이러한 작업을 하기 위해 original-fs 빌트인 모듈을 fs 모듈 대신에 사용할 수 있습니다. 이 모듈은 asar 지원이 빠져있습니다. 즉 파일 그대로를 읽어들입니다:

const originalFs = require('original-fs')
originalFs.readFileSync('/path/to/example.asar')

또한 process.noAsartrue로 지정하면 fs 모듈의 asar 지원을 비활성화 시킬 수 있습니다.

process.noAsar = true
fs.readFileSync('/path/to/example.asar')

Node API의 한계

asar 아카이브를 Node API가 최대한 디렉터리 구조로 작동하도록 노력해왔지만 여전히 저수준(low-level nature) Node API 때문에 한계가 있습니다.

아카이브는 읽기 전용입니다

아카이브는 수정할 수 없으며 기본적으로는 Node API로 파일을 수정할 수 있지만 asar 아카이브에선 작동하지 않습니다.

아카이브 안의 디렉터리를 작업 경로로 설정하면 안됩니다

asar 아카이브는 디렉터리처럼 사용할 수 있도록 구현되었지만 그것은 실제 파일시스템의 디렉터리가 아닌 가상의 디렉터리입니다. 그런 이유로 몇몇 API에서 지원하는 cwd 옵션을 asar 아카이브 안의 디렉터리 경로로 지정하면 나중에 문제가 발생할 수 있습니다.

특정 API로 인한 예외적인 아카이브 압축 해제

많은 fs API가 asar 아카이브의 압축을 해제하지 않고 바로 아카이브를 읽거나 정보를 가져올 수 있으나 몇몇 API는 시스템의 실제 파일의 경로를 기반으로 작동하므로 Electron은 API가 원할하게 작동할 수 있도록 임시 경로에 해당되는 파일의 압축을 해제합니다. 이 작업은 약간의 오버헤드를 불러 일으킬 수 있습니다.

위 예외에 해당하는 API 메서드는 다음과 같습니다:

fs.stat의 모조된(예측) 스테이터스 정보

fs.stat 로부터 반환되는 Stats 객체와 비슷한 API들은 asar 아카이브를 타겟으로 할 경우 예측된 디렉터리 파일 정보를 가집니다. 왜냐하면 아카이브의 디렉터리 경로는 실제 파일 시스템에 존재하지 않기 때문입니다. 그러한 이유로 파일 크기와 파일 타입 등을 확인할 때 Stats 객체를 신뢰해선 안됩니다.

asar 아카이브 내부의 바이너리 실행

Node API에는 child_process.exec, child_process.spawn 그리고 child_process.execFile와 같은 바이너리를 실행시킬 수 있는 API가 있습니다. 하지만 asar 아카이브 내에선 execFile API만 사용할 수 있습니다.

이 한계가 존재하는 이유는 execspawnfile 대신 command를 인수로 허용하고 있고 command는 shell에서 작동하기 때문입니다. Electron은 어떤 커맨드가 asar 아카이브 내의 파일을 사용하는지 결정하는데 적절한 방법을 가지고 있지 않으며, 심지어 그게 가능하다고 해도 부작용 없이 명령 경로를 대체할 수 있는지에 대해 확실히 알 수 있는 방법이 없습니다.

asar 아카이브에 미리 압축 해제된 파일 추가하기

전술한 바와 같이 몇몇 Node API는 호출 시 해당 파일을 임시폴더에 압축을 해제합니다. 이 방법은 성능문제가 발생할 수 있습니다. 그리고 설계상 백신 소프트웨어에서 잘못 진단하여 바이러스로 진단 할 수도 있습니다.

이 문제를 해결하려면 --unpack 옵션을 통해 파일을 압축이 풀려진 상태로 유지해야 합니다. 다음의 예시는 node 네이티브 모듈의 공유 라이브러리를 압축이 풀려진 상태로 유지합니다:

$ asar pack app app.asar --unpack *.node

커맨드를 실행한 후 같은 디렉터리에 app.asar 파일 외에 app.asar.unpacked 폴더가 같이 생성됩니다. 이 폴더안에 unpack 옵션에서 설정한 파일들이 압축이 풀려진 상태로 포함되어 있습니다. 사용자에게 애플리케이션을 배포할 때 반드시 해당 폴더도 같이 배포해야 합니다.


VSCode 에서 메인 프로세스 디버깅하기

1. VS Code 에서 Electron 프로젝트 열기.

$ git clone git@github.com:electron/electron-quick-start.git
$ code electron-quick-start

2. 다음 설정으로 .vscode/launch.json 파일 추가하기:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug Main Process",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceRoot}",
      "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
      "program": "${workspaceRoot}/main.js"
    }
  ]
}

참고: 윈도우에서, runtimeExecutable 을 위해 "${workspaceRoot}/node_modules/.bin/electron.cmd" 를 사용하세요.

3. 디버깅

main.js 에 중단점을 설정하고, Debug View 에서 디버깅을 시작하세요. 중단점을 만나게 될 것 입니다.

VSCode 에서 바로 디버깅 할 수 있는 프로젝트를 미리 준비했습니다: https://github.com/octref/vscode-electron-debug/tree/master/electron-quick-start


node-inspector 에서 메인 프로세스 디버깅하기

[node-inspector][node-inspector] 는 Electron 의 메인 프로세스를 디버깅하기 위해 크롬에서 사용할 수 있는 익숙한 개발도구 GUI 를 제공합니다. 그러나, node-inspector 가 네이티브 Node 모듈에 의존적이기 때문에 디버깅하려는 Electron 버전에 맞춰 다시 빌드해야 합니다. node-inspector 다시 빌드하여 의존성을 재구성하거나 [electron-inspector`] 가 대신 하게 할 수 있으며, 두 방식이 이 문서에 나와있습니다.

참고: 글쓴 시점 현재 node-inspector 최종버전 (0.12.8) 은 Electron 1.3.0 이상에서 해당 의존성 중 하나를 패치하지 않고 빌드 할 수 없습니다. electron-inspector 을 사용한다면 알아서 처리될 것 입니다.

디버깅에 electron-inspector 사용하기

1. node-gyp 필수 도구 설치

2. electron-rebuild가 없다면, 설���

npm install electron-rebuild --save-dev

3. electron-inspector 설치

npm install electron-inspector --save-dev

4. Electron 시작

--debug 스위치와 함께 Electron 실행:

electron --debug=5858 your/app

또는, 스크립트의 첫번째 줄에서 실행 중단:

electron --debug-brk=5858 your/app

5. electron-inspector 시작

macOS / Linux:

node_modules/.bin/electron-inspector

Windows:

node_modules\\.bin\\electron-inspector

electron-inspector 는 첫 실행과 Electron 버전 변경시에 node-inspector 의존성을 다시 빌드 할 것 입니다. 다시 빌드하는 과정에 Node 헤더와 라이브러리를 다운받기 위해 인터넷 연결이 필요하며, 이 작업은 몇 분 정도 시간이 소요됩니다.

6. 디버거 UI 로드

Chrome 브라우저에서 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 주소에 접속합니다. --debug-brk 로 시작한 경우 UI 갱신을 위해 일시정지 버튼을 클릭해야 할 수도 있습니다.

디버깅에 node-inspector 사용하기

1. node-gyp 필수 도구 설치

2. node-inspector 설치

$ npm install node-inspector

3. node-pre-gyp 설치

$ npm install node-pre-gyp

4. Electron 용 node-inspector v8 모듈 재 컴파일

참고: 사용하는 Electron의 버전에 맞춰 target 인수를 변경하세요.

$ node_modules/.bin/node-pre-gyp --target=1.2.5 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall
$ node_modules/.bin/node-pre-gyp --target=1.2.5 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall

또한 네이티브 모듈 설치 방법 문서도 참고해보세요.

5. Electron 디버그 모드 활성화

다음과 같이 debung 플래그로 Electron 을 실행할 수 있습니다:

$ electron --debug=5858 your/app

또는 스크립트 첫번째 줄에서 일시 정지할 수 있습니다:

$ electron --debug-brk=5858 your/app

6. Electron을 사용하는 node-inspector 서버 시작하기

$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js

7. 디버거 UI 로드

Chrome 브라우저에서 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 주소에 접속합니다. --debug-brk 로 시작한 경우 엔트리 라인을 보기 위해 일시정지 버튼을 클릭해야 할 수도 있습니다.


메인 프로세스 디버깅하기

Electron 브라우저 창의 개발자 도구는 웹 페이지 같은 창에서 실행된 스크립트만 디버깅이 가능합니다. 메인 프로세스에서 실행된 자바스크립트를 디버깅 하기 위해 외부 디버거가 필요하며, Electron 실행시 --debug 또는 --debug-brk 스위치가 필요합니다.

커맨드 라인 스위치(command line switches)

다음 커맨드 라인 스위치들을 사용하여 메인 프로세스를 디버깅 할 수 있습니다:

--debug=[port]

이 스위치를 사용하면 Electron은 지정한 port에 V8 디버거 프로토콜을 리스닝합니다. 기본 port5858 입니다.

--debug-brk=[port]

--debug와 비슷하지만 스크립트의 첫번째 라인에서 일시정지합니다.

외부 디버거

V8 디버거 프로토콜을 지원하는 디버거가 필요합니다. 다음 가이드들이 도움이 됩니다:


데스크톱 환경 통합

애플리케이션 배포의 대상이 되는 서로 다른 운영체제 시스템의 환경에 맞춰 애플리케이션의 기능을 통합할 수 있습니다. 예를 들어 Windows에선 태스크바의 JumpList에 바로가기를 추가할 수 있고 Mac(macOS)에선 dock 메뉴에 커스텀 메뉴를 추가할 수 있습니다.

이 문서는 Electron API를 이용하여 각 운영체제 시스템의 기능을 활용하는 방법을 설명합니다.

데스크톱 알림 (Windows, Linux, macOS)

Windows, Linux, macOS 운영체제 모두 기본적으로 애플리케이션에서 유저에게 알림을 보내는 방법을 제공합니다. Electron은 HTML5 Notification API를 통해 개발자가 편리하게 데스크톱 알림을 사용할 수 있는 기능을 제공합니다. 데스크톱 알림은 운영체제의 네이티브 알림 API를 사용하여 표시합니다.

참고: 이 API는 HTML5 API이기 때문에 렌더러 프로세스에서만 사용할 수 있습니다.

let myNotification = new Notification('Title', {
  body: 'Lorem Ipsum Dolor Sit Amet'
})

myNotification.onclick = () => {
  console.log('Notification clicked')
}

위 코드를 통해 생성한 데스크톱 알림은 각 운영체제 모두 비슷한 사용자 경험을 제공하지만, 하지만 몇 가지 다른 점들이 있습니다.

Windows

또한 알림 본문의 최대 길이는 250자 입니다. Windows 개발팀에선 알림 문자열을 200자 이하로 유지하는 것을 권장합니다.

Linux

데스크톱 알림의 구현으로 libnotify를 사용합니다. 따라서 Desktop Notifications Specification을 따르는 모든 데스크탑 환경에서 데스크톱 알림 기능을 사용할 수 있습니다. Cinnamon, Enlightenment, Unity, GNOME, KDE등을 지원합니다.

macOS

macOS에서의 데스크톱 알림은 아주 직관적입니다. 하지만 데스크톱 알림을 사용할 땐 Apple’s Human Interface guidelines regarding notifications 가이드를 고려해야 합니다.

참고로 데스크롭 알림의 최대 길이는 256 바이트 입니다. 길이가 초과할 경우 초과한 글자가 잘립니다.

최근 사용한 문서 (Windows & macOS)

Windows와 macOS는 JumpList 또는 dock 메뉴를 통해 최근 문서 리스트에 쉽게 접근할 수 있습니다.

JumpList:

JumpList 최근 문서

애플리케이션 dock menu:

파일을 최근 문서에 추가하려면 app.addRecentDocument API를 사용할 수 있습니다:

const {app} = require('electron')
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')

그리고 app.clearRecentDocuments API로 최근 문서 리스트를 비울 수 있습니다:

const {app} = require('electron')
app.clearRecentDocuments()

Windows에서 주의할 점

이 기능을 Windows에서 사용할 땐 운영체제 시스템에 애플리케이션에서 사용하는 파일 확장자가 등록되어 있어야 합니다. 그렇지 않은 경우 파일을 JumpList에 추가해도 추가되지 않습니다. 애플리케이션 등록에 관련된 API의 모든 내용은 Application Registration에서 찾아볼 수 있습니다.

유저가 JumpList에서 파일을 클릭할 경우 클릭된 파일의 경로가 커맨드 라인 인수로 추가되어 새로운 인스턴스의 애플리케이션이 실행됩니다.

macOS에서 주의할 점

파일이 최근 문서 메뉴에서 요청될 경우 app 모듈의 open-file 이벤트가 호출됩니다.

커스텀 독 메뉴 (macOS)

macOS는 개발자가 dock에 커스텀 메뉴를 만들 수 있도록 허용하고 있습니다. 보통 애플리케이션의 특정 기능 바로가기를 만들 때 사용합니다:

Terminal.app의 dock menu:

커스텀 dock menu를 설정하려면 app.dock.setMenu API를 사용하면 됩니다. macOS에서만 사용 가능합니다:

const {app, Menu} = require('electron')

const dockMenu = Menu.buildFromTemplate([
  {label: 'New Window', click () { console.log('New Window') }},
  {label: 'New Window with Settings',
    submenu: [
      {label: 'Basic'},
      {label: 'Pro'}
    ]
  },
  {label: 'New Command...'}
])
app.dock.setMenu(dockMenu)

사용자 작업 (Windows)

Windows에선 JumpList의 Tasks 카테고리에 원하는 작업을 설정할 수 있습니다. MSDN에선 해당 기능을 다음과 같이 설명하고 있습니다:

애플리케이션 작업은 프로그램의 기능 그리고 주요사양 두가지를 기반으로 유저의 행동을 예측하여 정의합니다. 실행할 필요가 없는 애플리케이션 작업은 작동하지 않을 때 반드시 context-free를 유지해야 합니다. 작업은 일반 사용자가 프로그램을 실행하거나 이메일 프로그램으로 이메일을 작성하거나 달력을 불러오고, 워드 프로세서로 새 문서를 작성, 특정 모드, 부속 명령으로 프로그램을 실행하는 등의 통계적, 일반적으로 가장 많이 사용되는 작업인지를 고려해야 합니다. 애플리케이션 작업은 일반 유저가 필요로 하지 않는 고급 기능을 조잡하게 채우거나 등록과 같은 일회성의 작업을 포함해선 안됩니다. 또한 작업에 특별 이벤트 또는 업그레이드 등의 홍보성 작업을 추가하면 안됩니다.

작업 리스트는 가능한 한 정적으로 유지되는 것을 적극 권장합니다. 이것은 동일한 상태 또는 응용 프로그램의 상태에 관계없이 유지되어야 합니다. 작업 목록은 동적으로 변경할 수 있지만 몇몇 유저는 예상하지 못한 작업 목록 변경에 혼란을 일으킬 수 있다는 점을 고려해야 합니다.

Internet Explorer의 작업:

IE

macOS의 dock menu(진짜 메뉴)와는 달리 Windows의 사용자 작업은 애플리케이션 바로 가기처럼 작동합니다. 유저가 작업을 클릭할 때 설정한 인수와 함께 새로운 애플리케이션이 실행됩니다.

사용자 작업을 설정하려면 app.setUserTasks 메서드를 통해 구현할 수 있습니다:

const {app} = require('electron')
app.setUserTasks([
  {
    program: process.execPath,
    arguments: '--new-window',
    iconPath: process.execPath,
    iconIndex: 0,
    title: 'New Window',
    description: 'Create a new window'
  }
])

작업 리스트를 비우려면 간단히 app.setUserTasks 메서드의 첫번째 인수에 빈 배열을 넣어 호출하면 됩니다:

const {app} = require('electron')
app.setUserTasks([])

사용자 작업 리스트는 애플리케이션이 삭제되지 않는 한 종료되어도 태스크바에 보존됩니다. 이러한 이유로 반드시 프로그램 경로와 아이콘 경로를 지정해야 합니다.

미리보기 툴바

Windows에선 작업 표시줄의 애플리케이션 선택시 나오는 미리보기에 특정한 미리보기 툴바를 추가할 수 있습니다. 이 기능은 유저가 윈도우를 활성화 하지 않고 특정한 커맨드를 실행시킬 수 있도록 할 수 있습니다.

MSDN의 설명에 의하면:

이 툴바는 표준 툴바의 공통 컨트롤과 비슷한 역할을 합니다. 버튼은 최대 7개 까지 만들 수 있습니다. 각 버튼의 구조엔 ID, 이미지, 툴팁, 상태 등이 정의되어있습니다. 작업표시줄에 구조가 전달되면 애플리케이션이 상태에 따라 버튼을 숨기거나, 활성화하거나, 비활성화 할 수 있습니다.

예를 들어, 윈도우 미디어 플레이어는(WMP) 미디어 플레이어가 공통적으로 사용하는 재생, 일시정지, 음소거, 정지등의 컨트롤을 포함하고 있습니다.

Windows Media Player의 미리보기 툴바:

player

BrowserWindow.setThumbarButtons API를 통해 애플리케이션에 미리보기 툴바를 설정할 수 있습니다:

const {BrowserWindow} = require('electron')
const path = require('path')

let win = new BrowserWindow({
  width: 800,
  height: 600
})

win.setThumbarButtons([
  {
    tooltip: 'button1',
    icon: path.join(__dirname, 'button1.png'),
    click () { console.log('button1 clicked') }
  },
  {
    tooltip: 'button2',
    icon: path.join(__dirname, 'button2.png'),
    flags: ['enabled', 'dismissonclick'],
    click () { console.log('button2 clicked.') }
  }
])

미리보기 툴바를 비우려면 간단히 BrowserWindow.setThumbarButtons API에 빈 배열을 전달하면 됩니다:

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setThumbarButtons([])

Unity 런처 숏컷 기능 (Linux)

Unity 환경에선 .desktop 파일을 수정함으로써 런처에 새로운 커스텀 엔트리를 추가할 수 있습니다. Adding Shortcuts to a Launcher 가이드를 참고하세요.

Audacious의 런처 숏컷:

audacious

작업 표시줄 안의 프로그레스 바 (Windows, macOS, Unity)

Windows에선 작업 표시줄의 애플리케이션 버튼에 프로그레스 바를 추가할 수 있습니다. 이 기능은 사용자가 애플리케이션의 창을 열지 않고도 애플리케이션의 작업의 상태 정보를 시각적으로 보여줄 수 있도록 해줍니다.

macOS에선 프로그레스바가 dock 아이콘의 일부에 표시됩니다.

또한 Unity DE도 런처에 프로그레스 바를 부착할 수 있습니다.

작업 표시줄 버튼의 프로그레스 바:

Taskbar Progress Bar

이 기능은 BrowserWindow.setProgressBar API를 사용하여 구현할 수 있습니다:

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setProgressBar(0.5)

작업 표시줄의 아이콘 오버레이 (Windows)

Windows에선 작업 표시줄 버튼에 애플리케이션의 상태를 표시하는 작은 오버레이를 사용할 수 있습니다. MSDN에서 인용하자면 (영문):

Icon overlays serve as a contextual notification of status, and are intended to negate the need for a separate notification area status icon to communicate that information to the user. For instance, the new mail status in Microsoft Outlook, currently shown in the notification area, can now be indicated through an overlay on the taskbar button. Again, you must decide during your development cycle which method is best for your application. Overlay icons are intended to supply important, long-standing status or notifications such as network status, messenger status, or new mail. The user should not be presented with constantly changing overlays or animations.

작업 표시줄 버튼 위의 오버레이:

작업 표시줄 버튼 위의 오버레이

윈도우에 오버레이 아이콘을 설정하려면 BrowserWindow.setOverlayIcon API를 사용할 수 있습니다:

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setOverlayIcon('path/to/overlay.png', 'Description for overlay')

대표 파일 제시 (macOS)

macOS는 창에서 대표 파일을 설정할 수 있습니다. 타이틀바에서 파일 아이콘이 있고, 사용자가 Command-Click 또는 Control-Click 키를 누를 경우 파일 경로 팝업이 보여집니다. 또한 창의 상태도 지정할 수 있습니다. 다시 말해 로드된 문서의 수정 여부를 제목의 파일 아이콘에 표시할 수 있습니다.

대표 파일 팝업 메뉴:

대표 파일 관련 API는 BrowserWindow.setRepresentedFilenameBrowserWindow.setDocumentEdited를 사용할 수 있습니다:

const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setRepresentedFilename('/etc/passwd')
win.setDocumentEdited(true)

파일을 윈도우 밖으로 드래그할 수 있도록 만들기

파일을 조작하는 특정 종류의 애플리케이션들에서 파일을 Electron에서 다른 애플리케이션으로 드래그할 수 있는 기능은 중요합니다. 이 기능을 구현하려면 애플리케이션에서 ondragstart 이벤트가 발생했을 때 webContents.startDrag(item) API를 호출해야 합니다:

웹 페이지에서:

<a href="#" id="drag">item</a>
<script type="text/javascript" charset="utf-8">
  document.getElementById('drag').ondragstart = (event) => {
    event.preventDefault()
    ipcRenderer.send('ondragstart', '/path/to/item')
  }
</script>

메인 프로세스에서:

const {ipcMain} = require('electron')
ipcMain.on('ondragstart', (event, filePath) => {
  event.sender.startDrag({
    file: filePath,
    icon: '/path/to/icon.png'
  })
})

개발자 도구 확장 기능

애플리케이션의 디버깅을 쉽게 하기 위해 Electron은 기본적으로 Chrome DevTools Extension을 지원합니다.

Electron은 유명한 웹 프레임워크를 디버깅하기 위해 사용할 수 있는 개발자 도구 확장 기능을 사용할 수 있도록 Chrome 개발자 도구 확장 기능을 지원합니다.

개발자 도구는 어떻게 로드하나요

이 문서는 확장 기능을 수동으로 로드하는 방법의 과정을 설명합니다. electron-devtools-installer와 같은 Chrome WebStore에서 자동으로 확장 기능을 다운로드하는 서드-파티 도구를 사용할 수도 있습니다.

Electron에 확장 기능을 로드하려면, Chrome 브라우저에서 다운로드 해야 하며, 파일 시스템 경로를 지정해야 합니다. 그리고 BrowserWindow.addDevToolsExtension(extension)를 호출함으로써 기능을 로드할 수 있습니다.

예시로 React Developer Tools를 사용한다면:

  1. Chrome 브라우저를 설치합니다.
  2. chrome://extensions로 이동한 후 해시된 fmkadmapgofadopljbjfkapdkoienihi 같이 생긴 확장 기능의 ID를 찾습니다.
  3. Chrome에서 사용하는 확장 기능을 저장해둔 파일 시스템 경로를 찾습니다:
    • Windows에선 %LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions;
    • Linux에선:
      • ~/.config/google-chrome/Default/Extensions/
      • ~/.config/google-chrome-beta/Default/Extensions/
      • ~/.config/google-chrome-canary/Default/Extensions/
      • ~/.config/chromium/Default/Extensions/
    • macOS에선 ~/Library/Application Support/Google/Chrome/Default/Extensions.
  4. 확장 기능의 경로를 BrowserWindow.addDevToolsExtension API로 전달합니다. React Developer Tools의 경우 다음과 비슷해야 합니다: ~/Library/Application Support/Google/Chrome/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/0.15.0_0

참고: BrowserWindow.addDevToolsExtension API는 app 모듈의 ready 이벤트가 발생하기 전까지 사용할 수 없습니다.

확장 기능의 이름은 BrowserWindow.addDevToolsExtension에서 반환되며, 이 이름을 BrowserWindow.removeDevToolsExtension API로 전달함으로써 해당하는 확장 기능을 언로드할 수 있습니다.

지원하는 개발자 도구 확장 기능

Electron은 아주 제한적인 chrome.* API만을 지원하므로 확장 기능이 지원하지 않는 chrome.* API를 사용한다면 해당 기능은 작동하지 않을 것입니다. 다음 개발자 도구들은 Electron에서 정상적으로 작동하는 것을 확인했으며 작동 여부를 보장할 수 있는 확장 기능입니다:

개발자 도구가 작동하지 않을 때 어떻게 해야 하나요?

먼저 해당 확장 기능이 확실히 계속 유지되고 있는지를 확인하세요. 몇몇 확장 기능들은 최신 버전의 Chrome 브라우저에서도 작동하지 않습니다. 그리고 이러한 확장 기능에 대해선 Electron 개발팀에 해줄 수 있는 것이 아무것도 없습니다.

위와 같은 상황이 아니라면 Electron의 이슈 리스트에 버그 보고를 추가한 후 예상한 것과 달리 확장 기능의 어떤 부분의 정상적으로 작동하지 않았는지 설명하세요.


Electron 버전 관리

노련한 Node 개발자라면, semver (유의적 버전)에 대해 확실히 알고 있을 것입니다 - 그리고 제공된 의존성 관리 시스템은 고정된 버전 숫자 대신 견고한 가이드라인을 따릅니다. Electron은 Node와 Chromium에 큰 의존성을 지니고 있는 만큼, 유의적 버전을 그대로 따르지 않습니다. 따라서 항상 Electron의 특정 버전을 참조해야 합니다.

버전 숫자는 다음과 같은 규칙으로 올라갑니다:

electron 또는 electron-prebuilt를 사용하고 있다면, Electron의 변경 사항을 확실하게 인지하고 개발자 스스로 업그레이드를 적용하기 위해 고정된 버전 숫자를 사용하는 것을 권장합니다. (^1.1.0 대신 1.1.0 사용)


Mac 앱 스토어 애플리케이션 제출 가이드

Electron은 v0.34.0 버전부터 앱 패키지를 Mac App Store(MAS)에 제출할 수 있게 되었습니다. 이 가이드는 애플리케이션을 앱 스토어에 등록하는 방법과 빌드의 한계에 대한 설명을 제공합니다.

참고: Mac App Store에 애플리케이션을 등록하려면 Apple Developer Program에 등록되어 있어야 하며 비용이 발생할 수 있습니다.

앱 스토어에 애플리케이션을 등록하는 방법

다음 몇 가지 간단한 절차에 따라 앱 스토어에 애플리케이션을 등록하는 방법을 알아봅니다. 한가지, 이 절차는 제출한 앱이 Apple로부터 승인되는 것을 보장하지 않습니다. 따라서 여전히 Apple의 Submitting Your App 가이드를 숙지하고 있어야 하며 앱 스토어 제출 요구 사항을 확실히 인지하고 있어야 합니다.

인증서 취득

앱 스토어에 애플리케이션을 제출하려면, 먼저 Apple로부터 인증서를 취득해야 합니다. 취득 방법은 웹에서 찾아볼 수 있는 가이드를 참고하면 됩니다.

Team ID 얻기

애플리케이션에 서명하기 전에, 먼저 개발 계정의 Team ID를 알아야 합니다. Team ID를 알아보려면 Apple Developer Center에 로그인한 후, 사이드바의 Membership을 클릭합니다. Team ID는 Membership Information 섹션의 팀 이름 밑에 위치합니다.

앱에 서명하기

준비 작업이 끝난 후, 애플리케이션 배포 문서에 따라 애플리케이션을 패키징한 후 애플리케이션에 서명합니다.

먼저, 앱의 Info.plist 에 Team ID 를 값으로 갖는 ElectronTeamID 키를 추가해야 합니다:

<plist version="1.0">
<dict>
  ...
  <key>ElectronTeamID</key>
  <string>TEAM_ID</string>
</dict>
</plist>

그리고, 다음 두 자격 파일을 준비해야 합니다.

child.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>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.inherit</key>
    <true/>
  </dict>
</plist>

parent.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>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.application-groups</key>
    <string>TEAM_ID.your.bundle.id</string>
  </dict>
</plist>

TEAM_ID 부분은 Team ID로 치환하고, your.bundle.id 부분은 애플리케이션의 Bundle ID로 치환해야 합니다.

그리고 다음 스크립트를 통해 애플리케이션에 서명합니다:

#!/bin/bash

# 애플리케이션의 이름.
APP="YourApp"
# 서명할 애���리케이션의 경로.
APP_PATH="/path/to/YourApp.app"
# 서명된 패키지의 출력 경로.
RESULT_PATH="~/Desktop/$APP.pkg"
# 요청한 인증서의 이름.
APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)"
INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)"
# plist 파일의 경로.
CHILD_PLIST="/path/to/child.plist"
PARENT_PLIST="/path/to/parent.plist"

FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"

codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP"
codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH"

productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"

만약 macOS의 샌드박스 개념에 대해 처음 접한다면 Apple의 Enabling App Sandbox 문서를 참고하여 기본적인 개념을 이해해야 합니다. 그리고 자격(plist) 파일에 애플리케이션에서 요구하는 권한의 키를 추가합니다.

그 외에 별로도 electron-osx-sign 모듈을 사용하여 직접 서명할 수도 있습니다.

네이티브 모듈에 서명하기

앱 내부에서 사용한 네이티브 모듈도 서명이 필요합니다. electron-osx-sign을 사용한다면, 인수 목록에 빌트인 바이너리 경로가 포함되어 있는지 확인해야 합니다:

electron-osx-sign YourApp.app YourApp.app/Contents/Resources/app/node_modules/nativemodule/build/release/nativemodule

참고로 네이티브 모듈이 의도하지 않게 중간 파일을 포함하는 경우도 있으며 이 파일은 포함되어선 안됩니다. (해당 파일에도 서명해야 할 수도 있습니다) 버전 8.1.0 전의 electron-packager 는, --ignore=.+\.o$ 를 추가하여 이 파일을 무시할 수 있습니다. 8.1.0 버전 이후에는 기본적으로 무시됩니다.

애플리케이션 업로드

애플리케이션 서명을 완료한 후 iTunes Connect에 업로드하기 위해 Application Loader를 사용할 수 있습니다. 참고로 업로드하기 전에 레코드를 만들었는지 확인해야 합니다.

애플리케이션을 심사에 제출

위 과정을 마치면 애플리케이션을 심사를 위해 제출할 수 있습니다.

MAS 빌드의 한계

모든 애플리케이션 샌드박스에 대한 요구 사항을 충족시키기 위해, 다음 모듈들은 MAS 빌드에서 비활성화됩니다:

그리고 다음 동작으로 대체됩니다:

또한 애플리케이션 샌드박스 개념으로 인해 애플리케이션에서 접근할 수 있는 리소스는 엄격하게 제한되어 있습니다. 자세한 내용은 앱 샌드박싱 문서를 참고하세요.

추가적인 권한

Mac 앱 스토어 빌드를 위해 앱에서 사용하는 Electron API에 따라 parent.plist 파일에 추가적인 기능에 대한 권한을 추가해야 할 수도 있습니다.

네트워크 접근

서버와 연결하기 위한 외부로 나가는 네트워크 연결 허용 활성화:

<key>com.apple.security.network.client</key>
<true/>

네트워크 리스닝 소켓을 열기 위한 내부로 들어오는 네트워크 연결 허용 활성화:

<key>com.apple.security.network.server</key>
<true/>

자세한 내용은 [네트워크 접근 활성화 문서][network-access] 를 참고하세요.

dialog.showOpenDialog

<key>com.apple.security.files.user-selected.read-only</key>
<true/>

자세한 내용은 User-Selected 파일 접근 활성화 문서를 참고하세요.

dialog.showSaveDialog

<key>com.apple.security.files.user-selected.read-write</key>
<true/>

자세한 내용은 User-Selected 파일 접근 활성화 문서를 참고하세요.

Electron에서 사용하는 암호화 알고리즘

국가와 살고 있는 지역에 따라, 맥 앱스토어는 제출한 애플리케이션에서 사용하는 암호화 알고리즘의 문서를 요구할 수 있습니다. 심지어 U.S. Encryption Registration (ERN)의 승인 사본을 제출하라고 할 수도 있습니다.

Electron은 다음과 같은 암호화 알고리즘을 사용합니다:

ERN의 승인을 얻는 방법은, 다음 글을 참고하는 것이 좋습니다: 애플리케이션이 암호화를 사용할 때, 합법적으로 Apple의 앱 스토어에 제출하는 방법 (또는 ERN의 승인을 얻는 방법).

역자주: Mac 앱 배포 가이드 공식 한국어 문서


오프스크린 렌더링

오프스크린 렌더링은 비트맵에 브라우저 윈도우의 컨텐츠를 얻게 합니다. 그래서 아무곳에서나 렌더링 될 수 있습니다. 예를 들어 3D 에서 텍스처위에 렌더링 될 수 있습니다. Electron 의 오프스크린 렌더링은 Chromium Embedded Framework 프로젝트와 비슷한 접근방식을 사용합니다.

두 방식의 렌더링을 사용할 수 있고 효율적으로 하기 위해 변경된 영역만 'paint' 이벤트에 전달됩니다. 렌더링을 중지하거나, 계속하거나, 프레임 속도를 변경할 수 있습니다. 명시된 프레임 속도는 상한선입니다. 웹페이지에 아무일도 발생하지 않으면 프레임이 생성되지 않습니다. 프레임 속도 최고값은 60입니다. 그 이상은 이점은 없고, 성능 저하만 발생합니다.

두가지 렌더링 방식

GPU 가속

GPU 가속 렌더링은 컴포지션에 GPU 가 사용되는 것을 의미합니다. 프레임이 GPU 에서 복사되기 때문에 더 많은 성능이 필요합니다. 그래서 이 방식이 좀 더 느립니다. 이 방식의 장점은 WebGL 과 3D CSS 애니메이션 지원입니다.

소프트웨어 출력 장치

이 방식은 CPU에서 렌더링을 위해 소프트웨어 출력 장치를 사용하여 프레임 생성이 더 빠릅니다. 그래서 이 방식을 GPU 가속보다 선호합니다.

이 방식을 사용하려면 app.disableHardwareAcceleration() API 를 호출하여 GPU 가속을 비활성화 하여야합니다.

사용법

const {app, BrowserWindow} = require('electron')

app.disableHardwareAcceleration()

let win
app.once('ready', () => {
  win = new BrowserWindow({
    webPreferences: {
      offscreen: true
    }
  })
  win.loadURL('http://github.com')
  win.webContents.on('paint', (event, dirty, image) => {
    // updateBitmap(dirty, image.getBitmap())
  })
  win.webContents.setFrameRate(30)
})

온라인/오프라인 이벤트 감지

온라인/오프라인 이벤트는 다음 예시와 같이 렌더러 프로세스에서 표준 HTML5 API를 이용하여 구현할 수 있습니다.

main.js

const {app, BrowserWindow} = require('electron')

let onlineStatusWindow

app.on('ready', () => {
  onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
  onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`)
})

online-status.html

<!DOCTYPE html>
<html>
<body>
<script>
  const alertOnlineStatus = () => {
    window.alert(navigator.onLine ? 'online' : 'offline')
  }

  window.addEventListener('online',  alertOnlineStatus)
  window.addEventListener('offline',  alertOnlineStatus)

  alertOnlineStatus()
</script>
</body>
</html>

메인 프로세스에서 이 이벤트를 처리할 필요가 있는 경우 이벤트를 메인 프로세스로 보낼 수 있습니다. 메인 프로세스는 navigator 객체를 가지고 있지 않기 때문에 이 이벤트를 직접 사용할 수는 없습니다.

대신 다음 예시와 같이 Electron의 inter-process communication(ipc) 유틸리티를 사용하면 이벤트를 메인 프로세스로 전달할 수 있습니다.

main.js

const {app, BrowserWindow, ipcMain} = require('electron')
let onlineStatusWindow

app.on('ready', () => {
  onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
  onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`)
})

ipcMain.on('online-status-changed', (event, status) => {
  console.log(status)
})

online-status.html

<!DOCTYPE html>
<html>
<body>
<script>
  const {ipcRenderer} = require('electron')
  const updateOnlineStatus = () => {
    ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline')
  }

  window.addEventListener('online',  updateOnlineStatus)
  window.addEventListener('offline',  updateOnlineStatus)

  updateOnlineStatus()
</script>
</body>
</html>

API 변경 계획

Electron 2.0 에 몇몇 API 가 제거될 예정입니다.

정해진 적용 계획은 없지만 적어도 90일 전에 중단 경고를 할 것 입니다.

변경 내용은 /docs/tutorial/planned-breaking-changes를 참고하세요.


시작하기

소개

Electron은 자바스크립트와 함께 제공된 풍부한 네이티브 API를 사용하여 멋진 데스크탑 애플리케이션을 만들 수 있도록 해주는 프레임워크입니다. 이 프레임워크의 Node.js는 웹 서버 개발이 아닌 데스크탑 애플리케이션 개발에 초점을 맞췄습니다.

이 말은 Electron이 GUI 라이브러리의 자바스크립트 바인딩이라는 뜻이 아닙니다. 대신, Electron은 웹 페이지의 GUI를 사용합니다. 쉽게 말해 Electron은 자바스크립트를 사용하여 조작하는 작은 Chromium 브라우저로 볼 수 있습니다.

메인 프로세스

Electron은 실행될 때 메인 프로세스 로 불리는 package.jsonmain 스크립트를 호출합니다. 이 스크립트는 메인 프로세스에서 작동합니다. GUI 컴포넌트를 조작하거나 웹 페이지 창을 생성할 수 있습니다.

렌더러 프로세스

Electron이 웹페이지를 보여줄 때 Chromium의 multi-processes 구조도 같이 사용됩니다. Electron 프로세스 내에서 작동하는 웹 페이지를 렌더러 프로세스 라고 불립니다.

보통 일반 브라우저의 웹 페이지들은 샌드박스가 적용된 환경에서 작동하며 네이티브 리소스에는 접근할 수 없도록 되어 있습니다. 하지만 Electron은 웹 페이지 내에서 Node.js API를 사용하여 low-level 수준으로 운영체제와 상호작용할 수 있습니다.

메인 프로세스와 렌더러 프로세스의 차이점

메인 프로세스는 BrowserWindow Class를 사용하여 새로운 창을 만들 수 있습니다. BrowserWindow 인스턴스는 따로 분리된 프로세스에서 렌더링 되며 이 프로세스를 렌더러 프로세스라고 합니다. BrowserWindow 인스턴스가 소멸할 때 그 창의 렌더러 프로세스도 같이 소멸합니다.

메인 프로세스는 모든 웹 페이지와 렌더러 프로세스를 관리하며 렌더러 프로세스는 각각의 프로세스에 고립되며 웹 페이지의 작동에만 영향을 끼칩니다.

웹 페이지 내에선 기본적으로 네이티브 GUI와 관련된 API를 호출할 수 없도록 설계 되어 있습니다. 왜냐하면 웹 페이지 내에서 네이티브 GUI 리소스를 관리하는 것은 보안에 취약하고 리소스를 누수시킬 수 있기 때문입니다. 꼭 웹 페이지 내에서 API를 사용해야 한다면 메인 프로세스에서 그 작업을 처리할 수 있도록 메인 프로세스와 통신을 해야 합니다.

Electron에는 메인 프로세스와 렌더러 프로세스 사이에 통신을 할 수 있도록 ipcRenderer와 [`ipcMain) 모듈을 제공하고 있습니다. 또는 remote 모듈을 사용하여 RPC 스타일로 통신할 수도 있습니다. 또한 FAQ에서 다양한 객체를 공유하는 방법도 소개하고 있습니다.

첫번째 Electron 앱 만들기

보통 Electron 앱은 다음과 같은 폴더 구조를 가집니다:

your-app/
├── package.json
├── main.js
└── index.html

package.json은 node 모듈의 package.json과 같습니다. 그리고 main 필드에 스크립트 파일을 지정하면 메인 프로세스의 엔트리 포인트로 사용합니다. 예를 들어 사용할 수 있는 package.json은 다음과 같습니다:

{
  "name"    : "your-app",
  "version" : "0.1.0",
  "main"    : "main.js"
}

알림: 만약 main 필드가 package.json에 설정되어 있지 않으면 Electron은 자동으로 같은 디렉터리의 index.js를 로드합니다.

반드시 main.js에서 창을 만들고 시스템 이벤트를 처리해야 합니다. 대표적인 예시로 다음과 같이 작성할 수 있습니다:

const electron = require('electron')
// 애플리케이션 생명주기를 조작 하는 모듈.
const {app} = electron
// 네이티브 브라우저 창을 만드는 모듈.
const {BrowserWindow} = electron

// 윈도우 객체를 전역에 유지합니다. 만약 이렇게 하지 않으면
// 자바스크립트 GC가 일어날 때 창이 멋대로 닫혀버립니다.
let win

function createWindow () {
  // 새로운 브라우저 창을 생성합니다.
  win = new BrowserWindow({width: 800, height: 600})

  // 그리고 현재 디렉터리의 index.html을 로드합니다.
  win.loadURL(`file://${__dirname}/index.html`)

  // 개발자 도구를 엽니다.
  win.webContents.openDevTools()

  // 창이 닫히면 호출됩니다.
  win.on('closed', () => {
    // 윈도우 객체의 참조를 삭제합니다. 보통 멀티 윈도우 지원을 위해
    // 윈도우 객체를 배열에 저장하는 경우가 있는데 이 경우
    // 해당하는 모든 윈도우 객체의 참조를 삭제해 주어야 합니다.
    win = null
  })
}

// 이 메서드는 Electron의 초기화가 끝나면 실행되며 브라우저
// 윈도우를 생성할 수 있습니다. 몇몇 API는 이 이벤트 이후에만
// 사용할 수 있습니다.
app.on('ready', createWindow)

// 모든 창이 닫히면 애플리케이션 종료.
app.on('window-all-closed', () => {
  // macOS의 대부분의 애플리케이션은 유저가 Cmd + Q 커맨드로 확실하게
  // 종료하기 전까지 메뉴바에 남아 계속 실행됩니다.
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // macOS에선 보통 독 아이콘이 클릭되고 나서도
  // 열린 윈도우가 없으면, 새로운 윈도우를 다시 만듭니다.
  if (win === null) {
    createWindow()
  }
})

// 이 파일엔 제작할 애플리케이션에 특화된 메인 프로세스 코드를
// 포함할 수 있습니다. 또한 파일을 분리하여 require하는 방법으로
// 코드를 작성할 수도 있습니다.

마지막으로, 사용자에게 보여줄 index.html 웹 페이지의 예시입니다:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>헬로 월드!</title>
  </head>
  <body>
    <h1>헬로 월드!</h1>
    이 애플리케이션은 node <script>document.write(process.version)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    Electron <script>document.write(process.versions.electron)</script>을 사용합니다.
  </body>
</html>

앱 실행하기

앱을 작성한 후 애플리케이션 배포 가이드를 따라 앱을 패키징 하고 패키징한 앱을 실행할 수 있습니다. 또한 Electron 실행파일을 다운로드 받아 바로 실행해 볼 수도 있습니다.

electron

electron은 Electron의 미리 컴파일된 바이너리를 포함하는 npm 모듈입니다.

만약 npm을 통해 전역에 이 모듈을 설치했다면, 애플리케이션 소스 디렉터리에서 다음 명령을 실행하면 바로 실행할 수 있습니다:

electron .

또는 앱 디렉터리 밖에서 앱을 실행할 수도 있습니다:

electron app

npm 모듈을 로컬에 설치했다면 다음 명령으로 실행할 수 있습니다:

macOS / Linux

$ ./node_modules/.bin/electron .

Windows

$ .\node_modules\.bin\electron .

다운로드 받은 Electron 바이너리 사용

따로 Electron 바이너리를 다운로드 받았다면 다음 예시와 같이 실행하면 됩니다.

Windows

$ .\electron\electron.exe your-app\

Linux

$ ./electron/electron your-app/

macOS

$ ./Electron.app/Contents/MacOS/Electron your-app/

애플리케이션 실행파일은 Electron의 release 패키지에 포함되어 있습니다. 여기에서 다운로드 받을 수 있습니다.

배포용 실행 파일 만들기

애플리케이션 작성을 모두 끝냈다면 애플리케이션 배포 가이드를 통해 제작한 앱을 패키징하고 배포할 수 있습니다.

미리 작성된 앱 실행하기

electron/electron-quick-start 저장소를 클론하면 이 문서에서 작성한 예시 앱을 바로 실행해 볼 수 있습니다.

참고: 이 예시를 실행시키려면 GitNode.js가 필요합니다. (CLI에서 실행 가능한 npm이 있어야 합니다)

역자주: npm은 보통 Node.js를 설치하면 자동으로 같이 설치됩니다.

# 저장소를 클론합니다
$ git clone https://github.com/electron/electron-quick-start
# 저장소 안으로 들어갑니다
$ cd electron-quick-start
# 애플리케이션의 의존성 모듈을 설치한 후 실행합니다
$ npm install && npm start

더 많은 예시 앱을 보려면 대단한 Electron 커뮤니티에 의해 만들어진 보일러플레이트 리스트를 참고하세요.


REPL

Read-Eval-Print-Loop (REPL) 은 단일 사용자 입력 (즉, 하나의 표현) 을 받아서, 평가하고, 사용자에게 결과를 반환하는 간단한 대화형 컴퓨터 프로그래밍 환경입니다.

repl 모듈은 REPL 구현을 제공하며 다음과 같이 접근할 수 있습니다:

이것은 메인 프로세스에 대한 REPL 만 생성합니다. 렌더러 프로세스를 위한 REPL 을 얻기 위해 개발자 도구의 콘솔 탭을 사용할 수 있습니다.

참고: electron --interactive 는 Windows 에서 사용할 수 없습니다.

자세한 정보는 Node.js REPL 문서를 참고하세요.


보안, 네이티브 호환성, 그리고 신뢰성

웹 개발자로써, 우리는 일반적으로 브라우저의 강력한 웹 보안을 잘 이용해왔습니다 - 작성한 코드에 관련된 보안 문제는 아주 적었습니다. 우리는 웹 사이트의 샌드박스안에서 허용된 상당히 제한된 권한과 기능에 의존해왔으며, 우리는 새로운 보안 위협에 대해 발 빠르게 대응할 수 있는 엔지니어들로 이루어진 커다란 팀으로부터 만들어진 브라우저를 사용자들이 마음 놓고 즐길 것이라고 믿어왔습니다.

하지만 Electron을 사용하여 작업한다면, Electron은 웹 브라우저가 아니라는 것을 기억해 두어야 합니다. Electron은 친근한 웹 기술을 사용하여 풍부한 기능의 데스크톱 애플리케이션을 만들 수 있도록 해주지만 그만큼 코드가 더 큰 힘을 사용합니다. JavaScript가 파일 시스템, 유저 쉘, 그외 여러가지 기능에 접근할 수 있습니다. 이러한 능력은 높은 퀄리티를 가진 네이티브 애플리케이션을 개발할 수 있도록 해주지만 코드에 부여된 추가적인 기능만큼 고유한 보안 문제가 발생할 가능성이 있습니다.

이를 염두해두고, 신뢰할 수 없는 출처의 임의의 콘텐츠를 표시할 때 Electron에서 자체적으로 처리하지 않는 심각한 보안 문제를 야기할 수 있다는 점을 주의해야 합니다. 실제로도, 가장 유명한 Electron 애플리케이션들은 (Atom, Slack, Visual Studio Code, 등) 주로 로컬 콘텐츠를 (또는 Node 통합이 제외된 신뢰된, 보안된 원격 콘텐츠) 사용합니다 - 만약 애플리케이션이 온라인 출처에서 가져온 코드를 실행한다면, 그 코드가 악성 코드가 아닌지 판별하는 것은 본인의 책임입니다.

Chromium 보안 문제와 업그레이드

Electron이 새로운 버전의 Chromium을 가능한 한 빠르게 지원하려고 노력하지만, 개발자는 이러한 업그레이딩 작업은 매우 힘든 작업이라는 것을 알아야 합니다 - 각 관련된 수십에서 심지어 백자리 개수의 파일들을 손수 수정해야 합니다. 주어진 자원과 현재 기여도를 생각한다면, Electron은 항상 최신 버전의 Chromium을 유지하지 못할 수 있으며, 며칠부터 몇 주까지 더 걸릴 수 있습니다.

현재 Chromium 구성 요소를 업데이트하는 시스템은 우리가 사용할 수 있는 자원과 이 프레임워크를 기반으로 구축된 대부분의 애플리케이션이 요구하는 것 사이에서 적절한 균형을 유지하고 있다고 느끼고 있습니다. 우리는 확실히 Electron 위에 무언가를 만드는 사람들의 사용 사례에 대한 자세한 내용을 듣는 것에 관심이 있습니다. 이러한 노력을 지원하는 Pull request와 기여는 언제나 환영합니다.

위 조언 무시하기

원격 위치에서 받아온 코드를 로컬에서 실행하는 경우 언제나 보안 문제가 존재합니다. 예를 들어, 원격 웹 사이트가 브라우저 윈도우에서 표시될 때를 생각해볼 때, 만약 공격자가 어떠한 방법으로 웹 페이지의 콘텐츠를 변경하는 경우 (소스를 직접적으로 공격하거나 애플리케이션과 실질적인 위치 사이에서 공격하는 등), 공갹자는 사용자의 기기에서 네이티브 코드를 실행할 수 있습니다.

:warning: 어떠한 상황에서도 원격 코드를 로드하고 실행할 땐 Node 통합 기능을 비활성화하고, 로컬 파일만 (애플리케이션 패키지 내부에 포함된) Node 코드를 실행시킬 수 있도록 하는 것이 좋습니다. 원격 콘텐츠를 표시할 땐, 항상 webview를 사용하고 nodeIntegration이 비활성화되어있는지 확인하세요.

체크 리스트

이 리스트는 완벽하지 않습니다, 하지만 최소한 다음 사항은 확인하는 것이 좋습니다:

다시 말하지만, 이 리스트는 그저 위험을 최소화할 뿐이며 완전히 제거하지 않습니다. 만약 목적이 그저 웹 사이트를 보여주는 것이라면 일반 웹 브라우저가 더 안전한 방법입니다.


지원하는 플랫폼

Electron에선 다음과 같은 플랫폼을 지원합니다:

macOS

macOS는 64비트 바이너리만 제공됩니다. 그리고 최소 macOS 지원 버전은 10.9입니다.

Windows

Windows 7 이후 버전만 지원됩니다. Windows Vista에서도 작동할 수 있지만 아직 모든 작동 테스트가 완료되지 않았습니다.

윈도우용 바이너리는 x86x64 모두 제공됩니다. 그리고 ARM 버전 윈도우는 아직 지원하지 않습니다.

Linux

Ubuntu 12.04 버전에서 빌드된 ia32(i686), x64(amd64) 바이너리가 제공됩니다. 그리고 arm 버전 바이너리는 ARM v7 hard-float ABI와 Debian Wheezy용 NEON에 맞춰 제공됩니다.

미리 빌드된 바이너리가 배포판에서 작동할 수 있는지 여부는 Electron이 빌드된 플랫폼에서 링크된 라이브러리에 따라 달라집니다. 그래서 현재 Linux 바이너리는 Ubuntu 12.04 버전만 정상적인 작동이 보장됩니다. 하지만 다음 플랫폼들은 미리 빌드된 Electron 바이너리가 정상적으로 작동하는 것을 확인했습니다:


Headless CI 시스템에서 테스팅하기 (Travis, Jenkins)

Chromium을 기반으로 한 Electron은 작업을 위해 디스플레이 드라이버가 필요합니다. 만약 Chromium이 디스플레이 드라이버를 찾기 못한다면, Electron은 그대로 실행에 실패할 것입니다. 따라서 실행하는 방법에 관계없이 모든 테스트를 실행하지 못하게 됩니다. Electron 기반 애플리케이션을 Travis, Circle, Jenkins 또는 유사한 시스템에서 테스팅을 진행하려면 약간의 설정이 필요합니다. 요점만 말하자면, 가상 디스플레이 드라이버가 필요합니다.

가상 디스플레이 드라이버 설정

먼저, Xvfb를 설치합니다. 이것은 X11 디스플레이 서버 프로토콜의 구현이며 모든 그래픽 작업을 스크린 출력없이 인-메모리에서 수행하는 가상 프레임버퍼입니다. 정확히 우리가 필요로 하는 것입니다.

그리고, 가상 xvfb 스크린을 생성하고 DISPLAY라고 불리우는 환경 변수를 지정합니다. Electron의 Chromium은 자동적으로 $DISPLAY 변수를 찾습니다. 따라서 앱의 추가적인 다른 설정이 필요하지 않습니다. 이러한 작업은 Paul Betts의 xvfb-maybe를 통해 자동화 할 수 있습니다: xvfb-maybe를 테스트 커맨드 앞에 추가하고 현재 시스템에서 요구하면 이 작은 툴이 자동적으로 xvfb를 설정합니다. Windows와 macOS에선 간단히 아무 작업도 하지 않습니다.

## Windows와 macOS에선, 그저 electron-mocha를 호출합니다
## Linux에선, 현재 headless 환경에 있는 경우
## xvfb-run electron-mocha ./test/*.js와 같습니다
xvfb-maybe electron-mocha ./test/*.js

Travis CI

Travis에선, .travis.yml이 대충 다음과 같이 되어야 합니다:

addons:
  apt:
    packages:
      - xvfb

install:
  - export DISPLAY=':99.0'
  - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &

Jenkins

Jenkins는 Xvfb 플러그인이 존재합니다.

Circle CI

Circle CI는 멋지게도 이미 xvfb와 $DISPLY 변수가 준비되어 있습니다. 따라서 추가적인 설정이 필요하지 않습니다.

AppVeyor

AppVeyor는 Windows에서 작동하기 때문에 Selenium, Chromium, Electron과 그 비슷한 툴들을 복잡한 과정 없이 모두 지원합니다. - 설정이 필요하지 않습니다.


네이티브 Node 모듈 사용하기

Electron에선 네이티브 Node 모듈을 지원합니다. 하지만 Electron이 시스템에 설치된 Node의 버전과 전혀 다른 V8 버전을 사용하고 있을 가능성이 높은 관계로, 네이티브 모듈을 빌드할 때 Electron의 헤더를 수동으로 지정해 주어야 합니다.

네이티브 모듈을 설치하는 방법

네이티브 모듈을 설치하는 방법에는 세 가지 방법이 있습니다:

npm 사용하기

몇 가지 환경 변수를 설치하는 것으로, 직접적으로 npm을 모듈을 설치하는데 사용할 수 있습니다.

다음 예시는 Electron에 대한 모든 의존성을 설치하는 예시입니다:

# Electron의 버전.
export npm_config_target=1.2.3
# Electron의 아키텍쳐, ia32 또는 x64가 될 수 있습니다.
export npm_config_arch=x64
export npm_config_target_arch=x64
# Electron에 대한 헤더 다운로드 링크.
export npm_config_disturl=https://atom.io/download/atom-shell
# node-pre-gyp에 Electron을 빌드한다는 것을 알려줍니다.
export npm_config_runtime=electron
# node-pre-gyp에 소스 코드로부터 모듈을 빌드한다는 것을 알려줍니다.
export npm_config_build_from_source=true
# 모든 의존성을 설치하고 캐시를 ~/.electron-gyp에 저장합니다.
HOME=~/.electron-gyp npm install

모듈을 설치하고 Electron을 위해 다시 빌드하기

다른 Node 프로젝트와 같이 모듈을 설치하는 것을 선택할 수도 있습니다. 그리고 electron-rebuild 패키지와 함께 Electron에 대해 모듈을 다시 빌드할 수 있습니다. 이 모듈은 Electron의 버전을 가져올 수 있고 헤더를 다운로드 하거나 네이티브 모듈을 빌드하는 등의 작업을 자동으로 실행할 수 있습니다.

다음 예시는 electron-rebuild을 설치하고 자동으로 모듈을 빌드하는 예시입니다:

npm install --save-dev electron-rebuild

# "npm install"을 실행할 때마다 다음 명령을 실행하세요:
./node_modules/.bin/electron-rebuild

# Windows에서 문제가 발생하면 다음 명령을 대신 실행하세요:
.\node_modules\.bin\electron-rebuild.cmd

역자주: npm scriptpostinstall을 사용하면 이 작업을 자동화 할 수 있습니다.

Electron을 위해 직접적으로 빌드하기

현재 본인이 네이티브 모듈을 개발하고 있는 개발자이고 Electron에 대해 실험하고 싶다면, 직접적으로 모듈을 Electron에 대해 다시 빌드하고 싶을 것입니다. node-gyp를 통해 직접적으로 Electron에 대해 빌드할 수 있습니다.

cd /path-to-module/
HOME=~/.electron-gyp node-gyp rebuild --target=1.2.3 --arch=x64 --dist-url=https://atom.io/download/atom-shell

HOME=~/.electron-gyp은 변경할 헤더의 위치를 찾습니다. --target=0.29.1은 Electron의 버전입니다. --dist-url=...은 헤더를 다운로드 하는 주소입니다. --arch=x64는 64비트 시스템을 타겟으로 빌드 한다는 것을 node-gyp에게 알려줍니다.

문제 해결

네이티브 모듈을 설치했는데 잘 작동하지 않았다면, 다음 몇 가지를 확인해봐야 합니다:

모듈이 node-pre-gyp에 의존합니다

node-pre-gyp은 미리 빌드된 바이너리와 함께 네이티브 Node 모듈을 배치하는 방법을 제공하며 수 많은 유명한 모듈들이 이를 사용합니다.

보통 이 모듈은 Electron과 함께 잘 작동하지만, Electron이 Node보다 새로운 V8 버전을 사용할 때, 만약 ABI가 변경되었다면, 때때로 안 좋은 일이 일어납니다. 그래서 일반적으론 언제나 네이티브 모듈의 소스 코드를 가져와서 빌드하는 것을 권장합니다.

npm을 통한 방법을 따르고 있다면, 기본적으로 이 소스를 받아와서 빌드합니다. 만약 그렇지 않다면, npm--build-from-source를 전달해 주어야 합니다. 아니면 npm_config_build_from_source를 환경 변수에 설정하는 방법도 있습니다.


Pepper 플래시 플러그인 사용하기

Electron은 Pepper 플래시 플러그인을 지원합니다. Electron에서 Pepper 플래시 플러그인을 사용하려면 Pepper 플래시 플러그인의 위치를 지정한 후 애플리케이션 내에서 활성화 시켜야 합니다.

플래시 플러그인 준비하기

크롬 브라우저의 chrome://plugins 페이지에 접속한 후 세부정보에서 플래시 플러그인의 위치와 버전을 찾을 수 있습니다. Electron에서 플래시 플러그인을 지원하기 위해선 이 두 가지를 복사해 와야 합니다.

Electron 스위치 추가

플러그인을 사용하려면 Electron 커맨드 라인에 --ppapi-flash-path--ppapi-flash-version 플래그를 appready 이벤트가 발생하기 전에 추가해야 합니다. 그리고 browser-windowplugins 옵션을 활성화해야 합니다.

예를 들면:

// 플래시 플러그인의 위치를 설정합니다. main.js와 위치가 같다고 가정할 때:
let pluginName
switch (process.platform) {
  case 'win32':
    pluginName = 'pepflashplayer.dll'
    break
  case 'darwin':
    pluginName = 'PepperFlashPlayer.plugin'
    break
  case 'linux':
    pluginName = 'libpepflashplayer.so'
    break
}

app.commandLine.appendSwitch('ppapi-flash-path', path.join(__dirname, pluginName))

// 선택적인으로 플래시 플레이어의 버전을 설정합니다. 예시로는, v17.0.0.169
app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169')

app.on('ready', () => {
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      plugins: true
    }
  })
  win.loadURL(`file://${__dirname}/index.html`)
  // 이외의 코드
})

직접 플러그인을 삽입하는 대신 시스템의 Pepper Flash 플러그인을 사용할 수도 있습니다. 시스템상의 플러그인의 경로는 app.getPath('pepperFlashSystemPlugin')로 불러올 수 있습니다.

<webview> 태그를 이용하여 플러그인을 활성화

plugins 속성을 <webview> 태그에 추가합니다.

<webview src="http://www.adobe.com/software/flash/about/" plugins></webview>

문제 해결

개발자 도구의 콘솔에서 navigator.plugins를 탐색하면 Pepper 플래시 플러그인이 잘 로드되었는지를 확인할 수 있습니다. (물론 플러그인의 경로를 잘 설정하지 않으면 확인할 수 없습니다)

Pepper 플래시 플러그인의 구조는 Electron과 일치해야 합니다. Windows에서 자주 발생하는 문제는 32비트 버전의 플래시 플레이어를 64비트 버전의 Electron에서 사용하는 것입니다.

Windows에선 --ppapi-flash-path로 전달되는 경로의 분리자로 \를 사용해야 합니다. POSIX-스타일 경로는 작동하지 않을 것입니다.


Selenium 과 WebDriver 사용하기

ChromeDriver - WebDriver for Chrome로부터 인용:

WebDriver는 많은 브라우저에서 웹 앱을 자동적으로 테스트하는 툴입니다. 이 툴킷은 웹 페이지를 자동으로 탐색하고 유저 폼을 사용하거나 자바스크립트를 실행하는 등의 작업을 수행할 수 있습니다. ChromeDriver는 Chromium의 WebDriver wire 프로토콜 스텐드얼론 서버 구현입니다. Chromium 과 WebDriver 팀 멤버에 의해 개발되었습니다.

Spectron 설정하기

Spectron은 공식적으로 지원하는 Electron을 위한 ChromeDriver 테스팅 프레임워크입니다. 이는 WebdriverIO를 기반으로 만들어졌고, 테스트에서 Electron API에 접근하기 위한 헬퍼를 가지고 있으며 ChromeDriver를 포함하고 있습니다.

$ npm install --save-dev spectron
// 윈도우가 제목과 함께 보이는지 검증하는 간단한 테스트.
var Application = require('spectron').Application
var assert = require('assert')

var app = new Application({
  path: '/Applications/MyApp.app/Contents/MacOS/MyApp'
})

app.start().then(function () {
  // 윈도우가 보이는지 확인합니다.
  return app.browserWindow.isVisible()
}).then(function (isVisible) {
  // 윈도우가 보이는지 검증합니다.
  assert.equal(isVisible, true)
}).then(function () {
  // 윈도우의 제목을 가져옵니다.
  return app.client.getTitle()
}).then(function (title) {
  // 윈도우의 제목을 검증합니다.
  assert.equal(title, 'My App')
}).catch(function (error) {
  // 테스트의 실패가 있다면 로깅합니다.
  console.error('Test failed', error.message)
}).then(function () {
  // 애플리케이션을 중지합니다.
  return app.stop()
})

WebDriverJs 설정하기

WebDriverJs는 WebDriver를 사용하여 테스트 할 수 있도록 도와주는 node 패키지입니다. 다음 예시를 참고하세요.

1. 크롬 드라이버 시작

먼저, chromedriver 바이너리를 다운로드 받고 실행합니다:

$ npm install electron-chromedriver
$ ./node_modules/.bin/chromedriver
Starting ChromeDriver (v2.10.291558) on port 9515
Only local connections are allowed.

포트 9515는 나중에 사용하므로 기억해 놓습니다.

2. WebDriverJS 설치

$ npm install selenium-webdriver

3. 크롬 드라이버에 연결

selenium-webdriver를 Electron과 같이 사용하는 방법은 기본적으로 upstream과 같습니다. 한가지 다른점이 있다면 수동으로 크롬 드라이버 연결에 대해 설정하고 Electron 실행파일의 위치를 전달합니다:

const webdriver = require('selenium-webdriver')

const driver = new webdriver.Builder()
  // 작동하고 있는 크롬 드라이버의 포트 "9515"를 사용합니다.
  .usingServer('http://localhost:9515')
  .withCapabilities({
    chromeOptions: {
      // 여기에 사용중인 Electron 바이너리의 경로를 지정하세요.
      binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
    }
  })
  .forBrowser('electron')
  .build()

driver.get('http://www.google.com')
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
driver.findElement(webdriver.By.name('btnG')).click()
driver.wait(() => {
  return driver.getTitle().then((title) => {
    return title === 'webdriver - Google Search'
  })
}, 1000)

driver.quit()

WebdriverIO 설정하기

WebdriverIO는 웹 드라이버와 함께 테스트를 위해 제공되는 node 패키지입니다.

1. 크롬 드라이버 시작

먼저, chromedriver 바이너리를 다운로드 받고 실행합니다:

$ npm install electron-chromedriver
$ ./node_modules/.bin/chromedriver --url-base=wd/hub --port=9515
Starting ChromeDriver (v2.10.291558) on port 9515
Only local connections are allowed.

포트 9515는 나중에 사용하므로 기억해 놓읍시다

2. WebDriverIO 설치

$ npm install webdriverio

3. 크롬 드라이버에 연결

const webdriverio = require('webdriverio')
let options = {
  host: 'localhost', // localhost에서 작동중인 크롬 드라이버 서버를 사용합니다.
  port: 9515,        // 연결할 크롬 드라이버 서버의 포트를 설정합니다.
  desiredCapabilities: {
    browserName: 'chrome',
    chromeOptions: {
      binary: '/Path-to-Your-App/electron', // Electron 바이너리 경로
      args: [/* cli arguments */]           // 선택 사항, 'app=' + /path/to/your/app/
    }
  }
}

let client = webdriverio.remote(options)

client
  .init()
  .url('http://google.com')
  .setValue('#q', 'webdriverio')
  .click('#btnG')
  .getTitle().then((title) => {
    console.log('Title was: ' + title)
  })
  .end()

작업 환경

따로 Electron을 다시 빌드하지 않는 경우 간단히 애플리케이션을 Electron의 리소스 디렉터리에 배치하여 바로 테스트 할 수 있습니다.

또한, Electron 바이너리의 명령줄 인수에 애플리케이션 폴더를 지정하는 방법으로 실행할 수도 있습니다. 이 방법을 사용하면 애플리케이션 폴더를 Electron의 resource 디렉터리로 복사하는 불필요한 과정을 생략할 수 있습니다.


Widevine CDM 플러그인 사용하기

Electron에선 Chrome 브라우저에서 취득해온 Widevine CDM 플러그인을 사용할 수 있습니다.

플러그인 취득

Electron은 라이센스상의 문제로 Widevine CDM 플러그인을 직접 제공하지 않습니다. 따라서 플러그인을 얻으려면 먼저 사용할 Electron 빌드의 아키텍쳐와 버전에 맞춰 공식 Chrome 브라우저를 설치해야 합니다.

참고: Chrome 브라우저의 메이저 버전은 Electron에서 사용하는 Chrome 버전과 같습니다, 만약 그렇지 않다면 navigator.plugins가 로드됐더라도 정상적으로 작동하지 않습니다.

Windows & macOS

Chrome 브라우저에서 chrome://components/를 열고 WidevineCdm을 찾은 후 확실히 최신버전인지 확인합니다. 여기까지 하면 모든 플러그인 바이너리를 APP_DATA/Google/Chrome/WidevineCDM/VERSION/_platform_specific/PLATFORM_ARCH/ 디렉터리에서 찾을 수 있습니다.

APP_DATA는 애플리케이션 데이터를 저장하고 있는 시스템 경로입니다. Windows에선 %LOCALAPPDATA%로 접근할 수 있고 macOS에선 ~/Library/Application Support로 접근할 수 있습니다. VERSION1.4.8.866 같은 Widevine CDM 플러그인의 버전 문자열입니다. PLATFORM은 플랫폼을 뜻하며 mac 또는 win이 될 수 있으며 ARCH는 아키텍쳐를 뜻하고 x86 또는 x64가 될 수 있습니다.

Windows에선 widevinecdm.dllwidevinecdmadapter.dll 같은 바이너리를 요구하며 macOS에선 libwidevinecdm.dylibwidevinecdmadapter.plugin 바이너리를 요구합니다. 원하는 곳에 이들을 복사해 놓을 수 있습니다. 하지만 반드시 바이너리는 같은 위치에 두어야 합니다.

Linux

Linux에선 플러그인 바이너리들이 Chrome 브라우저와 함께 제공됩니다. /opt/google/chrome 경로에서 찾을 수 있으며, 파일 이름은 libwidevinecdm.solibwidevinecdmadapter.so입니다.

플러그인 사용

플러그인 파일을 가져온 후, Electron의 --widevine-cdm-path 커맨드 라인 스위치에 widevinecdmadapter의 위치를 전달하고 플러그인의 버전을 --widevine-cdm-version 스위치에 전달해야 합니다.

참고: widevinecdmadapter 바이너리가 Electron으로 전달되어도, widevinecdm 바이너리는 옆에 같이 두어야 합니다.

커맨드 라인 스위치들은 app 모듈의 ready 이벤트가 발생하기 전에 전달되어야 합니다. 그리고 이 플러그인을 사용하는 페이지는 플러그인(속성)이 활성화되어있어야 합니다.

예시 코드:

// `widevinecdmadapter`의 파일 이름을 이곳에 전달해야 합니다. 파일 이름은
// * macOS에선 `widevinecdmadapter.plugin`로 지정합니다,
// * Linux에선 `libwidevinecdmadapter.so`로 지정합니다,
// * Windows에선 `widevinecdmadapter.dll`로 지정합니다.
app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevinecdmadapter.plugin')
// 플러그인의 버전은 크롬의 `chrome://plugins` 페이지에서 취득할 수 있습니다.
app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866')

let win = null
app.on('ready', () => {
  win = new BrowserWindow({
    webPreferences: {
      // `plugins`은 활성화되어야 합니다.
      plugins: true
    }
  })
})

플러그인 작동 확인

플러그인 정상적으로 작동하는지 확인하려면 다음과 같은 방법을 사용할 수 있습니다:


Windows 스토어 가이드

Windows 8부터, 오래되고 좋은 win32 실행 파일이 새로운 형제를 얻었습니다: Universial Windows Platform. 새로운 .appx 포맷은 Cortana와 푸시 알림과 같은 다수의 강력한 API뿐만 아니라, Windows Store를 통해 설치와 업데이트를 단순화합니다.

Microsoft는 개발자들이 새로운 애플리케이션 모델의 좋은 기능들을 사용할 수 있도록 Electron 애플리케이션을 .appx 패키지로 컴파일시키는 도구를 개발했습니다. 이 가이드는 이 도구를 사용하는 방법과 Electron AppX 패키지의 호환성과 한정 사항을 설명합니다.

기본 상식과 요구 사항

Windows 10 “기념일 업데이트”는 win32 .exe 바이너리를 가상화된 파일 시스템과 레지스트리를 함께 실행시킬 수 있도록 만들었습니다. 두 가지 모두 실행 중인 애플리케이션과 Windows 컨테이너 안의 인스톨러에 의해 컴파일되는 동안 만들어지며, 설치가 되는 동안 Windows가 확실하게 어떤 변경 사항이 운영 체제에 적용되는지 식별할 수 있도록 합니다. 가상 파일 시스템과 가상 레지스트리를 페어링 하는 실행 파일은 Windows가 한 번의 클릭으로 설치와 삭제를 할 수 있도록 만듭니다.

더 나아가서, exe는 appx 모델 안에서 실행됩니다 - 이 말은 즉 Universial Windows Platform에서 제공되는 수많은 API를 사용할 수 있다는 이야기입니다. 더 많은 기능을 사용하기 위해, Electron 애플리케이션은 백그라운드로 실행된 UWP 앱과 페어링 하여 exe와 같이 실행할 수 있습니다 - 이렇게 헬퍼와 비슷하게 실행되고 작업을 실행하기 위해 백그라운드에서 작동하며, 푸시 알림을 받거나, 다른 UWP 애플리케이션과 통신하는 역할을 합니다.

현재 존재하는 Electron 애플리케이션을 컴파일 하려면, 다음 요구 사항을 충족해야 합니다:

그리고 CLI에서 electron-windows-store를 설치합니다:

npm install -g electron-windows-store

Step 1: Electron 어플리케이션 패키징

electron-packager를 사용하여 애플리케이션을 패키징합니다. (또는 비슷한 도구를 사용합니다) 마지막으로 최종 애플리케이션에선 node_modules가 필요 없으며 그저 애플리케이션의 크기를 늘릴 뿐이니 확실하게 지웠는지 확인합니다.

출력된 파일들은 대충 다음과 같아야 합니다:

├── Ghost.exe
├── LICENSE
├── content_resources_200_percent.pak
├── content_shell.pak
├── d3dcompiler_47.dll
├── ffmpeg.dll
├── icudtl.dat
├── libEGL.dll
├── libGLESv2.dll
├── locales
│   ├── am.pak
│   ├── ar.pak
│   ├── [...]
├── natives_blob.bin
├── node.dll
├── resources
│   ├── app
│   └── atom.asar
├── snapshot_blob.bin
├── squirrel.exe
├── ui_resources_200_percent.pak
└── xinput1_3.dll

electron-windows-store 실행하기

관리자 권한의 PowerShell (“관리자 권한으로 실행”)을 실행하고, 디렉토리 입력과 출력, 애플리케이션의 이름과 버전, 마지막으로 node_modules를 평탄화시키는 인수들과 함께 electron-windows-store를 실행합니다.

electron-windows-store `
    --input-directory C:\myelectronapp `
    --output-directory C:\output\myelectronapp `
    --flatten true `
    --package-version 1.0.0.0 `
    --package-name myelectronapp

명령이 실행되면, 도구는 다음과 같이 작동합니다: Electron 애플리케이션을 입력으로 받고, node_modules를 평탄화하고 애플리케이션을 app.zip으로 압축합니다. 그리고 인스톨러와 Windows Container를 사용하여, “확장된” AppX 패키지를 만듭니다 - Windows Application Manifest (AppXManifest.xml)와 동시에 가상 파일 시스템과 가상 레지스트리를 포함하여 출력 폴더로 내보냅니다.

확장된 AppX 파일이 만들어지면, 도구는 Windows App Packager (MakeAppx.exe)를 사용하여 디스크의 파일로부터 단일-파일 AppX 패키지를 생성해냅니다. 최종적으로, 이 도구는 새 AppX 패키지에 서명하기 위해 컴퓨터에서 신뢰된 인증서를 만드는 데 사용할 수 있습니다. 서명된 AppX 패키지로, CLI는 자동으로 기기에 패키지를 설치할 수 있습니다.

Step 3: AppX 패키지 사용하기

일반 사용자들이 패키지를 실행하기 위해서는 “기념일 업데이트” 된 Windows 10 이 필요합니다. - Windows 업데이트 하는 방법은 여기에서 찾을 수 있습니다.

기존 UWP 앱과 반대로, 패키지된 앱은 현재 수동 확인 절차가 필요합니다. 이것은 여기에서 적용할 수 있습니다. 반면에, 사용자는 더블클릭으로 패키지를 설치할 수 있습니다. 더 쉬운 설치 방법을 찾고 있다면, 스토어에 제출하지 않아도 됩니다. (일반적으로 기업과 같은) 관리되는 환경에서는, Add-AppxPackage PowerShell Cmdlet 은 자동화된 방식으로 설치하는데 사용될 수 있습니다.

또 다른 중요한 제약은 컴파일된 AppX 패키지는 여전히 win32 실행 파일이 담겨있다는 것입니다 - 따라서 Xbox, HoloLens, Phone에서 실행할 수 없습니다.

Optional: 백그라운드 작업을 사용하여 UWP 기능 추가

필요하다면 Windows 10의 모든 기능을 사용하기 위해 보이지 않는 UWP 백그라운드 작업과 Electron 앱을 연결할 수 있습니다 - 푸시 알림, 코타나 통합, 라이브 타일등.

Electron 앱이 토스트 알림이나 라이브 타일을 사용할 수 있도록 하는 방법을 알아보려면 Microsoft가 제공하는 샘플을 참고하세요.

Optional: 컨테이너 가상화를 사용하여 변환

AppX 패키지를 만드려면, electron-windows-store CLI를 통해 대부분의 Electron 앱을 그대로 변환할 수 있습니다. 하지만, 커스텀 인스톨러를 사용하고 있거나, 패키지를 생성하는데 어떠한 문제라도 겪고있다면, Windows Container를 사용하여 패키지를 생성하는 시도를 해볼 수 있습니다 - 이 모드를 사용하면, CLI가 어플리케이션이 정확하게 운영체제에 대해 수행하는 작업이 어떤 변경 사항을 만드는지를 결정하기 위해 어플리케이션을 빈 Windows Container에서 설치하고 실행할 것입니다.

처음 CLI를 실행하기 전에, “Windows Desktop App Converter”를 먼저 설정해야 합니다. 이 작업은 약 몇 분 정도 소요됩니다. 하지만 걱정하지 않아도 됩니다 - 이 작업은 딱 한 번만 하면 됩니다. Desktop App Converter는 여기에서 다운로드 받을 수 있고, DesktopAppConverter.zipBaseImage-14316.wim 두 파일을 모두 받아야 합니다.

  1. DesktopAppConverter.zip의 압축을 풉니다. 그다음 PowerShell을 관리자 권한으로 실행하고 압축을 푼 위치로 이동합니다. (실행하는 모든 명령에 “관리자 권한”을 적용하려면 Set-ExecutionPolicy bypass를 실행하면 됩니다)
  2. 그리고, .\DesktopAppConverter.ps1 -Setup -BaseImage .\BaseImage-14316.wim를 실행하여 Windows 베이스 이미지 (BaseImage-14316.wim)를 Desktop App Converter로 전달하고 설치를 진행합니다.
  3. 만약 위 명령이 재시작을 요구하면, 기기를 재시작하고 위 명령을 다시 실행시키세요.

설치가 완료되면, 컴파일할 Electron 애플리케이션 경로로 이동합니다.