Android原生模拟器运行ARM APP
- INSTALL_FAILED_NO_MATCHING_ABIS
- Android原生APP安装微信(Android 6.0)
INSTALL_FAILED_NO_MATCHING_ABIS
安装APK的时候出现这个错误,其实是当你试图安装一个具有本地库的应用程序时,它没有你的CPU架构的本地库。例如,如果您为armv7编译了一个应用程序,并试图将其安装在使用英特尔架构的仿真器上,则无法正常工作。而Android Studio提供的模拟器是X86架构的,当然也有Arm架构的模拟器,只是慢得看不到开机成功的界面!
当你需要安装的APP是自己开发的APP时,你可以在build.gradle中加入以下代码(网上找的,没试过):
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a'
universalApk true
}
}
然而当你是需要安装微信等市场上的APP时,就不行了,因为大多数的APP是ARM架构,而不是X86,所以如果需要在Android原生模拟器上运行微信等APP,则需要一个ARM 到 X86 的指令集翻译器,能把apk里的arm用的so库在运行时动态地转换成x86的指令,所有x86的Android设备里都有这个,而Intel刚好提供了这样一个东西,只不过是闭源的。
Android原生APP安装微信(Android 6.0)
先贴一堆资料:
- 移动测试基础 Android 模拟器 Genymotion 安装配置与 ARM 支持
- Android Emulator - INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native
libraries, res=-113 - 如何打开Android X86对houdini的支持
- Android模拟器知识以及改造
- Github/Rprop/libhoudini
- Android-X86集成houdini(Arm兼容工具)
本篇文章主要参考:https://blog.imlk.top/,反复查看这位大佬的文章之后,最后成功运行微信,感谢大佬指路。
- 改build.prop里的ro.product.cpu.abilist和ro.product.cpu.abilist32为x86,armeabi-v7a,armeabi,骗过包安装器,让它能把微信装上(参考第4篇文章)
- 改default.prop里的ro.dalvik.vm.native.bridge=0为ro.dalvik.vm.native.bridge=libhoudini.so,开启系统内的NativeBridge(参考第4篇文章)
这里必须说一下,这个default.prop不在system.img里面,在ramdisk.img里面,ramdisk.img是只读的,只在启动的时候读一次到内存里。所以对default.prop的修改重启后会丢失,唯一的办法是手动编辑一个ramdisk.img,然后用emulator的-ramdisk选项指定修改后的ramdisk.img文件
emulator的参数可以到官网去查看
编辑的方法也不难,搜索cpio 就知道要怎么编辑了。
用gunzip解压它,再用cpio解包到一个目录里
在这目录里找到default.prop进行修改
在封ramdisk.img的时候,不要用cpio打包,可能会有问题导致开机不了(尝试了一次,真的开不了机),用mkbootfs ./你之前解包到的目录 最后的ramdisk-new.img就是修改过的ramdisk.img了,在启动avd时用emulator的-ramdisk选项指定它即可。 - 第3篇文章里面设置里那个叫Enable native
bridge的选项我一直没有找到,它说效果只是persist.sys.nativebridge从0改成了1,保险起见,我在build.prop里加了persist.sys.nativebridge=1(我尝试了一下,发现并没什么用) - 执行enable_nativebridge
这几篇文章里都提到了enable_nativebridge这个东西,但是我找了一番,我的AVD里面没有这个脚本,只要从网易的木木模拟器中提取出来。不过还好,在万能的github上面找到了一段enable_nativebridge,大概读一读能发现,恰好是Android7用的,而且考虑了各种情况,甚至还可以在线下载文件(显然访问不了,不过有办法解决的)
代码如下:
#!/system/bin/sh
PATH=/system/bin:/system/xbin
houdini_bin=0
dest_dir=/system/lib$1/arm$1
binfmt_misc_dir=/proc/sys/fs/binfmt_misc
if [ -z "$1" ]; then
if [ "`uname -m`" = "x86_64" ]; then
v=7_y
url=http://goo.gl/SBU3is
else
v=7_x
url=http://goo.gl/0IJs40
fi
else
v=7_z
url=http://goo.gl/FDrxVN
fi
if [ -s /system/lib$1/libhoudini.so ]; then
log -pi -thoudini "found /system/lib$1/libhoudini.so"
elif [ -e /system/etc/houdini$v.sfs ]; then
mount /system/etc/houdini$v.sfs $dest_dir
else
if mountpoint -q $dest_dir; then
kill -9 `fuser -m $dest_dir`
umount -f $dest_dir
fi
mkdir -p /data/arm
cd /data/arm
while ! mount houdini$v.sfs $dest_dir; do
while [ "$(getprop net.dns1)" = "" ]; do
sleep 10
done
wget $url -cO houdini$v.sfs && continue
rm -f houdini$v.sfs
sleep 30
done
fi
[ -s /system/lib$1/libhoudini.so ] || mount --bind $dest_dir/libhoudini.so /system/lib$1/libhoudini.so
# this is to add the supported binary formats via binfmt_misc
if [ ! -e $binfmt_misc_dir/register ]; then
mount -t binfmt_misc none $binfmt_misc_dir
fi
cd $binfmt_misc_dir
if [ -e register ]; then
[ -e /system/bin/houdini$1 ] && dest_dir=/system/bin
# register Houdini for arm binaries
if [ -z "$1" ]; then
echo ':arm_exe:M::\\x7f\\x45\\x4c\\x46\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x28::'"$dest_dir/houdini:P" > register
echo ':arm_dyn:M::\\x7f\\x45\\x4c\\x46\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x00\\x28::'"$dest_dir/houdini:P" > register
else
echo ':arm64_exe:M::\\x7f\\x45\\x4c\\x46\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xb7::'"$dest_dir/houdini64:P" > register
echo ':arm64_dyn:M::\\x7f\\x45\\x4c\\x46\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x00\\xb7::'"$dest_dir/houdini64:P" > register
fi
if [ -e arm${1}_exe ]; then
houdini_bin=1
fi
else
log -pe -thoudini "No binfmt_misc support"
fi
if [ $houdini_bin -eq 0 ]; then
log -pe -thoudini "houdini$1 enabling failed!"
else
log -pi -thoudini "houdini$1 enabled"
fi
[ "$(getprop ro.zygote)" = "zygote64_32" -a -z "$1" ] && exec $0 64
exit 0
如果有兴趣进行尝试的小伙伴,可以把 log -pi -thoudini 改成echo 方便查看运行结果。
熟悉linux的小伙伴一眼就知道这是Shell。
它的作用只是下载houdini.sfs文件并挂载到so库到/system/lib/arm下,过程中挂在等等出问题的可以是文件不存在等等问题,不行就自己建立一个文件夹。
我在尝试运行这个脚本的时候发现网络有问题,而且貌似没有wget等工具
不过在github上还发现了一个仓库: https://github.com/Rprop/libhoudini,这里面各个版本的sfs文件都有,阅读脚本发现,可以手动下载这个文件然后放到/system/etc/,然后更改脚本自行挂载。
X 是X86,Y Z是X86_64,Z不清楚AArch64是啥!
还有个办法就是直接将所需要的so库直接push到模拟器中。
Andorid原生模拟器的默认端口为5555,可以用adb connect 127.0.0.1:5555 进行连接
当你push到系统文件夹的时候,如果提示 Read Only的话,你可以remount一下。
如果remount也不行,那就先 adb disable-verity,在重启应该就行了。
adb disable-verity
adb reboot
adb remount
总结步骤:
- 修改build.prop
ro.product.cpu.abilist=x86,armeabi-v7a,armeabi
ro.product.cpu.abilist32=x86,armeabi-v7a,armeabi
添加可执行 ro.enable.native.bridge.exec=1 ```
- push所需要的.so文件到/system/lib下:具体是arm 文件夹 以及libhoudini.so
- 修改ramdisk.img中的default.prop文件
# ro.dalvik.vm.native.bridge=0
ro.dalvik.vm.native.bridge=libhoudini.so
然后就完事儿了!!!!!!最后附上结果图:
当这个持续很久的时候,基本上有戏!终于安装成功
真香