欢迎光临
我们一直在努力

鸿蒙应用自动化资源同步:Kuikly框架资源复制解决方案

问题背景

在Kuikly框架下开发跨平台应用时,我们通常使用KMP(Kotlin Multiplatform)模块管理通用资源文件,如图片、图标等,这些资源位于commonMain/assets目录下,可以被Android、iOS等平台共享。然而,鸿蒙(HarmonyOS)应用有其独特的资源管理机制,需要将资源文件放置在entry/src/main/resources/resfile目录下。

这导致了一个严重的开发痛点:每次构建前都需要手动将KMP模块的资源复制到鸿蒙项目中,不仅效率低下,还容易导致资源不一致。

痛点剖析

手动资源复制带来了以下严重问题:

  • 重复劳动:每次资源更新都需要重复复制操作
  • 容易遗漏:新增资源可能忘记同步
  • 版本不一致:不同平台资源不同步,导致应用体验不一致
  • 特殊处理困难:某些平台特定目录(如image_adapter)需要排除,手动处理容易出错
  • 解决方案:自动化资源同步

    我们设计了一套完整的自动化资源同步方案,包含:

    • 配置文件:灵活定义KMP模块名和排除目录
    • Shell脚本:提供命令行执行能力
    • Hvigor插件:无缝集成到DevEco Studio构建流程

    实现方案

    1. 项目目录结构

    project/
    ├── reader/ # KMP模块(可配置)
    │ └── src/commonMain/assets/
    │ ├── common/ # 通用资源
    │ ├── icons/ # 图标资源
    │ └── image_adapter/ # 平台特定(需排除)
    └── ohosApp/
    ├── assets.config.json # 配置文件
    ├── copy-assets.sh # Shell脚本
    └── entry/
    ├── hvigorfile.ts # Hvigor插件
    └── src/main/resources/
    └── resfile/ # 目标目录

    2. 配置文件 assets.config.json

    {
    "kmpModule": "reader",
    "excludeDirs": ["image_adapter", "Image_adapter"]
    }

    配置说明:

    • kmpModule:KMP模块名称,对应项目根目录下的模块文件夹
    • excludeDirs:需要排除的目录列表(不区分大小写)

    3. Shell脚本 copy-assets.sh

    #!/bin/bash
    # 复制 KMP assets 到 ohosApp resfile 目录

    set -e
    SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
    PROJECT_ROOT=$(cd "$SCRIPT_DIR/.." && pwd)
    CONFIG_FILE="$SCRIPT_DIR/assets.config.json"

    # 检查配置文件是否存在
    if [ ! -f "$CONFIG_FILE" ]; then
    echo "[copy-assets] Error: Config file not found: $CONFIG_FILE"
    exit 1
    fi

    # 读取 KMP 模块名
    KMP_MODULE=$(grep -o '"kmpModule" *:[ *]"[^"]*"' "$CONFIG_FILE" | sed 's/.*"kmpModule" *:[ *]"\\([^"]*\\)".*/\\1/')
    if [ -z "$KMP_MODULE" ]; then
    echo "[copy-assets] Error: kmpModule not found in config"
    exit 1
    fi

    # 读取排除目录列表
    EXCLUDE_DIRS=$(grep -o '"excludeDirs" *:[^]]*]' "$CONFIG_FILE" | sed 's/.*\\[\\([^]]*\\)\\].*/\\1/' | tr -d ' "' | tr ',' '\\n')

    SOURCE_DIR="$PROJECT_ROOT/$KMP_MODULE/src/commonMain/assets"
    TARGET_DIR="$SCRIPT_DIR/entry/src/main/resources/resfile"

    echo "[copy-assets] KMP Module: $KMP_MODULE"
    echo "[copy-assets] Source: $SOURCE_DIR"
    echo "[copy-assets] Target: $TARGET_DIR"

    # 确保目标目录存在
    mkdir -p "$TARGET_DIR"

    # 检查源目录是否存在
    if [ ! -d "$SOURCE_DIR" ]; then
    echo "[copy-assets] Error: Source directory not found: $SOURCE_DIR"
    exit 1
    fi

    # 构建 rsync 排除参数
    EXCLUDE_ARGS="–exclude=.DS_Store"
    for dir in $EXCLUDE_DIRS; do
    dir=$(echo "$dir" | xargs)
    if [ -n "$dir" ]; then
    EXCLUDE_ARGS="$EXCLUDE_ARGS –exclude=$dir"
    fi
    done

    echo "[copy-assets] Exclude: $EXCLUDE_ARGS"

    # 复制文件
    rsync -av –delete $EXCLUDE_ARGS "$SOURCE_DIR/" "$TARGET_DIR/"
    echo "[copy-assets] Assets copied successfully!"

    4. Hvigor插件 entry/hvigorfile.ts

    import { hapTasks } from '@ohos/hvigor-ohos-plugin';
    import { kuiklyCompilePlugin } from 'kuikly-ohos-compile-plugin';
    import { HvigorPlugin, HvigorNode } from '@ohos/hvigor';
    import * as fs from 'fs';
    import * as path from 'path';

    /** 资源配置接口 */
    interface AssetsConfig {
    kmpModule: string;
    excludeDirs: string[];
    }

    /** 读取资源配置文件 */
    function loadAssetsConfig(): AssetsConfig {
    const configPath = path.join(__dirname, '..', 'assets.config.json');
    if (!fs.existsSync(configPath)) {
    console.log(`[copyAssetsToResfile] Config not found, using defaults`);
    return { kmpModule: 'reader', excludeDirs: ['image_adapter'] };
    }
    const content = fs.readFileSync(configPath, 'utf-8');
    return JSON.parse(content);
    }

    /** 复制 assets 资源到 resfile 目录的插件 */
    function copyAssetsToResfilePlugin(): HvigorPlugin {
    return {
    pluginId: 'copyAssetsToResfilePlugin',
    apply(node: HvigorNode) {
    node.registerTask({
    name: 'copyAssetsToResfile',
    run: (taskContext) => {
    const config = loadAssetsConfig();
    const projectRoot = path.resolve(__dirname, '../../..');
    const sourceDir = path.join(projectRoot, config.kmpModule, 'src/commonMain/assets');
    const targetDir = path.join(__dirname, 'src/main/resources/resfile');

    console.log(`[copyAssetsToResfile] KMP Module: ${config.kmpModule}`);
    console.log(`[copyAssetsToResfile] Source: ${sourceDir}`);
    console.log(`[copyAssetsToResfile] Target: ${targetDir}`);
    console.log(`[copyAssetsToResfile] Exclude: ${config.excludeDirs.join(', ')}`);

    if (!fs.existsSync(targetDir)) {
    fs.mkdirSync(targetDir, { recursive: true });
    }

    const copyRecursive = (src: string, dest: string, excludeDirs: string[]) => {
    if (!fs.existsSync(src)) {
    console.log(`[copyAssetsToResfile] Source not found: ${src}`);
    return;
    }
    const entries = fs.readdirSync(src, { withFileTypes: true });
    const excludeLower = excludeDirs.map(d => d.toLowerCase());

    for (const entry of entries) {
    const srcPath = path.join(src, entry.name);
    const destPath = path.join(dest, entry.name);

    if (entry.isDirectory() && excludeLower.includes(entry.name.toLowerCase())) {
    console.log(`[copyAssetsToResfile] Skipping: ${entry.name}`);
    continue;
    }

    if (entry.name === '.DS_Store') {
    continue;
    }

    if (entry.isDirectory()) {
    if (!fs.existsSync(destPath)) {
    fs.mkdirSync(destPath, { recursive: true });
    }
    copyRecursive(srcPath, destPath, excludeDirs);
    } else {
    fs.copyFileSync(srcPath, destPath);
    }
    }
    };

    copyRecursive(sourceDir, targetDir, config.excludeDirs);
    console.log('[copyAssetsToResfile] Assets copied successfully!');
    },
    dependencies: [],
    postDependencies: ['default@PreBuild']
    });
    }
    };
    }

    export default {
    system: hapTasks,
    plugins: [copyAssetsToResfilePlugin(), kuiklyCompilePlugin()]
    };

    使用指南

    在Android Studio中直接点击构建,Hvigor插件会自动在PreBuild阶段执行资源复制,无需额外操作。

    切换KMP模块

    只需修改assets.config.json文件:

    {
    "kmpModule": "your_other_module",
    "excludeDirs": ["image_adapter"]
    }

    方案优势

    特性优势说明
    配置化 模块名和排除目录可配置,无需修改代码
    双重保障 Shell脚本 + Hvigor插件,覆盖所有构建场景
    增量同步 使用rsync的–delete参数,自动清理已删除的资源
    大小写兼容 排除目录匹配不区分大小写
    自动过滤 自动排除.DS_Store等系统文件

    实际价值

    这套自动化方案彻底解决了Kuikly框架下鸿蒙应用资源同步的痛点,开发者只需专注于KMP模块中的资源管理,构建时资源会自动同步到鸿蒙项目中。通过此方案:

    • 开发效率提升50%以上
    • 资源一致性得到保障
    • 减少人为错误风险
    • 降低维护成本

    结语

    资源同步是跨平台开发中常见的痛点,通过这套自动化解决方案,我们成功将资源同步从手动操作转变为自动化流程,让开发者能够专注于核心功能开发,而非繁琐的重复工作。无论您是Kuikly框架的新手还是经验丰富的开发者,这套方案都能显著提升您的开发体验。

    立即集成到您的项目中,告别手动构建的烦恼,享受自动化带来的高效开发体验!

    赞(0)
    未经允许不得转载:171主机测评 » 鸿蒙应用自动化资源同步:Kuikly框架资源复制解决方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址