[英]install an apk file programmatically after downloading(android studio)
[英]Android: Not a file URI: while downloading .apk file
我想下载 .apk 文件并安装它。 当我不使用 FileProvider 时,一切都很顺利,但是当我使用 FileProvider 从文件创建 uri 时,我得到了 IllegalArgumentException: Not a file URI: content://pl.rasztabiga.klasa1a.provider/external_storage_root/klasa1a。 apk上线
final long downloadId = manager.enqueue(request);
我尝试了 stackoverflow 中的所有内容,但没有任何帮助。 这是我的代码:
File file = new File(Environment.getExternalStorageDirectory(), "klasa1a.apk");
final Uri uri = FileProvider.getUriForFile(MainActivity.this, getApplicationContext().getPackageName() + ".provider", file);
//Delete update file if exists
//File file = new File(destination);
if (file.exists())
file.delete();
//get url of app on server
String url = "http://rasztabiga.ct8.pl/klasa1a.apk";
//set downloadmanager
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Downloading new version");
request.setTitle(MainActivity.this.getString(R.string.app_name));
//set destination
request.setDestinationUri(uri);
// get download service and enqueue file
final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
//set BroadcastReceiver to install app when .apk is downloaded
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(uri,
manager.getMimeTypeForDownloadedFile(downloadId));
startActivity(install);
unregisterReceiver(this);
finish();
}
};
//register receiver for when .apk download is compete
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
ACTION_VIEW
和ACTION_INSTALL_PACKAGE
仅支持 Android 7.0 以后的content
方案。 在此之前,您别无选择,只能使用file
。 所以,改变:
final Uri uri = FileProvider.getUriForFile(MainActivity.this, getApplicationContext().getPackageName() + ".provider", file);
到:
final Uri uri = (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) ?
FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", file) :
Uri.fromFile(file);
问题出在下载管理器中。 它无法将 uri 解析为“content://”,只能解析为“file://”,因此从 sdk24 开始,我们无法使用它。 使用常见的 IOStreams 和 HttpURLConnection 一切正常。 感谢@CommonsWare 向我展示了他的项目。 这就是现在的样子:
File file = new File(Environment.getExternalStorageDirectory(), "klasa1a.apk");
final Uri uri = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) ?
FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", file) :
Uri.fromFile(file);
//Delete update file if exists
//File file = new File(destination);
if (file.exists())
//file.delete() - test this, I think sometimes it doesnt work
file.delete();
//get url of app on server
String url = "http://rasztabiga.ct8.pl/klasa1a.apk";
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL sUrl = new URL(url);
connection = (HttpURLConnection) sUrl.openConnection();
connection.connect();
// download the file
input = connection.getInputStream();
output = new FileOutputStream(file);
byte data[] = new byte[4096];
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
return null;
}
output.write(data, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE)
.setData(uri)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(install);
return null;
}
对于那些仍然想使用DownloadManager
并发现CommonsWare的答案没有解决问题的人,您需要为APK文件包含一个例外
final Uri uri = (!file.getAbsolutePath().endsWith(".apk") && Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) ?
FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", file) :
Uri.fromFile(file);
request.setDestinationUri(uri);
哪个是更短的版本
if (!file.getAbsolutePath().endsWith(".apk") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
request.setDestinationUri(FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", download));
} else {
request.setDestinationUri(Uri.fromFile(file));
}
这可能更容易遵循。
简短的回答是 apk 文件应该用Uri.fromFile
处理,但这不必以改变整个过程为代价。
但是,如果您想要彻底,您还可以捕获IllegalArgumentException
for Not a file URI
并使用它来尝试Uri.fromFile
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.