Uniapp+Electron打包桌面应用加设备授权
Electron应用里加个激活码验证框
给桌面应用加个简单授权,不想搞复杂后端。直接在Electron启动时弹窗验证,验证通过存本地,下次跳过。顺便把码传给里面的Uniapp页面。
一、主要思路
Electron启动时弹窗收激活码,验证通过存本地文件(userData目录),后续读取跳过弹窗;同时将激活码作为参数传给Uniapp页面。
二、Electron主进程怎么做(弹窗、存文件、传参数)
核心代码放main.js,按启动流程走:
1. 工具函数(存读激活码)
const { app, BrowserWindow, dialog } = require('electron');const fs = require('fs');const path = require('path');// 激活码存储路径(用户目录,无权限问题)const ACTIVATION_PATH = path.join(app.getPath('userData'), 'activation.json');// 读本地激活码(注意:文件不存在或解析失败返回null)function getLocalCode() {try {if (fs.existsSync(ACTIVATION_PATH)) {const data = fs.readFileSync(ACTIVATION_PATH, 'utf8');const { code, isVerified } = JSON.parse(data);return isVerified ? code : null;}} catch (err) { console.error('读激活码失败:', err); }return null;}// 存激活码(注意:默认验证通过,实际需加后端校验)function saveCode(code) {try {fs.writeFileSync(ACTIVATION_PATH, JSON.stringify({code,isVerified: true, // 实际这里应调用后端接口验证后设为truetime: Date.now()}), 'utf8');return true;} catch (err) { console.error('存激活码失败:', err); }return false;}
2. 弹窗收激活码(可复用)
// 注意:递归弹窗直到输入有效码,取消则退出应用async function showActivationDialog() {const { response, inputValue } = await dialog.showInputBox({title: '激活应用',message: '请输入激活码',placeholderText: '激活码',buttons: ['确认', '取消'], // 确认=0,取消=1defaultId: 0});if (response === 0 && inputValue?.trim()) {const code = inputValue.trim();// 坑:这里先模拟验证通过,实际需调后端接口(如fetch('/verify', {method:'POST', body:JSON.stringify({code})}))const isLegal = true; // 替换为真实校验!if (isLegal && saveCode(code)) return code;dialog.showErrorBox('激活失败', '激活码无效');return showActivationDialog(); // 递归重试} else {app.quit(); // 取消或空输入,退出return null;}}
3. 启动窗口(加载Uniapp并传参)
async function createWindow() {const win = new BrowserWindow({width: 1200,height: 800,webPreferences: { contextIsolation: true, nodeIntegration: false }});// 获取激活码(首次弹窗,后续读本地)const code = getLocalCode() || await showActivationDialog();if (!code) return; // 未获取码(如取消激活),已退出// 加载Uniapp打包的H5(假设在dist/index.html),带激活码参数const h5Path = path.join(__dirname, 'dist', 'index.html');// 注意:Electron加载本地HTML用loadFile,参数通过URL拼接win.loadFile(h5Path).then(() => {win.webContents.executeJavaScript(`window.location.search = "?activationCode=${encodeURIComponent(code)}"`);});}app.whenReady().then(createWindow);
三、Uniapp页面怎么接(解析URL参数)
Uniapp在App.vue的onLaunch里解析参数,存起来用。
1. 解析URL参数工具函数(可复用)
// 注意:处理带hash的URL,取search部分function parseUrlParams(url) {const params = {};const search = url.split('?')[1]?.split('#')[0]; // 忽略hashif (search) {search.split('&').forEach(pair => {const [k, v] = pair.split('=');if (k) params[k] = decodeURIComponent(v || '');});}return params;}
2. 在App.vue里用
export default {onLaunch() {const params = parseUrlParams(window.location.href);const code = params.activationCode;if (code) {uni.setStorageSync('activationCode', code); // 存本地,后续用console.log('激活码:', code);} else {console.error('未获取到激活码'); // 兜底:Electron已校验,这里一般不会触发}}}
四、打包和踩过的坑
1. 打包配置(electron-builder)
package.json里加:
"build": {"files": ["main.js", "dist/**/*"], // 包含Uniapp的dist目录"win": { "target": "nsis" }}
2. 真实坑
坑1:Uniapp打包后资源加载失败
Uniapp打包H5时,在manifest.json的h5配置里设”publicPath”: “./”(相对路径),否则Electron加载本地文件会404。
坑2:Electron加载本地HTML参数丢失
上面用loadFile后执行JS改location.search,比直接loadURL(file://…?param)稳(避免路径特殊字符问题)。
最后
这是个本地验证的简单方案,怕破解需配合后端接口做在线校验。代码拿过去改改路径和校验逻辑就能用,半小时集成完。
夜雨聆风
