feat: 提交资源
This commit is contained in:
		
							
								
								
									
										227
									
								
								extensions/max-studio/source/hotupdate/hooks.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								extensions/max-studio/source/hotupdate/hooks.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
import {
 | 
			
		||||
    BuildHook,
 | 
			
		||||
    IBuildResult,
 | 
			
		||||
    IBuildTaskOption,
 | 
			
		||||
} from "@cocos/creator-types/editor/packages/builder/@types/public";
 | 
			
		||||
import path from "path";
 | 
			
		||||
import { existsSync, readFile, writeFile } from "fs";
 | 
			
		||||
import { ensureDirSync } from "fs-extra";
 | 
			
		||||
import { generator, GenPackageConfig } from "./version_generator";
 | 
			
		||||
import { createMinIOUploader, MinIOConfig } from "./minio-uploader";
 | 
			
		||||
 | 
			
		||||
const injectScript = `(function () {
 | 
			
		||||
    const native = globalThis?.jsb || window.jsb || native;
 | 
			
		||||
    if (typeof native === 'object') {
 | 
			
		||||
      var hotUpdateSearchPaths = localStorage.getItem('HotUpdateSearchPaths');
 | 
			
		||||
      if (hotUpdateSearchPaths) {
 | 
			
		||||
        var paths = JSON.parse(hotUpdateSearchPaths);
 | 
			
		||||
        native.fileUtils.setSearchPaths(paths);
 | 
			
		||||
 | 
			
		||||
        var fileList = [];
 | 
			
		||||
        var storagePath = paths[0] || '';
 | 
			
		||||
        var tempPath = storagePath + '_temp/';
 | 
			
		||||
        var baseOffset = tempPath.length;
 | 
			
		||||
        if (native.fileUtils.isDirectoryExist(tempPath) && !native.fileUtils.isFileExist(tempPath + 'project.manifest.temp')) {
 | 
			
		||||
          native.fileUtils.listFilesRecursively(tempPath, fileList);
 | 
			
		||||
          fileList.forEach(srcPath => {
 | 
			
		||||
              var relativePath = srcPath.substr(baseOffset);
 | 
			
		||||
              var dstPath = storagePath + relativePath;
 | 
			
		||||
              if (srcPath[srcPath.length - 1] === '/') {
 | 
			
		||||
                  native.fileUtils.createDirectory(dstPath)
 | 
			
		||||
              }
 | 
			
		||||
              else {
 | 
			
		||||
                  if (native.fileUtils.isFileExist(dstPath)) {
 | 
			
		||||
                      native.fileUtils.removeFile(dstPath)
 | 
			
		||||
                  }
 | 
			
		||||
                  native.fileUtils.renameFile(srcPath, dstPath);
 | 
			
		||||
              }
 | 
			
		||||
          })
 | 
			
		||||
          native.fileUtils.removeDirectory(tempPath);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  })();`;
 | 
			
		||||
 | 
			
		||||
export const onBeforeBuild: BuildHook.onBeforeBuild = async function (
 | 
			
		||||
    options: IBuildTaskOption,
 | 
			
		||||
    result: IBuildResult
 | 
			
		||||
) {};
 | 
			
		||||
 | 
			
		||||
export const onAfterBuild: BuildHook.onAfterBuild = async function (
 | 
			
		||||
    options: IBuildTaskOption,
 | 
			
		||||
    result: IBuildResult
 | 
			
		||||
) {
 | 
			
		||||
    console.log("onAfterBuild platform", options.platform);
 | 
			
		||||
 | 
			
		||||
    if (!["android", "mac", "ios", "windows"].includes(options.platform)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let url = path.join(result.dest, "data", "main.js");
 | 
			
		||||
    console.log("onAfterBuild url", url);
 | 
			
		||||
    if (!existsSync(url)) {
 | 
			
		||||
        url = path.join(result.dest, "assets", "main.js");
 | 
			
		||||
    }
 | 
			
		||||
    console.log("onAfterBuild url", url);
 | 
			
		||||
 | 
			
		||||
    const hotupdateConfig: {
 | 
			
		||||
        hotupdatePluginCheck: boolean;
 | 
			
		||||
        configInput: string;
 | 
			
		||||
        outInput: string;
 | 
			
		||||
        // MinIO 配置
 | 
			
		||||
        minioAutoUpload: boolean;
 | 
			
		||||
        minioEndpoint: string;
 | 
			
		||||
        minioAccessKeyId: string;
 | 
			
		||||
        minioSecretAccessKey: string;
 | 
			
		||||
        minioBucketName: string;
 | 
			
		||||
        minioUseSSL: boolean;
 | 
			
		||||
        minioPathPrefix: string;
 | 
			
		||||
    } = options.packages?.["max-framework"];
 | 
			
		||||
    console.log(
 | 
			
		||||
        "onAfterBuild hotupdateConfig",
 | 
			
		||||
        url,
 | 
			
		||||
        hotupdateConfig.hotupdatePluginCheck,
 | 
			
		||||
        hotupdateConfig.configInput,
 | 
			
		||||
        hotupdateConfig.outInput,
 | 
			
		||||
        JSON.stringify(hotupdateConfig)
 | 
			
		||||
    );
 | 
			
		||||
    if (!!hotupdateConfig.hotupdatePluginCheck) {
 | 
			
		||||
        // 验证配置参数
 | 
			
		||||
        if (!hotupdateConfig.configInput || !hotupdateConfig.outInput) {
 | 
			
		||||
            console.error("热更新配置不完整:configInput 和 outInput 不能为空");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            // configInput 是带 project:// 前缀的,需要转换为实际文件路径
 | 
			
		||||
            let configPath = hotupdateConfig.configInput;
 | 
			
		||||
            if (configPath.startsWith("project://")) {
 | 
			
		||||
                configPath = path.resolve(
 | 
			
		||||
                    Editor.Project.path,
 | 
			
		||||
                    configPath.replace("project://", "")
 | 
			
		||||
                );
 | 
			
		||||
            } else if (!path.isAbsolute(configPath)) {
 | 
			
		||||
                configPath = path.resolve(Editor.Project.path, configPath);
 | 
			
		||||
            }
 | 
			
		||||
            let outInput = hotupdateConfig.outInput;
 | 
			
		||||
            if (outInput.startsWith("project://")) {
 | 
			
		||||
                outInput = path.resolve(
 | 
			
		||||
                    Editor.Project.path,
 | 
			
		||||
                    outInput.replace("project://", "")
 | 
			
		||||
                );
 | 
			
		||||
            } else if (!path.isAbsolute(outInput)) {
 | 
			
		||||
                outInput = path.resolve(Editor.Project.path, outInput);
 | 
			
		||||
            }
 | 
			
		||||
            console.log("onAfterBuild configPath", configPath, outInput);
 | 
			
		||||
            const obj = require(configPath) as GenPackageConfig[];
 | 
			
		||||
            for (const item of obj) {
 | 
			
		||||
                // 验证包名不能为空
 | 
			
		||||
                if (!item.pkgName || item.pkgName.trim() === "") {
 | 
			
		||||
                    console.error("热更新包名不能为空:", item);
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                const source = path.join(result.dest, "data");
 | 
			
		||||
                console.log("开始生成Package: ", item.pkgName, source);
 | 
			
		||||
                ensureDirSync(
 | 
			
		||||
                    path.join(outInput, item.pkgName)
 | 
			
		||||
                );
 | 
			
		||||
                generator(source, outInput, item);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // MinIO上传功能
 | 
			
		||||
            if (hotupdateConfig.minioAutoUpload) {
 | 
			
		||||
                console.log("开始MinIO自动上传流程...");
 | 
			
		||||
                await uploadToMinIO(hotupdateConfig, outInput, obj);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error("热更新配置文件加载失败:", error);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
        readFile(url, "utf8", (err, data) => {
 | 
			
		||||
            if (err) {
 | 
			
		||||
                reject(err);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            const newStr = injectScript + data;
 | 
			
		||||
            writeFile(url, newStr, (err) => {
 | 
			
		||||
                if (err) {
 | 
			
		||||
                    reject(err);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                resolve();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 上传到MinIO
 | 
			
		||||
 * @param config 热更新配置
 | 
			
		||||
 * @param outputPath 输出路径
 | 
			
		||||
 * @param packages 包配置列表
 | 
			
		||||
 */
 | 
			
		||||
async function uploadToMinIO(
 | 
			
		||||
    config: {
 | 
			
		||||
        minioEndpoint: string;
 | 
			
		||||
        minioAccessKeyId: string;
 | 
			
		||||
        minioSecretAccessKey: string;
 | 
			
		||||
        minioBucketName: string;
 | 
			
		||||
        minioUseSSL: boolean;
 | 
			
		||||
        minioPathPrefix: string;
 | 
			
		||||
    },
 | 
			
		||||
    outputPath: string,
 | 
			
		||||
    packages: GenPackageConfig[]
 | 
			
		||||
) {
 | 
			
		||||
    try {
 | 
			
		||||
        // 验证MinIO配置
 | 
			
		||||
        if (!config.minioEndpoint || !config.minioAccessKeyId ||
 | 
			
		||||
            !config.minioSecretAccessKey || !config.minioBucketName) {
 | 
			
		||||
            console.error("MinIO配置不完整,跳过上传");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 创建MinIO上传器
 | 
			
		||||
        const minioConfig: MinIOConfig = {
 | 
			
		||||
            endpoint: config.minioEndpoint,
 | 
			
		||||
            accessKeyId: config.minioAccessKeyId,
 | 
			
		||||
            secretAccessKey: config.minioSecretAccessKey,
 | 
			
		||||
            bucketName: config.minioBucketName,
 | 
			
		||||
            useSSL: config.minioUseSSL,
 | 
			
		||||
            pathPrefix: config.minioPathPrefix
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const uploader = createMinIOUploader(minioConfig);
 | 
			
		||||
 | 
			
		||||
        // 上传每个包
 | 
			
		||||
        for (const pkg of packages) {
 | 
			
		||||
            if (!pkg.pkgName || pkg.pkgName.trim() === "") {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const packageDir = path.join(outputPath, pkg.pkgName);
 | 
			
		||||
            if (!existsSync(packageDir)) {
 | 
			
		||||
                console.error(`包目录不存在: ${packageDir}`);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            console.log(`开始上传包到MinIO: ${pkg.pkgName}`);
 | 
			
		||||
 | 
			
		||||
            const result = await uploader.uploadDirectory(packageDir, pkg.pkgName);
 | 
			
		||||
 | 
			
		||||
            if (result.success) {
 | 
			
		||||
                console.log(`包 ${pkg.pkgName} 上传成功,共 ${result.uploadedFiles.length} 个文件`);
 | 
			
		||||
                console.log(`上传的文件: ${result.uploadedFiles.join(', ')}`);
 | 
			
		||||
            } else {
 | 
			
		||||
                console.error(`包 ${pkg.pkgName} 上传失败: ${result.error}`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        console.log("所有包MinIO上传完成");
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        console.error("MinIO上传过程中发生错误:", error);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user