add pack rpk
This commit is contained in:
@@ -3,6 +3,10 @@ node_modules/
|
|||||||
|
|
||||||
# 构建输出目录
|
# 构建输出目录
|
||||||
dist/
|
dist/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# 临时目录
|
||||||
|
.temp_*/
|
||||||
|
|
||||||
# 日志文件
|
# 日志文件
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@@ -22,8 +22,33 @@ src/
|
|||||||
|
|
||||||
### 环境要求
|
### 环境要求
|
||||||
|
|
||||||
- 安装 AIoT-IDE(Xiaomi Vela JS 应用的集成开发环境)
|
- Node.js 14+
|
||||||
- 支持 Ubuntu、Windows、MacOS 等操作系统
|
- npm
|
||||||
|
- 系统安装了 OpenSSL(release 模式需要)
|
||||||
|
|
||||||
|
### 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构建 rpk 文件
|
||||||
|
|
||||||
|
**开发模式构建**(生成 `.debug.rpk`):
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
或直接:
|
||||||
|
```bash
|
||||||
|
node build.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**生产模式构建**(生成 `.release.rpk`,需要签名文件):
|
||||||
|
```bash
|
||||||
|
npm run build:release
|
||||||
|
```
|
||||||
|
|
||||||
|
构建成功后,rpk 文件会输出到 `dist/` 目录。
|
||||||
|
|
||||||
### 运行应用
|
### 运行应用
|
||||||
|
|
||||||
@@ -31,10 +56,10 @@ src/
|
|||||||
2. 启动模拟器
|
2. 启动模拟器
|
||||||
3. 运行项目查看效果
|
3. 运行项目查看效果
|
||||||
|
|
||||||
### 打包应用
|
或使用命令行:
|
||||||
|
```bash
|
||||||
1. 在 AIoT-IDE 中使用打包功能
|
npm start
|
||||||
2. 生成安装包(.rpk 文件)
|
```
|
||||||
|
|
||||||
## 应用特点
|
## 应用特点
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +1,192 @@
|
|||||||
/**
|
/**
|
||||||
* 构建脚本
|
* 构建脚本
|
||||||
* 用于构建 Xiaomi Vela JS 应用
|
* 用于构建 Xiaomi Vela JS 应用,生成 .rpk 安装包
|
||||||
|
*
|
||||||
|
* 使用方式:
|
||||||
|
* node build.js # 开发模式构建(生成 .debug.rpk)
|
||||||
|
* node build.js --release # 生产模式构建(生成 .release.rpk,需要签名文件)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const { execSync } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
// 源目录
|
// ========== 配置 ==========
|
||||||
const srcDir = path.join(__dirname, 'src');
|
const projectDir = __dirname;
|
||||||
|
const srcDir = path.join(projectDir, 'src');
|
||||||
|
const distDir = path.join(projectDir, 'dist');
|
||||||
|
const signDir = path.join(projectDir, 'sign');
|
||||||
|
const isRelease = process.argv.includes('--release');
|
||||||
|
|
||||||
// 输出目录
|
// ========== 辅助函数 ==========
|
||||||
const distDir = path.join(__dirname, 'dist');
|
|
||||||
|
|
||||||
// 创建输出目录
|
/**
|
||||||
if (!fs.existsSync(distDir)) {
|
* 执行命令并打印输出
|
||||||
fs.mkdirSync(distDir);
|
*/
|
||||||
|
function run(cmd, options = {}) {
|
||||||
|
console.log(`\n> ${cmd}`);
|
||||||
|
try {
|
||||||
|
const output = execSync(cmd, {
|
||||||
|
cwd: projectDir,
|
||||||
|
stdio: 'inherit',
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
return output;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`命令执行失败: ${cmd}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制文件函数
|
/**
|
||||||
function copyFileSync(source, target) {
|
* 检查 aiot CLI 是否已安装
|
||||||
let targetFile = target;
|
*/
|
||||||
|
function isAiotInstalled() {
|
||||||
|
try {
|
||||||
|
execSync('aiot --version', { cwd: projectDir, stdio: 'pipe' });
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 如果目标是一个目录,则在目录中创建同名文件
|
/**
|
||||||
if (fs.existsSync(target)) {
|
* 检查 node_modules 是否存在且 aiot-toolkit 已安装
|
||||||
if (fs.lstatSync(target).isDirectory()) {
|
*/
|
||||||
targetFile = path.join(target, path.basename(source));
|
function isNodeModulesReady() {
|
||||||
|
const aiotBin = path.join(projectDir, 'node_modules', '.bin', 'aiot');
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
return fs.existsSync(aiotBin + '.cmd');
|
||||||
|
}
|
||||||
|
return fs.existsSync(aiotBin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安装项目依赖
|
||||||
|
*/
|
||||||
|
function installDependencies() {
|
||||||
|
console.log('\n📦 正在安装项目依赖...');
|
||||||
|
run('npm install');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成签名文件(用于 release 模式)
|
||||||
|
*/
|
||||||
|
function generateSignFiles() {
|
||||||
|
if (!fs.existsSync(signDir)) {
|
||||||
|
fs.mkdirSync(signDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const privateKey = path.join(signDir, 'private.pem');
|
||||||
|
const certificate = path.join(signDir, 'certificate.pem');
|
||||||
|
|
||||||
|
if (fs.existsSync(privateKey) && fs.existsSync(certificate)) {
|
||||||
|
console.log('✅ 签名文件已存在,跳过生成');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n🔐 正在生成签名文件...');
|
||||||
|
const cmd = `openssl req -newkey rsa:2048 -nodes -keyout ${signDir}/private.pem -x509 -days 3650 -out ${signDir}/certificate.pem -subj "/CN=photo-viewer/O=Example/C=CN"`;
|
||||||
|
run(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理构建产物
|
||||||
|
*/
|
||||||
|
function cleanDist() {
|
||||||
|
if (fs.existsSync(distDir)) {
|
||||||
|
fs.rmSync(distDir, { recursive: true, force: true });
|
||||||
|
console.log('🧹 已清理 dist 目录');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找并展示构建产物
|
||||||
|
*/
|
||||||
|
function showBuildResult() {
|
||||||
|
if (!fs.existsSync(distDir)) {
|
||||||
|
console.error('❌ 构建失败:dist 目录不存在');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = [];
|
||||||
|
function walkDir(dir) {
|
||||||
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fullPath = path.join(dir, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
walkDir(fullPath);
|
||||||
|
} else if (entry.name.endsWith('.rpk')) {
|
||||||
|
const stats = fs.statSync(fullPath);
|
||||||
|
files.push({
|
||||||
|
path: fullPath,
|
||||||
|
size: (stats.size / 1024).toFixed(2),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
walkDir(distDir);
|
||||||
}
|
|
||||||
|
|
||||||
// 复制目录函数
|
if (files.length > 0) {
|
||||||
function copyFolderRecursiveSync(source, target) {
|
console.log('\n✅ 构建成功!生成的 rpk 文件:');
|
||||||
let files = [];
|
files.forEach((f) => {
|
||||||
|
console.log(` 📦 ${f.path} (${f.size} KB)`);
|
||||||
// 检查目标目录是否存在
|
|
||||||
const targetFolder = path.join(target, path.basename(source));
|
|
||||||
if (!fs.existsSync(targetFolder)) {
|
|
||||||
fs.mkdirSync(targetFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查源目录是否存在
|
|
||||||
if (fs.existsSync(source)) {
|
|
||||||
files = fs.readdirSync(source);
|
|
||||||
files.forEach(function (file) {
|
|
||||||
const curSource = path.join(source, file);
|
|
||||||
if (fs.lstatSync(curSource).isDirectory()) {
|
|
||||||
// 递归复制子目录
|
|
||||||
copyFolderRecursiveSync(curSource, targetFolder);
|
|
||||||
} else {
|
|
||||||
// 复制文件
|
|
||||||
copyFileSync(curSource, targetFolder);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('\n⚠️ 构建完成,但未在 dist 目录中找到 .rpk 文件');
|
||||||
|
console.log(' 请检查构建日志是否有错误信息');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始构建
|
// ========== 主流程 ==========
|
||||||
console.log('开始构建 Xiaomi Vela JS 应用...');
|
|
||||||
|
|
||||||
try {
|
function main() {
|
||||||
// 复制源文件到输出目录
|
const mode = isRelease ? '生产(release)' : '开发(debug)';
|
||||||
copyFolderRecursiveSync(srcDir, distDir);
|
console.log(`\n🚀 Xiaomi Vela JS 应用构建工具`);
|
||||||
console.log('构建完成!');
|
console.log(`📋 构建模式: ${mode}`);
|
||||||
console.log('输出目录:', distDir);
|
console.log(`📁 项目目录: ${projectDir}`);
|
||||||
} catch (error) {
|
|
||||||
console.error('构建失败:', error);
|
// 1. 检查 src 目录
|
||||||
|
const manifestPath = path.join(srcDir, 'manifest.json');
|
||||||
|
if (!fs.existsSync(manifestPath)) {
|
||||||
|
console.error('❌ 未找到 src/manifest.json,请确认项目结构正确');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 安装依赖
|
||||||
|
if (!isNodeModulesReady()) {
|
||||||
|
installDependencies();
|
||||||
|
} else {
|
||||||
|
console.log('\n✅ 依赖已安装');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 检查 aiot 命令是否可用
|
||||||
|
if (!isNodeModulesReady()) {
|
||||||
|
console.error('❌ aiot-toolkit 安装失败,请手动运行 npm install');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 清理旧构建产物
|
||||||
|
cleanDist();
|
||||||
|
|
||||||
|
// 5. release 模式需要签名文件
|
||||||
|
if (isRelease) {
|
||||||
|
generateSignFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 执行构建
|
||||||
|
console.log(`\n🔨 正在构建 rpk 文件...`);
|
||||||
|
if (isRelease) {
|
||||||
|
run('npx aiot release');
|
||||||
|
} else {
|
||||||
|
run('npx aiot build');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 展示构建结果
|
||||||
|
showBuildResult();
|
||||||
|
|
||||||
|
console.log('\n🎉 完成!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|||||||
Generated
+9491
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -5,7 +5,11 @@
|
|||||||
"main": "build.js",
|
"main": "build.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node build.js",
|
"build": "node build.js",
|
||||||
"start": "echo '请使用 AIoT-IDE 运行项目'"
|
"build:release": "node build.js --release",
|
||||||
|
"start": "npx aiot start"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"aiot-toolkit": "^2.0.5"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"xiaomi",
|
"xiaomi",
|
||||||
|
|||||||
+6
-2
@@ -6,10 +6,14 @@
|
|||||||
"versionCode": 1,
|
"versionCode": 1,
|
||||||
"minAPILevel": 1,
|
"minAPILevel": 1,
|
||||||
"features": [],
|
"features": [],
|
||||||
|
"config": {
|
||||||
|
"logLevel": "log",
|
||||||
|
"designWidth": 480
|
||||||
|
},
|
||||||
"router": {
|
"router": {
|
||||||
"entry": "index",
|
"entry": "pages/index",
|
||||||
"pages": {
|
"pages": {
|
||||||
"index": {
|
"pages/index": {
|
||||||
"component": "index"
|
"component": "index"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user