本文将讨论如何在x86架构的Linux电脑,用ReDroid玩ARM架构的手机游戏。我们会在ReDroid映像档加入ARM转译器+Google服务框架,以达成最佳使用体验。
PS Windows和MacOS也可以跑Docker。
1. ReDroid需要用到的软体
ReDroid在Github上有各大Linux发行版的安装说明。
- 由于我是Arch Linux,要先补齐Linux核心模组binderfs。
- 接着安装docker和docker-compose,用于执行容器
- 安装ADB和Scrcpy,连线到Android桌面:
# archlinux
sudo pacman -S android-tools
sudo pacman -S scrcpy
- 下载用于传输音效的sndcpy,将其解压缩。
*想要Scrcpy和Sndcpy二者整合和按键映射的,可以试试看QtScrcpy。
2. 取得ARM转译器libndk
大部分电脑是x86架构,只能执行x86版的Android APP,然而很多手机游戏只有ARM版。所以跑ReDroid前建议先下载ARM转译器,不然能执行的APP会少很多。
ReDroid支援用QEMU或libndk转译,本文采用后者。libndk是Google开发的ARM → x86转译器,含在Android Studio的模拟器里。注意libndk是专有软体,使用上处于灰色地带。
- 你可以用Droid-NDK-Extractor指令稿从Android 11模拟器映像档抽取libndk:
sudo pacman -S sleuthkit p7zip binwalk git
cd ~
git clone https://github.com/sickcodes/Droid-NDK-Extractor.git
cd Droid-NDK-Extractor
chmod +x android-extract-ndk.sh
./android-extract-ndk.sh x86_64
- 之后会在工作目录的
/working/extracted/
下找到native-bridge.tar
,大约30MB。 - 切换到
native-bridge.tar
所在的目录,修正权限后重新压缩档案:
cd ~/Droid-NDK-Extractor/working/extracted/
mkdir native-bridge
cd native-bridge
tar -xpf ../native-bridge.tar
chmod 0644 system/etc/init/ndk_translation_arm64.rc
chmod 0755 system/bin/arm
chmod 0755 system/bin/arm64
chmod 0755 system/lib/arm
chmod 0755 system/lib64/arm64
chmod 0644 system/etc/binfmt_misc/*
tar -cpf native-bridge.tar system
mv native-bridge.tar ..
cd ..
rm -r native-bridge
- 至此ARM转译器
native-bridge.tar
准备完成。
3. 建置ReDroid的Docker映像档
ReDroid目前提供Android 8 ~ Android 13的映像档。由于要使用libndk的关系,故以Android 11的映像档为基础下去建置。
- 新增一个空白目录
android
,将刚刚制作的native-bridge.tar
放到此目录。 - 在
android
目录新增一个名为dockerfile
的档案,填入以下内容:
FROM redroid/redroid:11.0.0-amd64
ADD native-bridge.tar /
- 在
android
目录开启终端机,开始建置含有libndk的ReDroid映像档:
docker build . -t redroid-11-libndk
4. 启动ReDroid
如果要用ReDroid玩手机游戏,建议电脑至少要有8GB以上RAM,因为有时ARM在转译成x86指令时会占用大量RAM。
- 部署ReDroid。没加
--rm
是因为后续还要对系统做修改。
sudo docker run -itd --privileged \
-v /home/user/data11-nb:/data \
-p 5555:5555 \
redroid-11-libndk \
androidboot.redroid_gpu_mode=host \
ro.product.cpu.abilist=x86_64,arm64-v8a,x86,armeabi-v7a,armeabi \
ro.product.cpu.abilist64=x86_64,arm64-v8a \
ro.product.cpu.abilist32=x86,armeabi-v7a,armeabi \
ro.dalvik.vm.isa.arm=x86 \
ro.dalvik.vm.isa.arm64=x86_64 \
ro.enable.native.bridge.exec=1 \
ro.dalvik.vm.native.bridge=libndk_translation.so \
ro.ndk_translation.version=0.2.2
如果要用docker-compose.yml
,内容如下:
version: "3"
services:
redroid:
image: redroid-11-libndk
stdin_open: true
tty: true
privileged: true
ports:
- "5555:5555"
volumes:
- /home/user/data11-nb:/data
command:
- androidboot.redroid_gpu_mode=host
- ro.product.cpu.abilist0=x86_64,arm64-v8a,x86,armeabi-v7a,armeabi
- ro.product.cpu.abilist64=x86_64,arm64-v8a
- ro.product.cpu.abilist32=x86,armeabi-v7a,armeabi
- ro.dalvik.vm.isa.arm=x86
- ro.dalvik.vm.isa.arm64=x86_64
- ro.enable.native.bridge.exec=1
- ro.dalvik.vm.native.bridge=libndk_translation.so
- ro.ndk_translation.version=0.2.2
- 用ADB连线至本机的ReDroid:
adb connect localhost:5555
# 如果連不上,用以下指令看一下容器內部發生什麼問題
sudo docker logs <容器ID>
sudo docker exec <容器ID> logcat
- 执行Scrcpy,连线到Android桌面:
scrcpy -s localhost:5555
- 这样就会看到Android的桌面了。
- 至于声音的话,切换到
sndcpy
所在的目录,执行sndcpy
,开始串流音效:
./sndcpy localhost:5555
5. 安装Google服务框架
作者说Google服务框架是专有软体无法内建,那么就得自行安装了。第一个方法是重新编译映像档,第二个是手动安装OpenGApps。
不推荐第一个方法,耗时而且作者提供的GApps编译教学又有其他APP侦测不到的问题。
这里采用第二个方法:手动安装,过程参考自:Install GApps Manually - Google Groups
- 到OpenGapps下载x86_64架构的Android 11 GApps,选择最小化的pico版。
- 解压缩,会看到以下目录
open_gapps-x86_64-11.0-pico-20220503
├── Core
├── GApps
├── META-INF
├── Optional
- 在解压缩的目录新增
system
目录。 - 接着,将
Core
和GApps
目录里面的.lz
档案都解压缩,并将里面的APK目录按照对应的安装目录放到system
目录。例如GApps/googletts-x86_64/nodpi/app/
下的GoogleTTS
目录要放到/system/app
。 - 放好之后,
system
下的目录结构应该会长这样:
system
├── app
│ ├── GoogleCalendarSyncAdapter
│ │ └── GoogleCalendarSyncAdapter.apk
│ ├── GoogleContactsSyncAdapter
│ │ └── GoogleContactsSyncAdapter.apk
│ ├── GoogleExtShared
│ │ └── GoogleExtShared.apk
│ └── GoogleTTS
│ └── GoogleTTS.apk
├── etc
│ ├── default-permissions
│ │ ├── default-permissions.xml
│ │ └── opengapps-permissions-q.xml
│ ├── permissions
│ │ ├── com.google.android.dialer.support.xml
│ │ ├── com.google.android.maps.xml
│ │ ├── com.google.android.media.effects.xml
│ │ ├── privapp-permissions-google.xml
│ │ └── split-permissions-google.xml
│ ├── preferred-apps
│ │ └── google.xml
│ └── sysconfig
│ ├── dialer_experience.xml
│ ├── google_build.xml
│ ├── google_exclusives_enable.xml
│ ├── google-hiddenapi-package-whitelist.xml
│ └── google.xml
├── framework
│ ├── com.google.android.dialer.support.jar
│ ├── com.google.android.maps.jar
│ └── com.google.android.media.effects.jar
├── priv-app
│ ├── AndroidAutoPrebuiltStub
│ │ └── AndroidAutoPrebuiltStub.apk
│ ├── AndroidMigratePrebuilt
│ │ └── AndroidMigratePrebuilt.apk
│ ├── CarrierSetup
│ │ └── CarrierSetup.apk
│ ├── ConfigUpdater
│ │ └── ConfigUpdater.apk
│ ├── GoogleBackupTransport
│ │ └── GoogleBackupTransport.apk
│ ├── GoogleExtServices
│ │ └── GoogleExtServices.apk
│ ├── GoogleFeedback
│ │ └── GoogleFeedback.apk
│ ├── GoogleOneTimeInitializer
│ │ └── GoogleOneTimeInitializer.apk
│ ├── GooglePackageInstaller
│ │ └── GooglePackageInstaller.apk
│ ├── GooglePartnerSetup
│ │ └── GooglePartnerSetup.apk
│ ├── GoogleRestore
│ │ └── GoogleRestore.apk
│ ├── GoogleServicesFramework
│ │ └── GoogleServicesFramework.apk
│ ├── Phonesky
│ │ └── Phonesky.apk
│ ├── PrebuiltGmsCore
│ │ └── PrebuiltGmsCore.apk
│ └── SetupWizard
│ └── SetupWizard.apk
└── product
└── overlay
└── PlayStoreOverlay.apk
- 执行以下指令取得root权限:
adb connect localhost:5555
adb -s localhost:5555 root
adb -s localhost:5555 remount
adb -s localhost:5555 shell "rm -rf system/priv-app/PackageInstaller"
- 接着将
system
目录推送到ReDroid系统,并赋予权限:
adb -s localhost:5555 push system /
adb -s localhost:5555 shell "pm grant com.google.android.gms android.permission.ACCESS_COARSE_LOCATION"
adb -s localhost:5555 shell "pm grant com.google.android.gms android.permission.ACCESS_FINE_LOCATION"
adb -s localhost:5555 shell "pm grant com.google.android.setupwizard android.permission.READ_PHONE_STATE"
adb -s localhost:5555 shell "pm grant com.google.android.setupwizard android.permission.READ_CONTACTS"
adb reboot
- 重新启动ReDroid容器:
docker ps
docker restart <ReDroid的容器ID>
- 启动Scrcpy,开启系统设定→应用程式,点选右上角显示系统应用程式,将Google Play服务和Play商店的权限都开启。
- 执行以下指令取得Android装置ID,到Google网站注册装置,等个30分钟后重新启动Redroid容器,才能登入Google Play。
adb -s localhost:5555 root
adb -s localhost:5555 shell 'sqlite3 /data/data/com.google.android.gsf/databases/gservices.db \
"select * from main where name = \"android_id\";"'
6. ReDroid安装APK
目前即使有安装libndk,Android 11的Play商店还是不给下载ARM架构的APP,请配合APKPure之类的应用程式商店安装APP。
除了用容器内部的浏览器下载APK外,你还可以用ADB安装APK至ReDroid容器。比方说到ApkMirror下载Line的APK,接着用ADB安装:
adb -s localhost:5555 install "jp.naver.line.android.apk"
你也可以用ADB的pull
和push
指令传输档案。
关于萤幕解析度的调整,请参阅ReDroid和Scrcpy的使用说明。
7. ReDroid如何「开关机」
如果要将ReDroid关机,将Scrcpy视窗关闭后,停止容器:
sudo docker ps
sudo docker stop <ReDroid的容器ID>
之后可以再用此指令启动ReDroid。ReDroid容器的/data
资料位于~/data11-nb
目录,可以用来备份多个系统的档案。
docker ps --filter "status=exited"
docker start <ReDroid的容器ID>
adb connect localhost:5555
scrcpy -s localhost:5555
8. 总结
目前来看,ReDroid的泛用性比Waydroid好,因为不只造福Linux使用者,连那些想摆脱专有模拟器、想自架云手机的用户都可以利用ReDroid达成目的。