到目前为止,我能够通过以下代码使用root(在应用程序内)安装APK文件:
pm install -t -f fullPathToApkFile
如果我想(尝试)安装到SD卡:
pm install -t -s fullPathToApkFile
最近,不确定哪个Android版本(至少在Android P beta上存在问题),上面的方法失败了,给我看了这条消息:
avc: denied { read } for scontext=u:r:system_server:s0 tcontext=u:object_r:sdcardfs:s0 tclass=file permissive=0
System server has no access to read file context u:object_r:sdcardfs:s0 (from path /storage/emulated/0/Download/FDroid.apk, context u:r:system_server:s0)
Error: Unable to open file: /storage/emulated/0/Download/FDroid.apk
Consider using a file under /data/local/tmp/
Error: Can't open file: /storage/emulated/0/Download/FDroid.apk
Exception occurred while executing:
java.lang.IllegalArgumentException: Error: Can't open file: /storage/emulated/0/Download/FDroid.apk
at com.android.server.pm.PackageManagerShellCommand.setParamsSize(PackageManagerShellCommand.java:306)
at com.android.server.pm.PackageManagerShellCommand.runInstall(PackageManagerShellCommand.java:884)
at com.android.server.pm.PackageManagerShellCommand.onCommand(PackageManagerShellCommand.java:138)
at android.os.ShellCommand.exec(ShellCommand.java:103)
at com.android.server.pm.PackageManagerService.onShellCommand(PackageManagerService.java:21125)
at android.os.Binder.shellCommand(Binder.java:634)
at android.os.Binder.onTransact(Binder.java:532)
at android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:2806)
at com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:3841)
at android.os.Binder.execTransact(Binder.java:731)
这似乎也影响了流行的应用程序,如“Titanium backup(pro)”,无法恢复应用程序。
看看写的是什么,它似乎缺乏安装不在/data/local/tmp/
的APK文件的权限。
所以我尝试了接下来的事情,看看能不能克服它:
chmod 777
) - 没有帮助。/data/local/tmp/
内:
Os.symlink(fullPathToApkFile, symLinkFilePath)
这没有做任何事情。 ln -sf $fullPathToApkFile $symLinkFilePath
这部分工作。文件就在那里,因为我可以在Total Commander应用程序中看到它,但当我尝试检查它是否存在时,当我尝试从那里安装APK时,它失败了。cp
或mv
)到/data/local/tmp/
路径,然后从那里安装。这有效,但它有缺点:移动有风险,因为它暂时隐藏原始文件,并且它会更改原始文件的时间戳。复制很糟糕,因为只是为了安装而使用额外的空间(即使是暂时的),因为它浪费了时间。 cp -p -r -l $fullPathToApkFile $tempFileParentPath"
这没用。它让我犯了这个错误:
cp: /data/local/tmp/test.apk: Cross-device link
如果您不介意移动过程,一种解决方案是保存和恢复原始文件的时间戳,如下所示:
val tempFileParentPath = "/data/local/tmp/"
val tempFilePath = tempFileParentPath + File(fullPathToApkFile).name
val apkTimestampTempFile = File(context.cacheDir, "apkTimestamp")
apkTimestampTempFile.delete()
apkTimestampTempFile.mkdirs()
apkTimestampTempFile.createNewFile()
root.runCommands("touch -r $fullPathToApkFile ${apkTimestampTempFile.absolutePath}")
root.runCommands("mv $fullPathToApkFile $tempFileParentPath")
root.runCommands("pm install -t -f $tempFilePath")
root.runCommands("mv $tempFilePath $fullPathToApkFile")
root.runCommands("touch -r ${apkTimestampTempFile.absolutePath} $fullPathToApkFile")
apkTimestampTempFile.delete()
它仍然有点危险,但比复制文件更好......
编辑:谷歌已经向我展示了一个很好的解决方法(here):
我们不支持从设备上的随机目录安装APK。它们需要使用'adb install'直接从主机安装,或者您必须流式传输内容以进行安装 -
$ cat foo.apk | pm install -S APK_SIZE
虽然我认为这是不正确的,他们不支持从随机路径安装APK文件(以前总是工作),解决方法似乎确实有效。我需要更改安装APK文件的代码是这样的:
val length = File(fullPathToApkFile ).length()
commands.add("cat $fullPathToApkFile | pm install -S $length")
事情是,现在我还有其他一些问题: