Commit ae702ba0 authored by dsq's avatar dsq

打包脚本汇总

parent 93684af7
#!/bin/bash
#
# Eazytec is pleased to support the open source community by making CPF-KMP-CMP available.
# Copyright (C) 2026 Eazytec. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
set -e
# Record script start time
START_TIME=$(date +%s)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ====================== [1. Default Configuration and Parameter Parsing] ======================
DEFAULT_PLATFORM="ohosArm64"
DEFAULT_TARGET_ID="127.0.0.1:5555"
# bundle 从 harmonyApp/AppScope/app.json5 读取,不存在则用默认
DEFAULT_BUNDLE_NAME="com.example.harmonyapp"
APP_JSON5="$SCRIPT_DIR/harmonyApp/AppScope/app.json5"
if [ -f "$APP_JSON5" ]; then
_bundle=$(grep '"bundleName"' "$APP_JSON5" 2>/dev/null | sed 's/.*"bundleName"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' | head -1 | tr -d '\r')
[ -n "$_bundle" ] && DEFAULT_BUNDLE_NAME="$_bundle"
fi
DEFAULT_ABILITY_NAME="EntryAbility"
LOCAL_OHOS_PATH=""
usage() {
echo "Usage: $0 [options] [PLATFORM] [TARGET_ID]"
echo ""
echo "Parameters:"
echo " PLATFORM Build platform (default: $DEFAULT_PLATFORM)"
echo " TARGET_ID Device ID (default: $DEFAULT_TARGET_ID)"
echo ""
echo "Options:"
echo " -M MODES 打包类型: debug | release | all(不传 -M 时在终端用 1/2/3 选择;非终端或 RUNOHOS_NO_MENU=1 则默认 all)"
echo " -m MODE Build mode: debug or release (default: debug)"
echo " -b BUNDLE Set bundle name (current: $DEFAULT_BUNDLE_NAME)"
echo " -a ABILITY Set Ability name (current: $DEFAULT_ABILITY_NAME)"
echo " -d MODE Debug mode: debug or attach (default: attach)"
echo " -p PATH Set external OHOS project path (localOhosPath)"
echo " -h Show this help message"
echo ""
echo "Examples:"
echo " $0 ohosArm64 127.0.0.1:5555"
echo " $0 -M debug # 仅打 debug 包"
echo " $0 -M release # 仅打 release 包"
echo " $0 -M all # debug+release(等价于菜单选 3)"
echo " $0 -b com.test.app -a MainAbility"
echo " $0 -p /path/to/external/ohos/project"
exit 0
}
# Preset variables
BUNDLE_NAME=$DEFAULT_BUNDLE_NAME
ABILITY_NAME=$DEFAULT_ABILITY_NAME
BUILD_MODE="debug"
BUILD_MODES_SELECT=""
M_FLAG_SET=0
DEBUG_MODE="attach"
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# Parse options (supports options in any position, e.g. ohosArm64 62Q0226107024702 -m release)
POSITIONALS=()
while [[ $# -gt 0 ]]; do
case $1 in
-M) M_FLAG_SET=1; BUILD_MODES_SELECT="$2"; shift 2 ;;
-m) BUILD_MODE="$2"; shift 2 ;;
-b) BUNDLE_NAME="$2"; shift 2 ;;
-a) ABILITY_NAME="$2"; shift 2 ;;
-d) DEBUG_MODE="$2"; shift 2 ;;
-p) LOCAL_OHOS_PATH="$2"; shift 2 ;;
-h) usage ;;
-*)
echo "Unknown option: $1"
usage
;;
*)
POSITIONALS+=("$1")
shift
;;
esac
done
PLATFORM=${POSITIONALS[0]:-$DEFAULT_PLATFORM}
TARGET_ID=${POSITIONALS[1]:-$DEFAULT_TARGET_ID}
echo -e "\033[32m▶ Run environment configuration:\033[0m"
echo " - Platform: $PLATFORM"
echo " - Devices: from hdc list targets (see below)"
echo " - Build modes: 由 -M 或菜单 1/2/3 选择 (debug / release / debug+release)"
echo " - Debug mode: $DEBUG_MODE"
echo " - Bundle: $BUNDLE_NAME"
echo " - Ability: $ABILITY_NAME"
if [ -n "$LOCAL_OHOS_PATH" ]; then
echo " - External OHOS path: $LOCAL_OHOS_PATH"
fi
echo "------------------------------------------------------------"
# --- Configuration ---
DEVECO_PATH="${DEVECO_PATH:-/Applications/DevEco-Studio.app}"
MIN_VERSION="6.0.0"
echo " DevEco Studio Path ${DEVECO_PATH}"
echo "🔍 Checking environment configuration..."
# 1. Check if DevEco exists
if [ ! -d "$DEVECO_PATH" ]; then
echo "❌ Error: DevEco Studio not found at $DEVECO_PATH."
exit 1
fi
# 2. Get version (from Info.plist CFBundleShortVersionString)
# Output example: 5.0.3.406
CURRENT_VERSION=$(defaults read "$DEVECO_PATH/Contents/Info.plist" CFBundleShortVersionString)
echo "Current DevEco version: $CURRENT_VERSION"
echo "Minimum required version: $MIN_VERSION"
CUR_MAJOR=$(echo "$CURRENT_VERSION" | cut -d. -f1)
CUR_MINOR=$(echo "$CURRENT_VERSION" | cut -d. -f2)
REQ_MAJOR=$(echo "$MIN_VERSION" | cut -d. -f1)
REQ_MINOR=$(echo "$MIN_VERSION" | cut -d. -f2)
if [ "$CUR_MAJOR" -lt "$REQ_MAJOR" ] 2>/dev/null || \
{ [ "$CUR_MAJOR" -eq "$REQ_MAJOR" ] && [ "$CUR_MINOR" -lt "$REQ_MINOR" ]; }; then
echo "-------------------------------------------------------"
echo -e "${RED}⛔️ Error: DevEco version is too low!${NC}"
echo -e "${RED}Current version: $CURRENT_VERSION${NC}"
echo -e "${RED}Minimum required: $MIN_VERSION+${NC}"
echo -e "${RED}Please upgrade DevEco Studio and run this script again.${NC}"
echo "-------------------------------------------------------"
exit 5
fi
echo "✅ DevEco version meets requirements ($CURRENT_VERSION)"
# ====================== [2. Environment Path and SDK Configuration] ======================
DEVECO_HOME="${DEVECO_HOME:-$DEVECO_PATH/Contents}"
echo "✅ ($DEVECO_HOME)"
HDC_BIN="$DEVECO_HOME/sdk/default/openharmony/toolchains/hdc"
export DEVECO_SDK_HOME="$DEVECO_HOME/sdk"
export PATH="$DEVECO_SDK_HOME:$DEVECO_HOME/jbr/Contents/Home/bin:$DEVECO_HOME/tools/node/bin:$DEVECO_HOME/tools/ohpm/bin:$DEVECO_HOME/tools/hvigor/bin:$PATH"
# ====================== [2.5 Device List and Build Mode List] ======================
DEVICE_IDS=()
while IFS= read -r line; do
line=$(echo "$line" | tr -d '\r' | xargs)
[ -n "$line" ] && DEVICE_IDS+=("$line")
done < <("$HDC_BIN" list targets 2>/dev/null | awk '{if (NF>=1) print $1}')
# 打包类型:未传 -M 时在交互终端用 1/2/3 选择;CI / 管道输入用 RUNOHOS_NO_MENU=1 或默认 all
pick_build_modes_interactive() {
if [[ -n "${RUNOHOS_NO_MENU:-}" ]]; then
BUILD_MODES_SELECT="all"
return
fi
if [[ ! -t 0 ]]; then
BUILD_MODES_SELECT="all"
return
fi
echo ""
echo "请选择打包类型(输入数字后回车):"
echo " 1) 仅 debug"
echo " 2) 仅 release"
echo " 3) debug + release(全部)"
local _c
read -r -p "请输入 1 / 2 / 3 [默认 3]: " _c || true
_c=${_c:-3}
case "$_c" in
1) BUILD_MODES_SELECT=debug ;;
2) BUILD_MODES_SELECT=release ;;
3) BUILD_MODES_SELECT=all ;;
*) echo "无效输入,使用默认 3(debug+release)"; BUILD_MODES_SELECT=all ;;
esac
}
if [[ "$M_FLAG_SET" -eq 0 ]]; then
pick_build_modes_interactive
fi
if [ -z "$BUILD_MODES_SELECT" ]; then
BUILD_MODES_SELECT="all"
fi
case "$(echo "$BUILD_MODES_SELECT" | tr '[:upper:]' '[:lower:]')" in
debug) BUILD_MODES=(debug) ;;
release) BUILD_MODES=(release) ;;
all|*) BUILD_MODES=(debug release) ;;
esac
if [ ${#DEVICE_IDS[@]} -eq 0 ]; then
echo -e "\033[31mError: No device found. Run 'hdc list targets' to check connected devices.\033[0m"
exit 5
fi
echo "Devices: ${DEVICE_IDS[*]}"
echo "Build modes: ${BUILD_MODES[*]}"
echo "------------------------------------------------------------"
TOTAL_COUNT=0
SUCCESS_COUNT=0
ERR_MSGS=()
PUSH_TIMES=()
PACK_SIZES=()
set +e
for TARGET_ID in "${DEVICE_IDS[@]}"; do
for BUILD_MODE in "${BUILD_MODES[@]}"; do
((TOTAL_COUNT++))
echo ""
echo "$TARGET_ID 设备 $BUILD_MODE 模式 进行打包"
# 每轮切到项目根,与原脚本一致在项目根执行 gradlew
cd "$SCRIPT_DIR"
# 每轮打包前:先删除 entry/builds、entry/build(含 HAP)、entry/libs 下全部 .so 与 arm64-v8a/x86_64 目录,删除后检测再打包
ENTRY_BASE="$SCRIPT_DIR/harmonyApp/entry"
CHECK_BASE="$SCRIPT_DIR/harmonyApp"
HAP_PATH="$CHECK_BASE/entry/build/default/outputs/default/entry-default-signed.hap"
LIBS_ARM="$CHECK_BASE/entry/libs/arm64-v8a"
LIBS_X86="$CHECK_BASE/entry/libs/x86_64"
DEL_RETRY=0
while true; do
rm -rf "$ENTRY_BASE/builds"
rm -rf "$ENTRY_BASE/build"
if [ -d "$ENTRY_BASE/libs" ]; then
find "$ENTRY_BASE/libs" -type f \( -name '*.so' -o -name '*.SO' \) -delete 2>/dev/null || true
fi
rm -rf "$ENTRY_BASE/libs/arm64-v8a"
rm -rf "$ENTRY_BASE/libs/x86_64"
HAP_EXISTS="无"; [ -f "$HAP_PATH" ] && HAP_EXISTS="有"
LIBS_EXISTS="无"
if [ -d "$LIBS_ARM" ] || [ -d "$LIBS_X86" ]; then LIBS_EXISTS="有"; fi
if [ -d "$ENTRY_BASE/libs" ]; then
_any_so=$(find "$ENTRY_BASE/libs" -type f \( -name '*.so' -o -name '*.SO' \) 2>/dev/null | head -1)
[ -n "$_any_so" ] && LIBS_EXISTS="有"
fi
if [ "$HAP_EXISTS" = "无" ] && [ "$LIBS_EXISTS" = "无" ]; then
echo -e "\033[35m删除后检测: HAP包=无, libs中间产物=无,已确认清理完成\033[0m"
break
fi
DEL_RETRY=$((DEL_RETRY + 1))
if [ $DEL_RETRY -ge 5 ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:清理未完全,HAP包=${HAP_EXISTS}, libs中间产物=${LIBS_EXISTS},须清光后再打包)"
echo "$_e"
ERR_MSGS+=("$_e")
continue 2
fi
sleep 1
done
"$HDC_BIN" -t "$TARGET_ID" shell aa force-stop "$BUNDLE_NAME" >/dev/null 2>&1 || true
# ====================== [3. Gradle Build] ======================
# publish 必须跑完且成功,再进行打包、推包;命令失败时打印完整错误输出(含具体文件/配置报错)
GRADLE_OUT="/tmp/runOhos_gradle_$$.out"
GRADLE_RET=0
if [ "$PLATFORM" = "ohosArm64" ]; then
if [ "$BUILD_MODE" = "release" ]; then
echo ">>> :composeApp:publishReleaseBinariesToHarmonyApp"
if [ -n "$LOCAL_OHOS_PATH" ]; then
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH" 2>&1 | tee "$GRADLE_OUT"
else
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp 2>&1 | tee "$GRADLE_OUT"
fi
GRADLE_RET=${PIPESTATUS[0]}
else
echo ">>> :composeApp:publishDebugBinariesToHarmonyApp"
if [ -n "$LOCAL_OHOS_PATH" ]; then
./gradlew :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH" 2>&1 | tee "$GRADLE_OUT"
else
./gradlew :composeApp:publishDebugBinariesToHarmonyApp 2>&1 | tee "$GRADLE_OUT"
fi
GRADLE_RET=${PIPESTATUS[0]}
fi
elif [ "$PLATFORM" = "ohosX86_64" ]; then
if [ "$BUILD_MODE" = "release" ]; then
echo ">>> :composeApp:publishReleaseBinariesToHarmonyApp"
if [ -n "$LOCAL_OHOS_PATH" ]; then
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH" 2>&1 | tee "$GRADLE_OUT"
else
./gradlew :composeApp:publishReleaseBinariesToHarmonyApp 2>&1 | tee "$GRADLE_OUT"
fi
GRADLE_RET=${PIPESTATUS[0]}
else
echo ">>> :composeApp:publishDebugBinariesToHarmonyApp"
if [ -n "$LOCAL_OHOS_PATH" ]; then
./gradlew :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="$LOCAL_OHOS_PATH" 2>&1 | tee "$GRADLE_OUT"
else
./gradlew :composeApp:publishDebugBinariesToHarmonyApp 2>&1 | tee "$GRADLE_OUT"
fi
GRADLE_RET=${PIPESTATUS[0]}
fi
elif [ "$PLATFORM" = "iosSimulatorArm64" ]; then
echo ">>> :composeApp:linkDebugFrameworkIosSimulatorArm64"
./gradlew :composeApp:linkDebugFrameworkIosSimulatorArm64 2>&1 | tee "$GRADLE_OUT"
GRADLE_RET=${PIPESTATUS[0]}
else
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:不支持的平台 $PLATFORM)"
echo "$_e"
ERR_MSGS+=("$_e")
continue
fi
if [ $GRADLE_RET -ne 0 ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:Gradle publish 未成功,exit code $GRADLE_RET)"
echo "$_e"
ERR_MSGS+=("$_e")
echo " >>> 命令错误输出(含具体文件/配置报错):"
[ -f "$GRADLE_OUT" ] && cat "$GRADLE_OUT" | tail -80
rm -f "$GRADLE_OUT"
continue
fi
rm -f "$GRADLE_OUT"
# SO packaging end time
HAP_START_TIME=$(date +%s)
# --- Subsequent install logic (hdc install etc.) ---
# ====================== [4. HAP Package Build] ======================
# Switch to harmonyApp directory for subsequent OHOS commands
# Use external path if specified, otherwise use default harmonyApp directory
if [ -n "$LOCAL_OHOS_PATH" ]; then
HARMONY_APP_DIR="$LOCAL_OHOS_PATH"
else
HARMONY_APP_DIR="harmonyApp"
fi
if [ ! -d "$HARMONY_APP_DIR" ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:harmonyApp 目录不存在 $HARMONY_APP_DIR)"
echo "$_e"
ERR_MSGS+=("$_e")
continue
fi
cd "$HARMONY_APP_DIR"
HVIGOR_OUT="/tmp/runOhos_hvigor_$$.out"
ohpm install --all 2>&1 | tee "$HVIGOR_OUT"
OHPM_RET=${PIPESTATUS[0]}
if [ $OHPM_RET -ne 0 ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:ohpm install 失败)"
echo "$_e"
ERR_MSGS+=("$_e")
echo " >>> 命令错误输出:"
[ -f "$HVIGOR_OUT" ] && cat "$HVIGOR_OUT" | tail -80
rm -f "$HVIGOR_OUT"
cd "$SCRIPT_DIR"
continue
fi
rm -f "$HVIGOR_OUT"
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --sync -p product=default -p buildMode="$BUILD_MODE" --analyze=normal --parallel --incremental --daemon 2>&1 | tee "$HVIGOR_OUT"
HVIGOR_SYNC_RET=${PIPESTATUS[0]}
if [ $HVIGOR_SYNC_RET -ne 0 ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:hvigor --sync 失败,请查看下方输出中的文件/配置名)"
echo "$_e"
ERR_MSGS+=("$_e")
echo " >>> 命令错误输出:"
[ -f "$HVIGOR_OUT" ] && cat "$HVIGOR_OUT" | tail -80
rm -f "$HVIGOR_OUT"
cd "$SCRIPT_DIR"
continue
fi
rm -f "$HVIGOR_OUT"
if [ "$BUILD_MODE" = "release" ]; then
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry -p product=default -p buildMode=release -p requiredDeviceType=phone assembleHap compileNative --analyze=normal --parallel --incremental --daemon 2>&1 | tee "$HVIGOR_OUT"
else
node "$DEVECO_HOME/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry@default -p product=default -p buildMode=debug -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon 2>&1 | tee "$HVIGOR_OUT"
fi
HVIGOR_ASM_RET=${PIPESTATUS[0]}
if [ $HVIGOR_ASM_RET -ne 0 ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:hvigor assembleHap 失败,请查看下方输出中的文件/配置名)"
echo "$_e"
ERR_MSGS+=("$_e")
echo " >>> 命令错误输出:"
[ -f "$HVIGOR_OUT" ] && cat "$HVIGOR_OUT" | tail -80
rm -f "$HVIGOR_OUT"
cd "$SCRIPT_DIR"
continue
fi
rm -f "$HVIGOR_OUT"
# ====================== [5. Install and Push Debug Components] ======================
AVAILABLE_TARGETS=$("$HDC_BIN" list targets)
HAP_DIR="./entry/build/default/outputs/default"
SIGNED_HAP="entry-default-signed.hap"
HAP_FILE="$HAP_DIR/$SIGNED_HAP"
# Check if signed HAP package exists
if [ ! -f "$HAP_FILE" ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:未找到已签名 HAP 包 $HAP_FILE)"
echo "$_e"
ERR_MSGS+=("$_e")
cd "$SCRIPT_DIR"
continue
fi
if ! echo "$AVAILABLE_TARGETS" | grep -q "$TARGET_ID"; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:设备离线或未连接)"
echo "$_e"
ERR_MSGS+=("$_e")
cd "$SCRIPT_DIR"
continue
fi
# 推包:与原脚本一致,使用绝对路径避免当前目录影响
HAP_FILE_ABS="$(pwd)/entry/build/default/outputs/default/$SIGNED_HAP"
# 安装前先卸载,避免同设备 debug/release 签名冲突(原脚本单次运行无此问题)
"$HDC_BIN" -t "$TARGET_ID" shell bm uninstall -n "$BUNDLE_NAME" >/dev/null 2>&1 || true
REMOTE_HAP_DIR="/data/local/tmp/debug_install"
"$HDC_BIN" -t "$TARGET_ID" shell mkdir -p "$REMOTE_HAP_DIR"
"$HDC_BIN" -t "$TARGET_ID" file send "$HAP_FILE_ABS" "$REMOTE_HAP_DIR"
INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
sleep 1
INSTALL_RESULT=$?
if echo "$INSTALL_OUTPUT" | grep -qE "failed|Failed|error|Error"; then
"$HDC_BIN" -t "$TARGET_ID" shell bm uninstall -n "$BUNDLE_NAME" >/dev/null 2>&1 || true
sleep 5
INSTALL_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell bm install -p "$REMOTE_HAP_DIR/$SIGNED_HAP" 2>&1)
sleep 5
fi
if echo "$INSTALL_OUTPUT" | grep -qE "failed|Failed|error|Error"; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:安装失败 bm install)"
echo "$_e"
ERR_MSGS+=("$_e")
echo " >>> $INSTALL_OUTPUT"
cd "$SCRIPT_DIR"
continue
fi
# ====================== [6. App Launch and Debug Mount] ======================
"$HDC_BIN" -t "$TARGET_ID" shell rm -rf "$REMOTE_HAP_DIR" >/dev/null 2>&1
sleep 1
# Step 1: Start app (with -D if debug mode enabled)
if [ "$DEBUG_MODE" = "debug" ]; then
AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" -D 2>&1)
else
AA_START_OUTPUT=$("$HDC_BIN" -t "$TARGET_ID" shell aa start -a "$ABILITY_NAME" -b "$BUNDLE_NAME" 2>&1)
fi
# Package push complete time
END_TIME=$(date +%s)
AA_START_RESULT=$?
# Check if screen lock error
if echo "$AA_START_OUTPUT" | grep -q "10106102\|screen is locked"; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:设备屏幕已锁定,请解锁后重试)"
echo "$_e"
ERR_MSGS+=("$_e")
cd "$SCRIPT_DIR"
continue
fi
# Step 2: Get app PID
get_pid_func() {
"$HDC_BIN" -t "$TARGET_ID" shell "pidof $BUNDLE_NAME" 2>/dev/null | tr -d '\r' | tr -d '\n' | awk '{print $1}'
}
MAX_WAIT=45
COUNT=0
APP_PID=""
while [ $COUNT -lt $MAX_WAIT ]; do
APP_PID=$(get_pid_func)
if [[ "$APP_PID" =~ ^[0-9]+$ ]]; then
break
fi
sleep 1
let COUNT=COUNT+1
done
if [ -z "$APP_PID" ]; then
_e="错误的 $TARGET_ID 设备 $BUILD_MODE 模式(原因:应用在 ${MAX_WAIT}s 内未启动,请检查设备与安装结果)"
echo "$_e"
ERR_MSGS+=("$_e")
echo " >>> aa start 输出: $AA_START_OUTPUT"
cd "$SCRIPT_DIR"
continue
fi
# 本组耗时统计(SO 构建 / HAP 打包+推包 / 总耗时)
ELAPSED_SO=$((HAP_START_TIME - START_TIME))
ELAPSED_HAP_PUSH=$((END_TIME - HAP_START_TIME))
ELAPSED_TOTAL=$((END_TIME - START_TIME))
echo " - SO build time: $((ELAPSED_SO/60))m$((ELAPSED_SO%60))s (${ELAPSED_SO}s)"
echo " - HAP package and push time: $((ELAPSED_HAP_PUSH/60))m$((ELAPSED_HAP_PUSH%60))s (${ELAPSED_HAP_PUSH}s)"
echo " - Total time: $((ELAPSED_TOTAL/60))m$((ELAPSED_TOTAL%60))s (${ELAPSED_TOTAL}s)"
# 本组 HAP 包大小检测(当前目录为 harmonyApp)
HAP_PATH_SIZE="$(pwd)/entry/build/default/outputs/default/$SIGNED_HAP"
if [ -f "$HAP_PATH_SIZE" ]; then
_bytes=$(stat -f%z "$HAP_PATH_SIZE" 2>/dev/null || stat -c%s "$HAP_PATH_SIZE" 2>/dev/null)
if [ -n "$_bytes" ] && [ "$_bytes" -gt 0 ] 2>/dev/null; then
if [ "$_bytes" -ge 1048576 ]; then
_size_str="$((_bytes / 1048576))MB (${_bytes}B)"
elif [ "$_bytes" -ge 1024 ]; then
_size_str="$((_bytes / 1024))KB (${_bytes}B)"
else
_size_str="${_bytes}B"
fi
echo " - HAP 包大小: $_size_str"
PACK_SIZES+=("$TARGET_ID | $BUILD_MODE | $_size_str")
fi
fi
PUSH_TIMES+=("$TARGET_ID | $BUILD_MODE | SO:${ELAPSED_SO}s HAP+push:${ELAPSED_HAP_PUSH}s 总:${ELAPSED_TOTAL}s")
echo "$TARGET_ID 设备 $BUILD_MODE 模式 打包成功"
((SUCCESS_COUNT++))
# Return to project root for next iteration (Gradle runs from project root)
cd "$SCRIPT_DIR"
done
done
set -e
SCRIPT_END_TIME=$(date +%s)
# ====================== [7. Packing Result Statistics] ======================
echo ""
echo "=============================================="
echo -e "\033[32m▶ 打包结果统计 / Packing Result Summary\033[0m"
echo "=============================================="
echo " 总次数 Total: $TOTAL_COUNT"
echo " 推包成功 Success: $SUCCESS_COUNT"
if [ "$TOTAL_COUNT" -gt 0 ]; then
RATE_PCT=$((SUCCESS_COUNT * 100 / TOTAL_COUNT))
echo " 通过率 Rate: ${SUCCESS_COUNT}/${TOTAL_COUNT} = ${RATE_PCT}%"
else
echo " 通过率 Rate: N/A"
fi
echo " 脚本总耗时: $((SCRIPT_END_TIME - START_TIME))s"
echo "=============================================="
if [ ${#ERR_MSGS[@]} -gt 0 ]; then
echo ""
echo "----------------------------------------------"
echo -e "\033[33m▶ 错误信息汇总\033[0m"
echo "----------------------------------------------"
for _line in "${ERR_MSGS[@]}"; do
echo " $_line"
done
echo "----------------------------------------------"
fi
if [ ${#PUSH_TIMES[@]} -gt 0 ]; then
echo ""
echo "----------------------------------------------"
echo -e "\033[32m▶ Push Time 汇总\033[0m"
echo "----------------------------------------------"
for _line in "${PUSH_TIMES[@]}"; do
echo " $_line"
done
echo "----------------------------------------------"
fi
if [ ${#PACK_SIZES[@]} -gt 0 ]; then
echo ""
echo "----------------------------------------------"
echo -e "\033[32m▶ 包大小汇总\033[0m"
echo "----------------------------------------------"
for _line in "${PACK_SIZES[@]}"; do
echo " $_line"
done
echo "----------------------------------------------"
fi
echo ""
\ No newline at end of file
@echo off
setlocal EnableDelayedExpansion
REM Eazytec is pleased to support the open source community by making CPF-KMP-CMP available.
REM Copyright 2026 Eazytec. All rights reserved.
REM
REM Licensed under the Apache License, Version 2.0. See LICENSE for terms.
REM you may not use this file except in compliance with the License.
REM
REM Windows port of runOhosApp-Mac-auto.sh (all hdc targets x build modes).
pushd "%~dp0"
set "SCRIPT_DIR=%CD%"
set "DEFAULT_PLATFORM=ohosArm64"
set "DEFAULT_BUNDLE_NAME=com.example.harmonyapp"
set "DEFAULT_ABILITY_NAME=EntryAbility"
set "BUNDLE_NAME=%DEFAULT_BUNDLE_NAME%"
set "ABILITY_NAME=%DEFAULT_ABILITY_NAME%"
set "BUILD_MODE=debug"
set "BUILD_MODES_SELECT="
set "M_FLAG_SET=0"
set "DEBUG_MODE=attach"
set "LOCAL_OHOS_PATH="
set "PLATFORM="
set "SHOW_HELP=0"
REM bundle from harmonyApp AppScope app.json5 same as Mac grep bundleName
set "APP_JSON5=%SCRIPT_DIR%\harmonyApp\AppScope\app.json5"
if exist "%APP_JSON5%" (
for /f "usebackq tokens=4 delims=^"" %%V in (`findstr /l /c:"bundleName" "%APP_JSON5%"`) do (
set "_bv=%%V"
set "_bv=!_bv:,=!"
if not "!_bv!"=="" set "DEFAULT_BUNDLE_NAME=!_bv!" & set "BUNDLE_NAME=!_bv!"
)
)
REM Parse options any position e.g. ohosArm64 -M release
:parse
if "%~1"=="" goto done_parse
if "%~1"=="-M" (set "BUILD_MODES_SELECT=%~2" & set "M_FLAG_SET=1" & shift & shift & goto parse)
if "%~1"=="-m" (set "BUILD_MODE=%~2" & shift & shift & goto parse)
if /i "%~1"=="-b" (set "BUNDLE_NAME=%~2" & shift & shift & goto parse)
if /i "%~1"=="-a" (set "ABILITY_NAME=%~2" & shift & shift & goto parse)
if /i "%~1"=="-d" (set "DEBUG_MODE=%~2" & shift & shift & goto parse)
if /i "%~1"=="-p" (set "LOCAL_OHOS_PATH=%~2" & shift & shift & goto parse)
if /i "%~1"=="-h" (set "SHOW_HELP=1" & shift & goto parse)
set "_A1=%~1"
if not "!_A1!"=="" if "!_A1:~0,1!"=="-" (
echo Unknown option: !_A1!
call :usage
popd
exit /b 1
)
if "!PLATFORM!"=="" set "PLATFORM=%~1"
shift
goto parse
:done_parse
if "!SHOW_HELP!"=="1" call :usage & popd & exit /b 0
if "!PLATFORM!"=="" set "PLATFORM=%DEFAULT_PLATFORM%"
if "!M_FLAG_SET!"=="0" call :prompt_build_modes_auto
if "!BUILD_MODES_SELECT!"=="" set "BUILD_MODES_SELECT=all"
set "HAS_DEBUG=0"
set "HAS_RELEASE=0"
if /i "!BUILD_MODES_SELECT!"=="debug" set "HAS_DEBUG=1"
if /i "!BUILD_MODES_SELECT!"=="release" set "HAS_RELEASE=1"
if /i "!BUILD_MODES_SELECT!"=="all" set "HAS_DEBUG=1" & set "HAS_RELEASE=1"
if "!HAS_DEBUG!!HAS_RELEASE!"=="00" set "HAS_DEBUG=1" & set "HAS_RELEASE=1"
call :get_epoch START_TIME
echo Run environment configuration:
echo - Platform: %PLATFORM%
echo - Devices: from hdc list targets ^(see below^)
echo - Build modes: 由 -M 或菜单 1/2/3 ^(debug / release / debug+release^)
echo - Debug mode: %DEBUG_MODE%
echo - Bundle: %BUNDLE_NAME%
echo - Ability: %ABILITY_NAME%
if not "!LOCAL_OHOS_PATH!"=="" echo - External OHOS path: !LOCAL_OHOS_PATH!
echo ------------------------------------------------------------
if "!DEVECO_PATH!"=="" (
if exist "C:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=C:\Program Files\Huawei\DevEco Studio"
) else if exist "D:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=D:\Program Files\Huawei\DevEco Studio"
) else (
echo Error: DevEco Studio not found at default path. Set DEVECO_PATH.
popd
exit /b 1
)
)
echo DevEco Studio Path: !DEVECO_PATH!
echo Checking environment configuration...
set "MIN_VERSION=6.0.0"
set "PRODUCT_INFO=!DEVECO_PATH!\product-info.json"
if exist "!PRODUCT_INFO!" (
set "CURRENT_VERSION=unknown"
for /f "usebackq tokens=4 delims=^"" %%v in (`findstr /c:"^"version^":" "!PRODUCT_INFO!"`) do (
if "!CURRENT_VERSION!"=="unknown" (
set "CURRENT_VERSION=%%v"
set "CURRENT_VERSION=!CURRENT_VERSION:,=!"
)
)
) else (
echo Warning: product-info.json not found, skipping version check.
set "CURRENT_VERSION=unknown"
)
if not "!CURRENT_VERSION!"=="unknown" (
echo Current DevEco version: !CURRENT_VERSION!
echo Minimum required version: !MIN_VERSION!
for /f "tokens=1,2 delims=." %%a in ("!CURRENT_VERSION!") do (set "CUR_MAJOR=%%a" & set "CUR_MINOR=%%b")
for /f "tokens=1,2 delims=." %%a in ("!MIN_VERSION!") do (set "REQ_MAJOR=%%a" & set "REQ_MINOR=%%b")
if !CUR_MAJOR! lss !REQ_MAJOR! (
echo -------------------------------------------------------
echo Error: DevEco version is too low!
echo Current version: !CURRENT_VERSION!
echo Minimum required: !MIN_VERSION!+
echo Please upgrade DevEco Studio and run this script again.
echo -------------------------------------------------------
popd
exit /b 5
)
if !CUR_MAJOR! equ !REQ_MAJOR! if !CUR_MINOR! lss !REQ_MINOR! (
echo -------------------------------------------------------
echo Error: DevEco version is too low!
echo Current version: !CURRENT_VERSION!
echo Minimum required: !MIN_VERSION!+
echo Please upgrade DevEco Studio and run this script again.
echo -------------------------------------------------------
popd
exit /b 5
)
echo DevEco version meets requirements ^(!CURRENT_VERSION!^)
)
set "HDC_BIN=!DEVECO_PATH!\sdk\default\openharmony\toolchains\hdc.exe"
set "DEVECO_SDK_HOME=!DEVECO_PATH!\sdk"
set "PATH=!DEVECO_PATH!\jbr\bin;!DEVECO_PATH!\tools\node;!DEVECO_PATH!\tools\ohpm\bin;!DEVECO_PATH!\tools\hvigor\bin;!DEVECO_SDK_HOME!;!PATH!"
if not exist "!HDC_BIN!" (
echo Error: hdc not found at !HDC_BIN!
popd
exit /b 1
)
set "RUNOHOS_TMP=%TEMP%\runOhos_win_auto_%RANDOM%"
mkdir "%RUNOHOS_TMP%" 2>nul
set "DEV_FILE=%RUNOHOS_TMP%\devices.txt"
set "ERR_FILE=%RUNOHOS_TMP%\errors.txt"
set "PUSH_FILE=%RUNOHOS_TMP%\push.txt"
set "SIZE_FILE=%RUNOHOS_TMP%\sizes.txt"
del "%ERR_FILE%" "%PUSH_FILE%" "%SIZE_FILE%" 2>nul
del "%DEV_FILE%" 2>nul
for /f "tokens=1*" %%a in ('"!HDC_BIN!" list targets 2^>nul') do (
if not "%%a"=="" echo %%a >>"%DEV_FILE%"
)
if not exist "%DEV_FILE%" (
echo Error: No device found. Run 'hdc list targets' to check connected devices.
popd
exit /b 5
)
for %%F in ("%DEV_FILE%") do if %%~zF equ 0 (
echo Error: No device found. Run 'hdc list targets' to check connected devices.
popd
exit /b 5
)
echo Devices:
type "%DEV_FILE%"
echo Build modes:
if "!HAS_DEBUG!"=="1" echo debug
if "!HAS_RELEASE!"=="1" echo release
echo ------------------------------------------------------------
set "TOTAL_COUNT=0"
set "SUCCESS_COUNT=0"
for /f "usebackq delims=" %%D in ("%DEV_FILE%") do (
set "TID=%%D"
set "TID=!TID: =!"
if not "!TID!"=="" (
set "TARGET_ID=!TID!"
if "!HAS_DEBUG!"=="1" (set "BUILD_MODE=debug" & call :one_combo)
if "!HAS_RELEASE!"=="1" (set "BUILD_MODE=release" & call :one_combo)
)
)
call :get_epoch SCRIPT_END_TIME
echo.
echo ==============================================
echo 打包结果统计 / Packing Result Summary
echo ==============================================
echo 总次数 Total: !TOTAL_COUNT!
echo 推包成功 Success: !SUCCESS_COUNT!
if !TOTAL_COUNT! gtr 0 (
set /a RATE_PCT=!SUCCESS_COUNT!*100/!TOTAL_COUNT!
echo 通过率 Rate: !SUCCESS_COUNT!/!TOTAL_COUNT! = !RATE_PCT!%%
) else (
echo 通过率 Rate: N/A
)
set /a SCRIPT_ELAPSED=!SCRIPT_END_TIME!-!START_TIME!
echo 脚本总耗时: !SCRIPT_ELAPSED!s
echo ==============================================
if exist "%ERR_FILE%" (
echo.
echo ----------------------------------------------
echo 错误信息汇总
echo ----------------------------------------------
type "%ERR_FILE%"
echo ----------------------------------------------
)
if exist "%PUSH_FILE%" (
echo.
echo ----------------------------------------------
echo Push Time 汇总
echo ----------------------------------------------
type "%PUSH_FILE%"
echo ----------------------------------------------
)
if exist "%SIZE_FILE%" (
echo.
echo ----------------------------------------------
echo 包大小汇总
echo ----------------------------------------------
type "%SIZE_FILE%"
echo ----------------------------------------------
)
rd /s /q "%RUNOHOS_TMP%" 2>nul
popd
if !SUCCESS_COUNT! lss !TOTAL_COUNT! exit /b 1
exit /b 0
:prompt_build_modes_auto
if /i "!RUNOHOS_NO_MENU!"=="1" (
set "BUILD_MODES_SELECT=all"
exit /b 0
)
echo.
echo 请选择打包类型(输入数字后回车):
echo 1 = 仅 debug
echo 2 = 仅 release
echo 3 = debug + release(全部)
set "BMENU="
set /p "BMENU=请输入 1 / 2 / 3 [默认 3]: "
if "!BMENU!"=="" set "BMENU=3"
if "!BMENU!"=="1" set "BUILD_MODES_SELECT=debug" & exit /b 0
if "!BMENU!"=="2" set "BUILD_MODES_SELECT=release" & exit /b 0
if "!BMENU!"=="3" set "BUILD_MODES_SELECT=all" & exit /b 0
echo 无效输入,使用默认 3(debug+release)
set "BUILD_MODES_SELECT=all"
exit /b 0
:get_epoch
set "_epf=%TEMP%\ro_epoch_!RANDOM!.txt"
set "RO_EPOCH=!_epf!"
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$n=[int](Get-Date -UFormat '%%s'); $b=[Text.Encoding]::ASCII.GetBytes([string]$n); [IO.File]::WriteAllBytes($env:RO_EPOCH,$b)"
set "RO_EPOCH="
set "_epl="
for /f "usebackq delims=" %%L in ("!_epf!") do set "_epl=%%L"
del "!_epf!" 2>nul
set "%~1=!_epl!"
exit /b 0
:usage
echo Usage: %~nx0 ^[options^] ^[PLATFORM^]
echo.
echo Parameters:
echo PLATFORM Build platform ^(default: %DEFAULT_PLATFORM%^)
echo Note devices from hdc list targets, no TARGET_ID argument
echo.
echo Options:
echo -M MODES 打包类型: debug ^| release ^| all ^(不传 -M 时提示输入 1/2/3;设 RUNOHOS_NO_MENU=1 则默认 all^)
echo -m MODE Build mode: debug or release ^(default: debug^)
echo -b BUNDLE Set bundle name ^(current: %DEFAULT_BUNDLE_NAME%^)
echo -a ABILITY Set Ability name ^(current: %DEFAULT_ABILITY_NAME%^)
echo -d MODE Debug mode: debug or attach ^(default: attach^)
echo -p PATH Set external OHOS project path ^(localOhosPath^)
echo -h Show this help message
echo.
echo Examples:
echo %~nx0 ohosArm64
echo %~nx0 -M debug
echo %~nx0 -M release
echo %~nx0 -M all
echo %~nx0 -b com.test.app -a MainAbility
echo %~nx0 -p D:\path\to\external\ohos\project
exit /b 0
:one_combo
set /a TOTAL_COUNT+=1
echo.
echo !TARGET_ID! 设备 !BUILD_MODE! 模式 进行打包
cd /d "!SCRIPT_DIR!"
set "ENTRY_BASE=!SCRIPT_DIR!\harmonyApp\entry"
set "CHECK_BASE=!SCRIPT_DIR!\harmonyApp"
set "HAP_PATH=!CHECK_BASE!\entry\build\default\outputs\default\entry-default-signed.hap"
set "LIBS_ARM=!CHECK_BASE!\entry\libs\arm64-v8a"
set "LIBS_X86=!CHECK_BASE!\entry\libs\x86_64"
set "DEL_RETRY=0"
:cleanup_loop
if exist "!ENTRY_BASE!\builds" rmdir /s /q "!ENTRY_BASE!\builds" 2>nul
if exist "!ENTRY_BASE!\build" rmdir /s /q "!ENTRY_BASE!\build" 2>nul
if exist "!ENTRY_BASE!\libs\" (
for /r "!ENTRY_BASE!\libs" %%F in (*.so) do if exist "%%F" del /f /q "%%F" 2>nul
)
if exist "!ENTRY_BASE!\libs\arm64-v8a" rmdir /s /q "!ENTRY_BASE!\libs\arm64-v8a" 2>nul
if exist "!ENTRY_BASE!\libs\x86_64" rmdir /s /q "!ENTRY_BASE!\libs\x86_64" 2>nul
set "HAP_EXISTS=0"
if exist "!HAP_PATH!" set "HAP_EXISTS=1"
set "LIBS_EXISTS=0"
if exist "!LIBS_ARM!" set "LIBS_EXISTS=1"
if exist "!LIBS_X86!" set "LIBS_EXISTS=1"
if exist "!ENTRY_BASE!\libs\" (
for /r "!ENTRY_BASE!\libs" %%F in (*.so) do (
if exist "%%F" set "LIBS_EXISTS=1"
)
)
if "!HAP_EXISTS!"=="0" if "!LIBS_EXISTS!"=="0" (
echo 删除后检测: HAP包=无, libs中间产物=无,已确认清理完成
goto cleanup_ok
)
set /a DEL_RETRY+=1
if !DEL_RETRY! geq 5 (
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:清理未完全,HAP包=!HAP_EXISTS!, libs中间产物=!LIBS_EXISTS!,须清光后再打包^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:清理未完全^)
cd /d "!SCRIPT_DIR!"
exit /b 1
)
timeout /t 1 /nobreak >nul
goto cleanup_loop
:cleanup_ok
"!HDC_BIN!" -t !TARGET_ID! shell aa force-stop !BUNDLE_NAME! 2>nul
set "GRADLE_OUT=%RUNOHOS_TMP%\gradle_!RANDOM!.txt"
del "!GRADLE_OUT!" 2>nul
if "!PLATFORM!"=="ohosArm64" goto gradle_ohos
if "!PLATFORM!"=="ohosX86_64" goto gradle_ohos
if "!PLATFORM!"=="iosSimulatorArm64" (
echo ^>^>^> :composeApp:linkDebugFrameworkIosSimulatorArm64
call gradlew.bat :composeApp:linkDebugFrameworkIosSimulatorArm64 1>"!GRADLE_OUT!" 2>&1
if errorlevel 1 (type "!GRADLE_OUT!" & goto gradle_fail)
type "!GRADLE_OUT!"
goto gradle_ok
)
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:不支持的平台 !PLATFORM!^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:不支持的平台 !PLATFORM!^)
cd /d "!SCRIPT_DIR!"
exit /b 1
:gradle_ohos
if /i "!BUILD_MODE!"=="release" (
echo ^>^>^> :composeApp:publishReleaseBinariesToHarmonyApp
if not "!LOCAL_OHOS_PATH!"=="" (
call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyApp -PharmonyAppPath="!LOCAL_OHOS_PATH!" 1>"!GRADLE_OUT!" 2>&1
) else call gradlew.bat :composeApp:publishReleaseBinariesToHarmonyApp 1>"!GRADLE_OUT!" 2>&1
) else (
echo ^>^>^> :composeApp:publishDebugBinariesToHarmonyApp
if not "!LOCAL_OHOS_PATH!"=="" (
call gradlew.bat :composeApp:publishDebugBinariesToHarmonyApp -PharmonyAppPath="!LOCAL_OHOS_PATH!" 1>"!GRADLE_OUT!" 2>&1
) else call gradlew.bat :composeApp:publishDebugBinariesToHarmonyApp 1>"!GRADLE_OUT!" 2>&1
)
if errorlevel 1 (type "!GRADLE_OUT!" & goto gradle_fail)
type "!GRADLE_OUT!"
goto gradle_ok
:gradle_fail
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:Gradle publish 未成功^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:Gradle publish 未成功^)
echo ^>^>^> 命令错误输出(含具体文件/配置报错^):
powershell -NoProfile -Command "Get-Content \"!GRADLE_OUT!\" -Tail 80"
del "!GRADLE_OUT!" 2>nul
cd /d "!SCRIPT_DIR!"
exit /b 1
:gradle_ok
del "!GRADLE_OUT!" 2>nul
call :get_epoch HAP_START_TIME
if not "!LOCAL_OHOS_PATH!"=="" (set "HARMONY_APP_DIR=!LOCAL_OHOS_PATH!") else (set "HARMONY_APP_DIR=!SCRIPT_DIR!\harmonyApp")
if not exist "!HARMONY_APP_DIR!" (
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:harmonyApp 目录不存在 !HARMONY_APP_DIR!^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:harmonyApp 目录不存在^)
cd /d "!SCRIPT_DIR!"
exit /b 1
)
cd /d "!HARMONY_APP_DIR!"
set "HVIGOR_OUT=%RUNOHOS_TMP%\hvigor_!RANDOM!.txt"
call ohpm install --all 1>"!HVIGOR_OUT!" 2>&1
if errorlevel 1 (
type "!HVIGOR_OUT!"
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:ohpm install 失败^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:ohpm install 失败^)
echo ^>^>^> 命令错误输出:
powershell -NoProfile -Command "Get-Content \"!HVIGOR_OUT!\" -Tail 80"
del "!HVIGOR_OUT!" 2>nul
cd /d "!SCRIPT_DIR!"
exit /b 1
)
type "!HVIGOR_OUT!"
del "!HVIGOR_OUT!" 2>nul
call node "!DEVECO_PATH!\tools\hvigor\bin\hvigorw.js" --sync -p product=default -p buildMode=!BUILD_MODE! --analyze=normal --parallel --incremental --daemon 1>"!HVIGOR_OUT!" 2>&1
if errorlevel 1 (
type "!HVIGOR_OUT!"
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:hvigor --sync 失败,请查看下方输出中的文件/配置名^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:hvigor --sync 失败^)
echo ^>^>^> 命令错误输出:
powershell -NoProfile -Command "Get-Content \"!HVIGOR_OUT!\" -Tail 80"
del "!HVIGOR_OUT!" 2>nul
cd /d "!SCRIPT_DIR!"
exit /b 1
)
type "!HVIGOR_OUT!"
del "!HVIGOR_OUT!" 2>nul
if /i "!BUILD_MODE!"=="release" (
call node "!DEVECO_PATH!\tools\hvigor\bin\hvigorw.js" --mode module -p module=entry -p product=default -p buildMode=release -p requiredDeviceType=phone assembleHap compileNative --analyze=normal --parallel --incremental --daemon 1>"!HVIGOR_OUT!" 2>&1
) else (
call node "!DEVECO_PATH!\tools\hvigor\bin\hvigorw.js" --mode module -p module=entry@default -p product=default -p buildMode=debug -p requiredDeviceType=phone assembleHap --analyze=normal --parallel --incremental --daemon 1>"!HVIGOR_OUT!" 2>&1
)
if errorlevel 1 (
type "!HVIGOR_OUT!"
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:hvigor assembleHap 失败,请查看下方输出中的文件/配置名^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:hvigor assembleHap 失败^)
echo ^>^>^> 命令错误输出:
powershell -NoProfile -Command "Get-Content \"!HVIGOR_OUT!\" -Tail 80"
del "!HVIGOR_OUT!" 2>nul
cd /d "!SCRIPT_DIR!"
exit /b 1
)
type "!HVIGOR_OUT!"
del "!HVIGOR_OUT!" 2>nul
set "SIGNED_HAP=entry-default-signed.hap"
set "HAP_FILE=entry\build\default\outputs\default\!SIGNED_HAP!"
if not exist "!HAP_FILE!" (
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:未找到已签名 HAP 包 !HAP_FILE!^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:未找到已签名 HAP 包^)
cd /d "!SCRIPT_DIR!"
exit /b 1
)
set "LIST_OUT=%RUNOHOS_TMP%\list_!RANDOM!.txt"
"!HDC_BIN!" list targets 1>"!LIST_OUT!" 2>nul
findstr /c:"!TARGET_ID!" "!LIST_OUT!" >nul
if errorlevel 1 (
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:设备离线或未连接^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:设备离线或未连接^)
del "!LIST_OUT!" 2>nul
cd /d "!SCRIPT_DIR!"
exit /b 1
)
del "!LIST_OUT!" 2>nul
set "HAP_FILE_ABS=!CD!\entry\build\default\outputs\default\!SIGNED_HAP!"
set "REMOTE_HAP_DIR=/data/local/tmp/debug_install"
set "REMOTE_HAP_PATH=!REMOTE_HAP_DIR!/!SIGNED_HAP!"
"!HDC_BIN!" -t !TARGET_ID! shell bm uninstall -n !BUNDLE_NAME! 2>nul
"!HDC_BIN!" -t !TARGET_ID! shell mkdir -p !REMOTE_HAP_DIR!
"!HDC_BIN!" -t !TARGET_ID! file send "!HAP_FILE_ABS!" !REMOTE_HAP_DIR!
set "INST_OUT=%RUNOHOS_TMP%\inst_!RANDOM!.txt"
"!HDC_BIN!" -t !TARGET_ID! shell bm install -p "!REMOTE_HAP_PATH!" 1>"!INST_OUT!" 2>&1
type "!INST_OUT!"
timeout /t 1 /nobreak >nul
findstr /i /c:"failed" /c:"error" "!INST_OUT!" >nul
if not errorlevel 1 (
"!HDC_BIN!" -t !TARGET_ID! shell bm uninstall -n !BUNDLE_NAME! 2>nul
timeout /t 5 /nobreak >nul
"!HDC_BIN!" -t !TARGET_ID! shell bm install -p "!REMOTE_HAP_PATH!" 1>"!INST_OUT!" 2>&1
type "!INST_OUT!"
timeout /t 5 /nobreak >nul
)
findstr /i /c:"failed" /c:"error" "!INST_OUT!" >nul
if not errorlevel 1 (
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:安装失败 bm install^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:安装失败 bm install^)
type "!INST_OUT!"
del "!INST_OUT!" 2>nul
cd /d "!SCRIPT_DIR!"
exit /b 1
)
del "!INST_OUT!" 2>nul
"!HDC_BIN!" -t !TARGET_ID! shell rm -rf !REMOTE_HAP_DIR! 2>nul
timeout /t 1 /nobreak >nul
if /i "!DEBUG_MODE!"=="debug" (
"!HDC_BIN!" -t !TARGET_ID! shell aa start -a !ABILITY_NAME! -b !BUNDLE_NAME! -D 1>"%RUNOHOS_TMP%\aa.txt" 2>&1
) else (
"!HDC_BIN!" -t !TARGET_ID! shell aa start -a !ABILITY_NAME! -b !BUNDLE_NAME! 1>"%RUNOHOS_TMP%\aa.txt" 2>&1
)
type "%RUNOHOS_TMP%\aa.txt"
call :get_epoch END_TIME
findstr /i /c:"10106102" /c:"screen is locked" "%RUNOHOS_TMP%\aa.txt" >nul
if not errorlevel 1 (
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:设备屏幕已锁定,请解锁后重试^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:设备屏幕已锁定^)
cd /d "!SCRIPT_DIR!"
exit /b 1
)
set /a COUNT=0
:wait_pid
set "APP_PID="
for /f "tokens=1" %%i in ('"!HDC_BIN!" -t !TARGET_ID! shell pidof !BUNDLE_NAME! 2^>nul') do set "APP_PID=%%i"
if not "!APP_PID!"=="" goto got_pid
timeout /t 1 /nobreak >nul
set /a COUNT+=1
if !COUNT! lss 45 goto wait_pid
echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:应用在 45s 内未启动,请检查设备与安装结果^)
>>"%ERR_FILE%" echo 错误的 !TARGET_ID! 设备 !BUILD_MODE! 模式(原因:应用未启动^)
echo ^>^>^> aa start 输出见上方 type 日志
cd /d "!SCRIPT_DIR!"
exit /b 1
:got_pid
set /a ELAPSED_SO=!HAP_START_TIME!-!START_TIME!
set /a M=!ELAPSED_SO!/60
set /a S=!ELAPSED_SO!%%60
set /a ELAPSED_HAP=!END_TIME!-!HAP_START_TIME!
set /a M2=!ELAPSED_HAP!/60
set /a S2=!ELAPSED_HAP!%%60
set /a ELAPSED_TOT=!END_TIME!-!START_TIME!
set /a M3=!ELAPSED_TOT!/60
set /a S3=!ELAPSED_TOT!%%60
echo - SO build time: !M!m!S!s ^(!ELAPSED_SO!s^)
echo - HAP package and push time: !M2!m!S2!s ^(!ELAPSED_HAP!s^)
echo - Total time: !M3!m!S3!s ^(!ELAPSED_TOT!s^)
set "HAP_BYTES="
if exist "!HAP_FILE_ABS!" for %%Z in ("!HAP_FILE_ABS!") do set "HAP_BYTES=%%~zZ"
if defined HAP_BYTES if !HAP_BYTES! gtr 0 (
set "SIZE_STR=!HAP_BYTES! B"
if !HAP_BYTES! geq 1048576 (set /a MB=!HAP_BYTES!/1048576 & set "SIZE_STR=!MB! MB ^(!HAP_BYTES! B^)") else if !HAP_BYTES! geq 1024 (set /a KB=!HAP_BYTES!/1024 & set "SIZE_STR=!KB! KB ^(!HAP_BYTES! B^)")
echo - HAP 包大小: !SIZE_STR!
>>"%SIZE_FILE%" echo !TARGET_ID! ^| !BUILD_MODE! ^| !SIZE_STR!
)
>>"%PUSH_FILE%" echo !TARGET_ID! ^| !BUILD_MODE! ^| SO:!ELAPSED_SO!s HAP+push:!ELAPSED_HAP!s 总:!ELAPSED_TOT!s
echo !TARGET_ID! 设备 !BUILD_MODE! 模式 打包成功
set /a SUCCESS_COUNT+=1
cd /d "!SCRIPT_DIR!"
exit /b 0
#!/bin/bash
#
# Uninstall this project's OHOS app from all hdc-connected devices.
# bundleName is read from harmonyApp/AppScope/app.json5 (override with -b).
# After uninstall, local harmonyApp/entry build / HAP / intermediates are removed by default.
# Use -c when there is no device: skip uninstall but still clean local artifacts (or hdc missing).
#
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_JSON5="$SCRIPT_DIR/harmonyApp/AppScope/app.json5"
APP_JSON5="$DEFAULT_JSON5"
BUNDLE_OVERRIDE=""
DO_CLEAN=0
usage() {
echo "Usage: $0 [options]"
echo " -c No-device mode: only clean local entry/build, .cxx, libs (still uninstalls if devices exist)"
echo " -j PATH Path to app.json5 (default: harmonyApp/AppScope/app.json5 under script dir)"
echo " -b NAME Override bundle name (skip reading app.json5)"
echo " -h Help"
exit 0
}
while [[ $# -gt 0 ]]; do
case $1 in
-c) DO_CLEAN=1; shift ;;
-j) APP_JSON5="$2"; shift 2 ;;
-b) BUNDLE_OVERRIDE="$2"; shift 2 ;;
-h) usage ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
if [[ -n "$BUNDLE_OVERRIDE" ]]; then
BUNDLE_NAME="$BUNDLE_OVERRIDE"
else
if [[ ! -f "$APP_JSON5" ]]; then
echo "Error: app.json5 not found: $APP_JSON5"
exit 1
fi
BUNDLE_NAME=$(grep '"bundleName"' "$APP_JSON5" 2>/dev/null | sed 's/.*"bundleName"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' | head -1 | tr -d '\r')
if [[ -z "$BUNDLE_NAME" ]]; then
echo "Error: could not parse bundleName from $APP_JSON5"
exit 1
fi
fi
clean_harmony_entry() {
local base="$SCRIPT_DIR/harmonyApp/entry"
if [[ ! -d "$base" ]]; then
echo "Warning: entry directory not found: $base"
return 0
fi
rm -rf "$base/builds" "$base/build" "$base/.cxx"
if [[ -d "$base/libs" ]]; then
find "$base/libs" -type f \( -name '*.so' -o -name '*.SO' \) -delete 2>/dev/null || true
fi
rm -rf "$base/libs/arm64-v8a" "$base/libs/x86_64"
echo "Local clean: entry/build, builds, .cxx, all *.so under libs, libs/arm64-v8a, libs/x86_64"
}
run_uninstall_all() {
local hdc_bin="$1"
shift
local -a ids=("$@")
echo "Bundle: $BUNDLE_NAME"
echo "Targets: ${ids[*]}"
echo "------------------------------------------------------------"
local tid
for tid in "${ids[@]}"; do
echo "[$tid] aa force-stop (ignore errors)"
"$hdc_bin" -t "$tid" shell aa force-stop "$BUNDLE_NAME" 2>/dev/null || true
echo "[$tid] bm uninstall -n $BUNDLE_NAME"
"$hdc_bin" -t "$tid" shell bm uninstall -n "$BUNDLE_NAME" 2>&1 || true
done
echo "------------------------------------------------------------"
echo "Uninstall attempted on ${#ids[@]} device(s) for bundle $BUNDLE_NAME"
}
if [[ $DO_CLEAN -eq 1 ]]; then
DEVECO_PATH="${DEVECO_PATH:-/Applications/DevEco-Studio.app}"
DEVECO_HOME="${DEVECO_HOME:-$DEVECO_PATH/Contents}"
HDC_BIN="$DEVECO_HOME/sdk/default/openharmony/toolchains/hdc"
DEVICE_IDS=()
if [[ -d "$DEVECO_PATH" && -x "$HDC_BIN" ]]; then
while IFS= read -r line; do
line=$(echo "$line" | tr -d '\r' | xargs)
[[ -n "$line" ]] && DEVICE_IDS+=("$line")
done < <("$HDC_BIN" list targets 2>/dev/null | awk '{if (NF>=1) print $1}')
fi
if [[ ${#DEVICE_IDS[@]} -gt 0 ]]; then
echo "Scanning devices (hdc list targets)..."
run_uninstall_all "$HDC_BIN" "${DEVICE_IDS[@]}"
else
if [[ -d "$DEVECO_PATH" && -x "$HDC_BIN" ]]; then
echo "No connected device; skip uninstall."
else
echo "hdc not available; skip uninstall."
fi
fi
echo "Cleaning local harmonyApp/entry artifacts..."
clean_harmony_entry
echo "Done."
exit 0
fi
DEVECO_PATH="${DEVECO_PATH:-/Applications/DevEco-Studio.app}"
if [[ ! -d "$DEVECO_PATH" ]]; then
echo "Error: DevEco Studio not found at $DEVECO_PATH. Set DEVECO_PATH."
exit 1
fi
DEVECO_HOME="${DEVECO_HOME:-$DEVECO_PATH/Contents}"
HDC_BIN="$DEVECO_HOME/sdk/default/openharmony/toolchains/hdc"
if [[ ! -x "$HDC_BIN" ]]; then
echo "Error: hdc not found at $HDC_BIN"
exit 1
fi
echo "Scanning devices (hdc list targets)..."
DEVICE_IDS=()
while IFS= read -r line; do
line=$(echo "$line" | tr -d '\r' | xargs)
[[ -n "$line" ]] && DEVICE_IDS+=("$line")
done < <("$HDC_BIN" list targets 2>/dev/null | awk '{if (NF>=1) print $1}')
if [[ ${#DEVICE_IDS[@]} -eq 0 ]]; then
echo "Error: no device found. Connect device and run: hdc list targets"
exit 1
fi
run_uninstall_all "$HDC_BIN" "${DEVICE_IDS[@]}"
echo "Cleaning local harmonyApp/entry artifacts..."
clean_harmony_entry
echo "Done."
@echo off
setlocal EnableDelayedExpansion
REM Uninstall this project's OHOS app from all hdc-connected devices.
REM bundleName from harmonyApp\AppScope\app.json5 unless -b overrides.
REM After uninstall, local entry build / HAP / intermediates are removed by default.
REM -c: no-device mode — still clean local dirs; uninstalls only if hdc and devices exist.
pushd "%~dp0"
set "SCRIPT_DIR=%CD%"
set "APP_JSON5=%SCRIPT_DIR%\harmonyApp\AppScope\app.json5"
set "BUNDLE_NAME="
set "CLEAN=0"
:parse
if "%~1"=="" goto done_parse
if /i "%~1"=="-c" (set "CLEAN=1" & shift & goto parse)
if /i "%~1"=="-j" (set "APP_JSON5=%~2" & shift & shift & goto parse)
if /i "%~1"=="-b" (set "BUNDLE_NAME=%~2" & shift & shift & goto parse)
if /i "%~1"=="-h" goto show_help
echo Unknown option: %~1
goto show_help
:done_parse
if "!BUNDLE_NAME!"=="" (
if not exist "!APP_JSON5!" (
echo Error: app.json5 not found: !APP_JSON5!
popd
exit /b 1
)
for /f "usebackq tokens=4 delims=^"" %%V in (`findstr /l /c:"bundleName" "!APP_JSON5!"`) do (
set "BUNDLE_NAME=%%V"
set "BUNDLE_NAME=!BUNDLE_NAME:,=!"
)
)
if "!BUNDLE_NAME!"=="" (
echo Error: could not parse bundleName from !APP_JSON5!
popd
exit /b 1
)
if "!CLEAN!"=="1" goto do_clean_combo
if "!DEVECO_PATH!"=="" (
if exist "C:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=C:\Program Files\Huawei\DevEco Studio"
) else if exist "D:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=D:\Program Files\Huawei\DevEco Studio"
) else (
echo Error: DevEco Studio not found. Set DEVECO_PATH.
popd
exit /b 1
)
)
set "HDC_BIN=!DEVECO_PATH!\sdk\default\openharmony\toolchains\hdc.exe"
if not exist "!HDC_BIN!" (
echo Error: hdc not found at !HDC_BIN!
popd
exit /b 1
)
echo Scanning devices ^(hdc list targets^)...
set "DEV_FILE=%TEMP%\uninstall_ohos_dev_%RANDOM%.txt"
del "!DEV_FILE!" 2>nul
for /f "tokens=1*" %%a in ('"!HDC_BIN!" list targets 2^>nul') do (
if not "%%a"=="" echo %%a >>"!DEV_FILE!"
)
if not exist "!DEV_FILE!" (
echo Error: no device found. Connect device and run: hdc list targets
popd
exit /b 1
)
for %%F in ("!DEV_FILE!") do if %%~zF equ 0 (
echo Error: no device found. Connect device and run: hdc list targets
del "!DEV_FILE!" 2>nul
popd
exit /b 1
)
echo Bundle: !BUNDLE_NAME!
echo Targets:
type "!DEV_FILE!"
echo ------------------------------------------------------------
for /f "usebackq delims=" %%T in ("!DEV_FILE!") do (
set "TID=%%T"
set "TID=!TID: =!"
if not "!TID!"=="" call :uninstall_one "!TID!"
)
del "!DEV_FILE!" 2>nul
echo Cleaning local harmonyApp\entry artifacts...
call :clean_entry
echo ------------------------------------------------------------
echo Done. Uninstall attempted for bundle !BUNDLE_NAME!
popd
exit /b 0
:do_clean_combo
if "!DEVECO_PATH!"=="" (
if exist "C:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=C:\Program Files\Huawei\DevEco Studio"
) else if exist "D:\Program Files\Huawei\DevEco Studio" (
set "DEVECO_PATH=D:\Program Files\Huawei\DevEco Studio"
)
)
set "HDC_BIN="
if not "!DEVECO_PATH!"=="" (
set "HDC_BIN=!DEVECO_PATH!\sdk\default\openharmony\toolchains\hdc.exe"
)
if exist "!HDC_BIN!" (
set "DEV_FILE=%TEMP%\uninstall_ohos_dev_%RANDOM%.txt"
del "!DEV_FILE!" 2>nul
for /f "tokens=1*" %%a in ('"!HDC_BIN!" list targets 2^>nul') do (
if not "%%a"=="" echo %%a >>"!DEV_FILE!"
)
set "HAS_DEV=0"
if exist "!DEV_FILE!" for %%F in ("!DEV_FILE!") do if %%~zF gtr 0 set "HAS_DEV=1"
if "!HAS_DEV!"=="1" (
echo Scanning devices ^(hdc list targets^)...
echo Bundle: !BUNDLE_NAME!
echo Targets:
type "!DEV_FILE!"
echo ------------------------------------------------------------
for /f "usebackq delims=" %%T in ("!DEV_FILE!") do (
set "TID=%%T"
set "TID=!TID: =!"
if not "!TID!"=="" call :uninstall_one "!TID!"
)
echo ------------------------------------------------------------
echo Uninstall attempted for bundle !BUNDLE_NAME!
) else (
echo No connected device; skip uninstall.
)
del "!DEV_FILE!" 2>nul
) else (
echo hdc not available; skip uninstall.
)
echo Cleaning local harmonyApp\entry artifacts...
call :clean_entry
echo Done.
popd
exit /b 0
:clean_entry
set "ENTRY_BASE=!SCRIPT_DIR!\harmonyApp\entry"
if not exist "!ENTRY_BASE!" (
echo Warning: entry directory not found: !ENTRY_BASE!
exit /b 0
)
if exist "!ENTRY_BASE!\builds" rmdir /s /q "!ENTRY_BASE!\builds" 2>nul
if exist "!ENTRY_BASE!\build" rmdir /s /q "!ENTRY_BASE!\build" 2>nul
if exist "!ENTRY_BASE!\.cxx" rmdir /s /q "!ENTRY_BASE!\.cxx" 2>nul
if exist "!ENTRY_BASE!\libs\" (
for /r "!ENTRY_BASE!\libs" %%F in (*.so) do if exist "%%F" del /f /q "%%F" 2>nul
)
if exist "!ENTRY_BASE!\libs\arm64-v8a" rmdir /s /q "!ENTRY_BASE!\libs\arm64-v8a" 2>nul
if exist "!ENTRY_BASE!\libs\x86_64" rmdir /s /q "!ENTRY_BASE!\libs\x86_64" 2>nul
echo Local clean: entry\build, builds, .cxx, all *.so under libs, libs\arm64-v8a, libs\x86_64
exit /b 0
:uninstall_one
set "TARGET_ID=%~1"
echo [!TARGET_ID!] aa force-stop ^(ignore errors^)
"!HDC_BIN!" -t !TARGET_ID! shell aa force-stop !BUNDLE_NAME! 2>nul
echo [!TARGET_ID!] bm uninstall -n !BUNDLE_NAME!
"!HDC_BIN!" -t !TARGET_ID! shell bm uninstall -n !BUNDLE_NAME!
exit /b 0
:show_help
echo Usage: %~nx0 [options]
echo -c No-device mode: clean local entry build; uninstall if devices exist
echo -j PATH Path to app.json5 ^(default: harmonyApp\AppScope\app.json5^)
echo -b NAME Override bundle name
echo -h Show help
popd
exit /b 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment