diff --git a/electron/main/backend/install-manager.ts b/electron/main/backend/install-manager.ts index aae163a4..fb00c500 100644 --- a/electron/main/backend/install-manager.ts +++ b/electron/main/backend/install-manager.ts @@ -396,4 +396,15 @@ ipcMain.handle('uninstall-installed', async (_event, pkgname: string) => { success, message: success ? '卸载完成' : (stderr || stdout || `卸载失败,退出码 ${code}`) }; +}); + +ipcMain.handle('launch-app', async (_event, pkgname: string) => { + if (!pkgname) { + logger.warn('No pkgname provided for launch-app'); + } + + const execCommand = 'dbus-launch'; + const execParams = ['/opt/apm-app-store/extras/apm-launcher', 'start', pkgname]; + + await runCommandCapture(execCommand, execParams); }); \ No newline at end of file diff --git a/extras/apm-launcher b/extras/apm-launcher new file mode 100755 index 00000000..e844bb67 --- /dev/null +++ b/extras/apm-launcher @@ -0,0 +1,105 @@ +#!/bin/bash + +# ===== 日志函数(简化版)===== +log.info() { echo "INFO: $*"; } +log.warn() { echo "WARN: $*"; } +log.error() { echo "ERROR: $*"; } +log.debug() { :; } # APM 场景下可禁用 debug 日志 + +# ===== APM 专用桌面文件扫描(单文件)===== +function scan_apm_desktop_log() { + unset desktop_file_path + local pkg_name="$1" + local desktop_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/${pkg_name}/entries/applications" + + [ -d "$desktop_dir" ] || return 1 + + while IFS= read -r -d '' path; do + [ -f "$path" ] || continue + if ! grep -q 'NoDisplay=true' "$path" 2>/dev/null; then + log.info "Found valid APM desktop file: $path" + export desktop_file_path="$path" + return 0 + fi + done < <(find "$desktop_dir" -name "*.desktop" -type f -print0 2>/dev/null) + + return 1 +} + +# ===== APM 专用桌面文件扫描(多文件列表)===== +function scan_apm_desktop_list() { + local pkg_name="$1" + local desktop_dir="/var/lib/apm/apm/files/ace-env/var/lib/apm/${pkg_name}/entries/applications" + local result="" + + [ -d "$desktop_dir" ] || { echo ""; return; } + + while IFS= read -r -d '' path; do + [ -f "$path" ] || continue + if ! grep -q 'NoDisplay=true' "$path" 2>/dev/null; then + result+="${path}," + fi + done < <(find "$desktop_dir" -name "*.desktop" -type f -print0 2>/dev/null) + + echo "${result%,}" +} + +# ===== 启动应用 ===== +function launch_app() { + local desktop_path="${1#file://}" + local exec_cmd + + # 提取并清理 Exec 行(移除字段代码如 %f %u 等) + exec_cmd=$(grep -m1 '^Exec=' "$desktop_path" | cut -d= -f2- | sed 's/%[fFuUdDnNickvm]*//g; s/^[[:space:]]*//; s/[[:space:]]*$//') + [ -z "$exec_cmd" ] && return 1 + + # ACE 环境内使用 host-spawn 在宿主显示图形界面 + [ -n "$IS_ACE_ENV" ] && exec_cmd="host-spawn $exec_cmd" + + log.info "Launching: $exec_cmd" + ${SHELL:-bash} -c "$exec_cmd" & +} + +# 导出函数供 ACE 环境调用 +export -f launch_app scan_apm_desktop_log scan_apm_desktop_list log.info log.error + +# ===== 主逻辑 ===== +[ $# -lt 2 ] && { + log.error "Usage: $0 {check|list|launch|start} " + exit 1 +} + +action="$1" +pkg_name="$2" + +case "$action" in + check) + if scan_apm_desktop_log "$pkg_name"; then + exit 0 + else + exit 1 + fi + ;; + + list) + if result=$(scan_apm_desktop_list "$pkg_name"); [ -n "$result" ]; then + echo "$result" + exit 0 + else + exit 1 + fi + ;; + + launch|start) + if scan_apm_desktop_log "$pkg_name" && launch_app "$desktop_file_path"; then + exit 0 + else + exit 1 + fi + ;; + + *) + log.error "Invalid command: $action (supported: check|list|launch|start)" + exit 2 + ;; +esac diff --git a/src/App.vue b/src/App.vue index c37b31f6..a163300d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -15,7 +15,7 @@ + @open-preview="openScreenPreview" @open-app="openDownloadedApp" /> @@ -536,11 +536,12 @@ const closeDownloadDetail = () => { currentDownload.value = null; }; -const openDownloadedApp = (download: DownloadItem) => { - const encodedPkg = encodeURIComponent(download.pkgname); - openApmStoreUrl(`apmstore://launch?pkg=${encodedPkg}`, { - fallbackText: `打开应用: ${download.pkgname}` - }); +const openDownloadedApp = (pkgname: string) => { + // const encodedPkg = encodeURIComponent(download.pkgname); + // openApmStoreUrl(`apmstore://launch?pkg=${encodedPkg}`, { + // fallbackText: `打开应用: ${download.pkgname}` + // }); + window.ipcRenderer.invoke('launch-app', pkgname); }; const loadCategories = async () => { diff --git a/src/components/AppDetailModal.vue b/src/components/AppDetailModal.vue index 787f3db8..c9642b17 100644 --- a/src/components/AppDetailModal.vue +++ b/src/components/AppDetailModal.vue @@ -29,12 +29,20 @@ {{ installFeedback ? '已加入队列' : '安装' }} - +