这个帖子回答了一个类似的问题,但我想在Android 5.0-6.0上从应用程序内部存储(SD卡上)以编程方式安装APK文件。
如果不是来自应用程序内部存储,我可以使用一个意图(其操作为ACTION_VIEW),并使用具有“file://”方案的数据URI(使用Uri.fromFile())调用startActivity()。但我尝试过,这对于应用程序内部存储无效,因为其他应用程序无法读取它。我基于像下面的日志消息做出这个结论:
如果不是来自应用程序内部存储,我可以使用一个意图(其操作为ACTION_VIEW),并使用具有“file://”方案的数据URI(使用Uri.fromFile())调用startActivity()。但我尝试过,这对于应用程序内部存储无效,因为其他应用程序无法读取它。我基于像下面的日志消息做出这个结论:
W/asset: Asset path /storage/C5DF-1113/Android/data/com.example/files/foo.apk is neither a directory nor file (type=1).
W/InstallFlowAnalytics: Failed to hash APK contents
java.io.FileNotFoundException: /storage/C5DF-1113/Android/data/com.example/files/foo.apk: open failed: ENOENT (No such file or directory)
我尝试过通过子类化ContentProvider来使用content://
协议。但是显然(参见CommonsWare在这里的答案),直到Android 7.0,包安装程序才支持content://
协议。在Android 6.0中,我会得到以下日志消息:
I/ActivityManager: START u0 {act=android.intent.action.VIEW dat=content://com.example.provider/internal/foo.apk typ=application/vnd.android.package-archive flg=0x10000001} from uid 10159 on display 0
E/Updates: installNewApk
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=content://com.example.provider/internal/foo.apk typ=application/vnd.android.package-archive flg=0x10000001 }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1805)
在符合安装包的意图和不符合的意图之间,唯一明显的区别似乎是数据URI从file://
...变为content://
...
有其他关于静默安装应用的答案,但这不是我项目的要求。还有使用反射获取未公开功能或需要设备root的解决方案,但这些技术对于这个项目来说太脆弱或用户不友好。
还有将APK从应用程序内部存储复制到外部存储以启动安装程序的选项。我们可能不得不去那里,但首先将APK置于内部存储中是出于隐私和安全性的考虑。(我意识到这还远非铁壁铜墙,但总比没有好,这也是我们客户想要的。)
我愿意根据当前Android版本进行条件判断,但目前我仍然不知道在5.0-6.0上该怎么做。
感谢任何建议。
getFilesDir()
这样的东西保留的。 SD 卡最好称为“可移动存储”。 关于你的问题,据我所知,你没有运气了——在 Android 7.0 之前,APK 必须在外部存储 (getExternalFilesDir()
等) 中。 我曾经大声抱怨过这个问题,但毫无用处。 - CommonsWareUri.fromFile()
对您无效的原因。只有您可以访问该目录;其他应用程序(包括安装程序)不能访问。如果使用getFilesDir()
,您将遇到相同的问题,因为其他应用程序无法访问该位置。而且,在7.0之前,您不能使用content
作为方案,这使您只能使用外部存储...就是这样,据我所知。 - CommonsWare