You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron技术问询:exe/dmg提取触发事件及用户Token获取方案

Solution for Embedding User-Specific Tokens in Electron App Installers

Great question! Handling per-user tokens without rebuilding your Electron app for every user is a smart approach, and modifying the installer filename is a clever workaround. Let’s break down how to make this work across Windows (exe) and macOS (dmg), plus cover your questions about events and post-extraction actions.

1. Triggering Actions During Install/Extraction

The ability to hook into events depends on the installer type you’re using (Electron Builder is the most common tool here):

Windows (NSIS/WiX Installers)

  • NSIS (the default for Electron Builder) lets you run custom scripts before, during, or after installation. You can access the installer’s filename directly in the script to extract the token, then run any follow-up logic.
  • WiX installers support similar custom actions, though NSIS is more straightforward for quick scripted tasks.

macOS (DMGs)

  • macOS doesn’t natively trigger events when a DMG is mounted or the app is copied to Applications. Instead, you’ll want to handle this on the app’s first launch: check if the token exists in your config, and if not, attempt to extract it from the DMG’s name (if the app is still running from the mounted DMG) or fall back to a backup method.

2. Extracting the Token from the Filename

Windows NSIS Script Example

If your installer filename follows a format like MyApp-{token}.exe, add this to your Electron Builder nsis configuration (in package.json or electron-builder.yml):

"nsis": {
  "include": "installer-script.nsh"
}

Then create installer-script.nsh with this logic to extract and save the token:

; Get the full path of the installer exe
StrCpy $installerPath $EXEPATH
; Extract the filename (e.g., "MyApp-xyz123.exe")
StrCpy $installerName $installerPath -1 -1
; Split the filename to isolate the token
StrSplit $installerName "-" $prefix $tokenWithExt
StrSplit $tokenWithExt "." $token $ext
; Save the token to the app's config file in the installation directory
WriteIniStr "$INSTDIR\config.json" "user" "token" $token

macOS First-Launch Logic

In your main Electron process, add code to check for the token on first run:

const { app, dialog } = require('electron');
const fs = require('fs');
const path = require('path');

app.on('ready', async () => {
  const configPath = path.join(app.getPath('userData'), 'app-config.json');
  let appConfig = fs.existsSync(configPath) ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : {};

  // Skip if token already exists
  if (appConfig.userToken) {
    console.log('Using existing token:', appConfig.userToken);
    return;
  }

  // Try to extract token from DMG mount directory (if app is running from DMG)
  const appExecPath = app.getPath('exe');
  const appDir = path.dirname(appExecPath);
  let userToken = null;

  if (appDir.startsWith('/Volumes/')) {
    const dmgMountName = path.basename(appDir);
    // Assume DMG name format: "MyApp-xyz123.dmg"
    const nameParts = dmgMountName.split('-');
    if (nameParts.length > 1) {
      userToken = nameParts[1].split('.')[0];
    }
  }

  if (userToken) {
    // Save token to config
    appConfig.userToken = userToken;
    fs.writeFileSync(configPath, JSON.stringify(appConfig, null, 2));
    console.log('Token extracted and saved:', userToken);
    // Run post-extraction actions here (see section 3)
    await postTokenActions(userToken);
  } else {
    // Fallback: prompt user to enter token if extraction fails
    const inputResult = await dialog.showMessageBox({
      type: 'info',
      message: 'Enter your unique token:',
      buttons: ['Save', 'Cancel'],
      defaultId: 0,
      inputPlaceholder: 'Your token here'
    });

    if (inputResult.response === 0 && inputResult.inputValue) {
      appConfig.userToken = inputResult.inputValue;
      fs.writeFileSync(configPath, JSON.stringify(appConfig, null, 2));
      await postTokenActions(inputResult.inputValue);
    }
  }
});

// Example post-extraction actions
async function postTokenActions(token) {
  // 1. Update a JSON config file
  const appSettingsPath = path.join(app.getAppPath(), 'settings.json');
  let settings = fs.existsSync(appSettingsPath) ? JSON.parse(fs.readFileSync(appSettingsPath)) : {};
  settings.authenticated = true;
  settings.token = token;
  fs.writeFileSync(appSettingsPath, JSON.stringify(settings, null, 2));

  // 2. Send token to your server for validation/registration
  try {
    await fetch('https://your-server.com/api/register', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token, deviceId: app.getVersion() })
    });
  } catch (err) {
    console.error('Failed to register token:', err);
  }

  // 3. Download user-specific assets (e.g., custom themes)
  // const assetResponse = await fetch(`https://your-server.com/assets/${token}`);
  // const assetData = await assetResponse.buffer();
  // fs.writeFileSync(path.join(app.getPath('documents'), 'user-asset.zip'), assetData);
}

3. Supported Post-Extraction Actions

Yes, you can absolutely do all the actions you mentioned:

  • Update JSON files: Use Node.js’s fs module to write to config files in the app’s userData directory (safe for user-specific data) or the app’s installation directory (note: on macOS, the installation directory is read-only for non-admin users, so use userData instead).
  • Push data to your server: Use fetch or libraries like axios to send the token and any other user/device info to your backend for validation or registration.
  • Download user-specific files: Fetch assets from your server using the token as an identifier, then save them to a user-accessible directory (like documents or userData).

Key Considerations

  • Filename tampering: Users might rename the installer, so always validate the token with your server after extracting it to prevent malicious use.
  • Portable Windows apps: If you distribute portable exes (not installers), you can read the exe’s filename directly via path.basename(process.execPath) in your Electron main process.
  • Fallback mechanism: Always include a backup way to get the token (like a user input prompt) in case filename extraction fails.

内容的提问来源于stack exchange,提问作者Sarah Sh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:34:05