跳到主要内容

让安卓应用像原生窗口一样开在 Linux 桌面上:Waydroid 多窗口实操

更新于 (2分钟前)查看源文

记录把 Waydroid 从「一整个安卓桌面」调成「每个应用一个独立窗口」的完整流程:镜像选择、window HAL 校验、安装 APK 的正确姿势,以及为什么很多镜像根本开不出多窗口。

Waydroid

Waydroid 默认给你的是「一整个安卓桌面」:一个窗口,里面是完整的 Android,应用都在里面跑。这和「像原生应用一样,在旁边开一个窗口」的体验差得很远。

好消息是 Waydroid 确实有多窗口模式(multi-window),开启后每个 Android 应用都是合成器里的一个独立 toplevel,可以和原生窗口切列、并排、浮动。坏消息是它能不能用,几乎完全取决于你装的是哪套镜像——这一点在文档里几乎没写。

下面是我在这台机器(Arch + niri + Waydroid 1.6.3)上跑通的最终流程。

不背单词在 niri 中作为独立窗口

最终效果

waydroid app launch cn.com.langeasy.LangEasyLexis 之后,桌面多出一个窗口:

app_id: waydroid.cn.com.langeasy.LangEasyLexis
title : 不背单词
size  : 1707x1033

再启动「设置」,又多一个 waydroid.com.android.settings 窗口,两个窗口同时存在。窗口没有服务端装饰(合成器本来也不画边框),其余行为与原生窗口一致。

前提:镜像必须带 window HAL

多窗口不是纯宿主侧的开关。Android 框架要把每个任务窗口导出成 Wayland surface,靠的是 vendor 侧的 HIDL HAL:[email protected]::IWaydroidWindow。

先启动会话,然后进容器验证:

waydroid session start &
sudo waydroid shell -- lshal | grep waydroid

能用的镜像会看到类似这样的行(DM, Y 表示清单已声明、框架兼容):

DM    Y [email protected]::IWaydroidWindow/default
DM    Y [email protected]::IWaydroidWindow/default

如果这里只看到 vendor.waydroid.task,或者什么都没有,那这套镜像就永远开不出多窗口。 我在一套第三方 Android 17 镜像上就是这种情况,logcat 里明确写着:

W WayDroidService: Waydroid window HAL unavailable
I hwservicemanager: Cannot find entry [email protected]::IWaydroidWindow/default

那套镜像里只有客户端 stub([email protected]),没有服务端实现;而且它的 system.img 是 EROFS 只读,多窗口还依赖把 pc.xml(android.hardware.type.pc)bind 到 /system/etc/permissions/,目标文件不存在又写不进去,规则直接失效。补 VINTF 声明也没用——没有服务进程,声明了照样找不到。

结论:换镜像,不要试图修补。

完整流程

1. 用官方镜像初始化

paru -S waydroid --needed
sudo waydroid init            # 官方 LineageOS 20 (Android 13) VANILLA + MAINLINE vendor

确认 images_path 指向这套官方镜像(/var/lib/waydroid/waydroid.cfg 里的 images_path)。第三方镜像如果是放在 /etc/waydroid-extra/images/ 那种,切回来改这一行即可。

2. 打开多窗口并持久化

waydroid session start &
waydroid prop set persist.waydroid.multi_windows true

prop set 只改运行期;要开机就生效,直接写进配置文件:

echo 'persist.waydroid.multi_windows=true' | sudo tee -a /var/lib/waydroid/waydroid.prop

然后重启会话让它进容器:

waydroid session stop
waydroid session start &
waydroid status            # Session: RUNNING / Container: RUNNING

3. 装 APK

waydroid app install ~/Downloads/app.apk

这条命令走的是 Waydroid 自己的 IPlatform.installApp,某些镜像上会因为缺 persistent_data_block 服务在 PackageInstallerSession.markAsSealed 抛异常而失败。稳妥的做法是绕开它,直接进容器用 pm:

mkdir -p ~/.local/share/waydroid/data/waydroid_tmp
cp ~/Downloads/app.apk ~/.local/share/waydroid/data/waydroid_tmp/
sudo waydroid shell -- pm install -r -g /data/waydroid_tmp/app.apk   # Success
sudo waydroid shell -- pm list packages -3                            # 确认包名

4. 启动应用

waydroid app launch cn.com.langeasy.LangEasyLexis

窗口就该出现了。多个应用分别 app launch 就是多个窗口。

三个坑

坑一:冷启动会弹出整个安卓桌面。 waydroid app launch 在会话未运行时,会用 background=False 起会话(session_manager.py → waydroid.background_start=false),Android 于是直接展示整套 UI。想只出应用窗口,必须先 waydroid session start(background=True),再 launch。

坑二:NoDisplay 与自动生成的桌面条目。 Waydroid 自带的 user_manager 服务会为每个 Android 应用生成 ~/.local/share/applications/waydroid.<包名>.desktop,图标导出到 ~/.local/share/waydroid/data/icons/。系统应用会自动带 NoDisplay=true,所以启动器里通常只多出你自己装的那几个。想自定义名称/图标,别去改它生成的那份(每次用户解锁都会被重写),另建一份、给它加 NoDisplay=true 更稳。

坑三:窗口尺寸交给合成器。 Waydroid 不负责窗口装饰和尺寸。用 niri 的话加一条规则就够了:

window-rule {
    match app-id=r#"^waydroid\."#
    default-column-width { proportion 0.5; }
}

取舍

官方 Android 13 VANILLA 镜像不带 Google 服务,这是多窗口能用的代价。需要 GApps 的话得自己给这套镜像打补丁(如 waydroid_script),而不是换回缺 window HAL 的新版第三方镜像。

另外,多窗口模式意味着你不再有一个「安卓桌面」可用:所有操作都得从应用窗口发起。如果偶尔确实需要整套 UI,waydroid show-full-ui 还能叫出来。

一句话总结:多窗口是镜像能力,不是开关能力。先 lshal | grep waydroid.window 确认服务在跑,再谈其他。

除另有说明,本文内容采用 CC BY-NC-SA 4.0 协议许可。转载或改编请署名、非商业使用,并以相同方式共享。

文章信息
作者: Omicron0314#Android#Linux#niri#运维