[英]Android: Not a file URI: while downloading .apk file
I want to download .apk file and install it.我想下载 .apk 文件并安装它。 When I'm not using FileProvider, everything is going well, but when I create uri from file using FileProvider, I've got IllegalArgumentException: Not a file URI: content://pl.rasztabiga.klasa1a.provider/external_storage_root/klasa1a.apk on line
当我不使用 FileProvider 时,一切都很顺利,但是当我使用 FileProvider 从文件创建 uri 时,我得到了 IllegalArgumentException: Not a file URI: content://pl.rasztabiga.klasa1a.provider/external_storage_root/klasa1a。 apk上线
final long downloadId = manager.enqueue(request);
I tried everything from stackoverflow but nothing helped.我尝试了 stackoverflow 中的所有内容,但没有任何帮助。 Here is my code:
这是我的代码:
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
and ACTION_INSTALL_PACKAGE
only support the content
scheme as of Android 7.0. ACTION_VIEW
和ACTION_INSTALL_PACKAGE
仅支持 Android 7.0 以后的content
方案。 Prior to that, you have no choice but to use file
.在此之前,您别无选择,只能使用
file
。 So, change:所以,改变:
final Uri uri = FileProvider.getUriForFile(MainActivity.this, getApplicationContext().getPackageName() + ".provider", file);
to:到:
final Uri uri = (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) ?
FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", file) :
Uri.fromFile(file);
The problem was in DownloadManager.问题出在下载管理器中。 It cannot parse uri's as "content://", only as "file://" so since sdk24, we cannot use it.
它无法将 uri 解析为“content://”,只能解析为“file://”,因此从 sdk24 开始,我们无法使用它。 Using common IOStreams and HttpURLConnection everything works fine.
使用常见的 IOStreams 和 HttpURLConnection 一切正常。 Thanks to @CommonsWare for showing me his project.
感谢@CommonsWare 向我展示了他的项目。 That's how it looks like now:
这就是现在的样子:
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;
}
For those that still want to use DownloadManager
and find that the answer by CommonsWare doesn't solve the problem, you need to include an exception for APK file对于那些仍然想使用
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);
Which is a shorter version of哪个是更短的版本
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));
}
that may be easier to follow.这可能更容易遵循。
The short answer is that apk files should be handled with Uri.fromFile
, but this does not have to come at the cost of changing the entire process.简短的回答是 apk 文件应该用
Uri.fromFile
处理,但这不必以改变整个过程为代价。
If you want to be thorough, though, you can also catch the IllegalArgumentException
for Not a file URI
and use that to attempt Uri.fromFile
但是,如果您想要彻底,您还可以捕获
IllegalArgumentException
for Not a file URI
并使用它来尝试Uri.fromFile
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.