簡體   English   中英

Android:不是文件 URI:在下載 .apk 文件時

[英]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_VIEWACTION_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM