23. 主进程模块:app

app 模块是为了控制整个应用的生命周期设计的。

下面的这个例子将会展示如何在最后一个窗口被关闭时退出应用:

var app = require('app');
app.on('window-all-closed', function() {
  app.quit();
});

事件列表

  • will-finish-launching:当应用程序完成基础的启动的时候被触发。
    • 在 Windows 和 Linux 中, will-finish-launching 事件与 ready 事件是相同的; 在 OS X 中, 这个时间相当于 NSApplication 中的 applicationWillFinishLaunching 提示。 你应该经常在这里为 open-fileopen-url 设置监听器,并启动崩溃报告和自动更新。
    • 在大多数的情况下,你应该只在 ready 事件处理器中完成所有的业务。
  • ready:当 Electron 完成初始化时被触发。
  • window-all-closed:当所有的窗口都被关闭时触发。
    • 这个时间仅在应用还没有退出时才能触发。 如果用户按下了 Cmd + Q, 或者开发者调用了 app.quit() ,Electron 将会先尝试关闭所有的窗口再触发 will-quit 事件, 在这种情况下 window-all-closed 不会被触发。
  • before-quit:在应用程序开始关闭它的窗口的时候被触发。
    • 返回:event Event
    • 调用 event.preventDefault() 将会阻止终止应用程序的默认行为。
  • will-quit:当所有的窗口已经被关闭,应用即将退出时被触发。
    • 返回:event Event
    • 调用 event.preventDefault() 将会阻止终止应用程序的默认行为。
    • 你可以在 window-all-closed 事件的描述中看到 will-quit 事件 和 window-all-closed 事件的区别。
  • quit:当应用程序正在退出时触发。
    • 返回:
      • event Event
      • exitCode Integer
  • open-file OS X:当用户想要在应用中打开一个文件时触发。
    • 返回:
      • event Event
      • path String
    • open-file 事件常常在应用已经打开并且系统想要再次使用应用打开文件时被触发。 open-file 也会在一个文件被拖入 dock 且应用还没有运行的时候被触发。 请确认在应用启动的时候(甚至在 ready 事件被触发前)就对 open-file 事件进行监听,以处理这种情况。
    • 如果你想处理这个事件,你应该调用 event.preventDefault() 。 在 Windows系统中, 你需要通过解析 process.argv 来获取文件路径。
  • open-url OS X:当用户想要在应用中打开一个url的时候被触发。
    • 返回:
      • event Event
      • url String
    • URL格式必须要提前标识才能被你的应用打开。
    • 如果你想处理这个事件,你应该调用 event.preventDefault()
  • activate OS X:当应用被激活时触发,常用于点击应用的 dock 图标的时候。
    • 返回:
      • event Event
      • hasVisibleWindows Boolean
  • browser-window-blur:当一个 BrowserWindow 失去焦点的时候触发。
    • 返回:
      • event Event
      • window BrowserWindow
  • browser-window-focus:当一个BrowserWindow 获得焦点的时候触发。
    • 返回:
      • event Event
      • window BrowserWindow
  • browser-window-created:当一个 BrowserWindow 被创建的时候触发。
    • 返回:
      • event Event
      • window BrowserWindow
  • certificate-error:当对 url 验证 certificate 证书失败的时候触发。
    • 返回:
      • event Event
      • webContents WebContents
      • url String - URL 地址
      • error String - 错误码
      • certificate Object
        • data Buffer - PEM 编码数据
        • issuerName String - 发行者的公有名称
      • callback Function
    • 如果需要信任这个证书,你需要阻止默认行为 event.preventDefault() 并且 调用 callback(true)
    • session.on('certificate-error', function(event, webContents, url, error, certificate, callback) {
        if (url == "https://github.com") {
          // 验证逻辑。
          event.preventDefault();
          callback(true);
        } else {
          callback(false);
        }
      });
      
  • select-client-certificate:当一个客户端认证被请求的时候被触发。
    • 返回:
      • event Event
      • webContents WebContents
      • url String - URL 地址
      • certificateList [Object]
        • data Buffer - PEM 编码数据
        • issuerName String - 发行者的公有名称
      • callback Function
    • url 指的是请求客户端认证的网页地址,调用 callback 时需要传入一个证书列表中的证书。
    • 需要通过调用 event.preventDefault() 来防止应用自动使用第一个证书进行验证。如下所示:
      • app.on('select-certificate', function(event, host, url, list, callback) {
          event.preventDefault();
          callback(list[0]);
        })
        
  • login:当 webContents 要做进行一次 HTTP 登陆验证时被触发。
    • 返回:
      • event Event
      • webContents WebContents
      • request Object
        • method String
        • url URL
        • referrer URL
      • authInfo Object
        • isProxy Boolean
        • scheme String
        • host String
        • port Integer
        • realm String
      • callback Function
    • 默认情况下,Electron 会取消所有的验证行为,如果需要重写这个行为,你需要用 event.preventDefault() 来阻止默认行为,并且 用 callback(username, password) 来进行验证。
    • app.on('login', function(event, webContents, request, authInfo, callback) {
        event.preventDefault();
        callback('username', 'secret');
      })
      
  • gpu-process-crashed:当 GPU 进程崩溃时触发。

方法列表

请注意 有的方法只能用于特定的操作系统。

  • app.quit():试图关掉所有的窗口。
    • before-quit 事件将会最先被触发。如果所有的窗口都被成功关闭了, will-quit 事件将会被触发,默认下应用将会被关闭。
    • 这个方法保证了所有的 beforeunloadunload 事件处理器被正确执行。假如一个窗口的 beforeunload 事件处理器返回 false,那么整个应用可能会取消退出。
  • app.hide() OS X:隐藏所有的应用窗口,不是最小化.
  • app.show() OS X:隐藏后重新显示所有的窗口,不会自动选中他们。
  • app.exit(exitCode):所有的窗口会被立刻关闭,不会询问用户。
    • exitCode 整数
    • 带着exitCode退出应用.
    • before-quitwill-quit 这2个事件不会被触发
  • app.getAppPath():返回当前应用所在的文件路径。
  • app.getPath(name):返回一个与 name 参数相关的特殊文件夹或文件路径。
    • name String
    • 当失败时抛出一个 Error
    • 你可以通过名称请求以下的路径:
      • home 用户的 home 文件夹(主目录)
      • appData 当前用户的应用数据文件夹,默认对应:
        • %APPDATA% Windows 中
        • $XDG_CONFIG_HOME or ~/.config Linux 中
        • ~/Library/Application Support OS X 中
      • userData 储存你应用程序设置文件的文件夹,默认是 appData 文件夹附加应用的名称
      • temp 临时文件夹
      • exe 当前的可执行文件
      • module libchromiumcontent
      • desktop 当前用户的桌面文件夹
      • documents 用户文档目录的路径
      • downloads 用户下载目录的路径.
      • music 用户音乐目录的路径.
      • pictures 用户图片目录的路径.
      • videos 用户视频目录的路径.
  • app.setPath(name, path)
    • name String
    • path String
    • 重写某个 name 的路径为 pathpath 可以是一个文件夹或者一个文件,这个和 name 的类型有关。 如果这个路径指向的文件夹不存在,这个文件夹将会被这个方法创建。 如果错误则会抛出 Error
    • name 参数只能使用 app.getPath 中定义过 name
    • 默认情况下,网页的 cookie 和缓存都会储存在 userData 文件夹。 如果你想要改变这个位置,你需要在 app 模块中的 ready 事件被触发之前重写 userData 的路径。
  • app.getVersion():返回加载应用程序的版本。如果应用程序的 package.json 文件中没有写版本号, 将会返回当前包或者可执行文件的版本。
  • app.getName():返回当前应用程序的 package.json 文件中的名称。
    • 由于 npm 的命名规则,通常 name 字段是一个短的小写字符串。但是应用名的完整名称通常是首字母大写的,你应该单独使用一个 productName 字段,用于表示你的应用程序的完整名称。Electron 会优先使用这个字段作为应用名。
  • app.setName(name):重写当前应用的名字
    • name String
  • app.getLocale():返回当前应用程序的语言。
  • app.addRecentDocument(path) OS X Windows
    • path String
    • 在最近访问的文档列表中添加 path
    • 这个列表由操作系统进行管理。在 Windows 中您可以通过任务条进行访问,在 OS X 中你可以通过 dock 菜单进行访问。
  • app.clearRecentDocuments() OS X Windows:清除最近访问的文档列表。
  • app.setUserTasks(tasks) Windows
    • tasks [Task] - 一个由 Task 对象构成的数组
    • tasks 添加到 Windows 中 JumpList 功能的 Tasks 分类中。
    • tasks 中的 Task 对象格式如下:
      • Task Object
        • program String - 执行程序的路径,通常你应该说明当前程序的路径为 process.execPath 字段。
        • arguments String - 当 program 执行时的命令行参数。
        • title String - JumpList 中显示的标题。
        • description String - 对这个任务的描述。
        • iconPath String - JumpList 中显示的图标的绝对路径,可以是一个任意包含一个图标的资源文件。通常来说,你可以通过指明 process.execPath 来显示程序中的图标。
        • iconIndex Integer - 图标文件中的采用的图标位置。如果一个图标文件包括了多个图标,就需要设置这个值以确定使用的是哪一个图标。 如果这个图标文件中只包含一个图标,那么这个值为 0。
  • app.allowNTLMCredentialsForAllDomains(allow)
    • allow Boolean
    • 动态设置是否总是为 HTTP NTLM 或 Negotiate 认证发送证书。通常来说,Electron 只会对本地网络(比如和你处在一个域中的计算机)发 送 NTLM / Kerberos 证书。但是假如网络设置得不太好,可能这个自动探测会失效,所以你可以通过这个接口自定义 Electron 对所有 URL 的行为。
  • app.makeSingleInstance(callback)
    • callback Function
    • 这个方法可以让你的应用在同一时刻最多只会有一个实例,否则你的应用可以被运行多次并产生多个实例。你可以利用这个接口保证只有一个实例正 常运行,其余的实例全部会被终止并退出。
    • 如果多个实例同时运行,那么第一个被运行的实例中 callback 会以 callback(argv, workingDirectory) 的形式被调用。其余的实例 会被终止。 argv 是一个包含了这个实例的命令行参数列表的数组,workingDirectory 是这个实例目前的运行目录。通常来说,我们会用通过将应用在 主屏幕上激活,并且取消最小化,来提醒用户这个应用已经被打开了。
    • appready 事件后,callback 才有可能被调用。
    • 如果当前实例为第一个实例,那么在这个方法将会返回 false 来保证它继续运行。否则将会返回 true 来让它立刻退出。
    • 在 OS X 中,如果用户通过 Finder、open-file 或者 open-url 打开应用,系统会强制确保只有一个实例在运行。但是如果用户是通过 命令行打开,这个系统机制会被忽略,所以你仍然需要靠这个方法来保证应用为单实例运行的。
    • 下面是一个简单的例子。我们可以通过这个例子了解如何确保应用为单实例运行状态。
      • var myWindow = null;
        var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
          // 当另一个实例运行的时候,这里将会被调用,我们需要激活应用的窗口
          if (myWindow) {
            if (myWindow.isMinimized()) myWindow.restore();
            myWindow.focus();
          }
          return true;
        });
        // 这个实例是多余的实例,需要退出
        if (shouldQuit) {
          app.quit();
          return;
        }
        // 创建窗口、继续加载应用、应用逻辑等……
        app.on('ready', function() {
        });
        
  • app.setAppUserModelId(id) Windows:改变当前应用的 Application User Model IDid.
    • id String
  • app.isAeroGlassEnabled() Windows
    • 如果 DWM composition(Aero Glass) 启用 了,那么这个方法会返回 true,否则是 false。你可以用这个方法来决定是否要开启透明窗口特效,因为如果用户没开启 DWM,那么透明窗 口特效是无效的。
    • 举个例子:
      • let browserOptions = {width: 1000, height: 800};
        // 只有平台支持的时候才使用透明窗口
        if (process.platform !== 'win32' || app.isAeroGlassEnabled()) {
          browserOptions.transparent = true;
          browserOptions.frame = false;
        }
        // 创建窗口
        win = new BrowserWindow(browserOptions);
        // 转到某个网页
        if (browserOptions.transparent) {
          win.loadURL('file://' + __dirname + '/index.html');
        } else {
          // 没有透明特效,我们应该用某个只包含基本样式的替代解决方案。
          win.loadURL('file://' + __dirname + '/fallback.html');
        }
        
  • app.commandLine.appendSwitch(switch[, value]):通过可选的参数 value 给 Chromium 中添加一个命令行开关。
    • 注意 这个方法不会影响 process.argv,我们通常用这个方法控制一些底层 Chromium 行为。
  • app.commandLine.appendArgument(value):给 Chromium 中直接添加一个命令行参数,这个参数 value 的引号和格式必须正确。
    • 注意 这个方法不会影响 process.argv
  • app.dock.bounce([type]) OS X
    • type String - 可选参数,可以是 criticalinformational。默认为 informational
    • 当传入的是 critical 时,dock 中的应用将会开始弹跳,直到这个应用被激活或者这个请求被取消。
    • 当传入的是 informational 时,dock 中的图标只会弹跳一秒钟。但是,这个请求仍然会激活,直到应用被激活或者请求被取消。
    • 这个方法返回的返回值表示这个请求的 ID。
  • app.dock.cancelBounce(id) OS X:取消这个 id 对应的请求。
    • id Integer
  • app.dock.setBadge(text) OS X:设置应用在 dock 中显示的字符串。
    • text String
  • app.dock.getBadge() OS X:返回应用在 dock 中显示的字符串。
  • app.dock.hide() OS X:隐藏应用在 dock 中的图标。
  • app.dock.show() OS X:显示应用在 dock 中的图标。
  • app.dock.setMenu(menu) OS X
    • menu 菜单
    • 设置应用的 dock 菜单.
  • app.dock.setIcon(image) OS X
    • image NativeImage
    • 设置应用在 dock 中显示的图标。
下一节:几个 Electron 开发过程中常见的问题及解答