web-dev-qa-db-fra.com

Android DownloadManager API - ouverture du fichier après le téléchargement?

Je suis confronté à un problème d'ouverture du fichier téléchargé après un téléchargement réussi via l'API DownloadManager. Dans mon code:

Uri uri=Uri.parse("http://www.nasa.gov/images/content/206402main_jsc2007e113280_hires.jpg");

Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
    .mkdirs();

lastDownload = mgr.enqueue(new DownloadManager.Request(uri)
    .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
                            DownloadManager.Request.NETWORK_MOBILE)
    .setAllowedOverRoaming(false)
    .setTitle("app update")
    .setDescription("New version 1.1")
    .setShowRunningNotification(true)
    .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "a.apk"));

Cursor c=mgr.query(new DownloadManager.Query().setFilterById(lastDownload));

if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)) == 8) {
    try {
        mgr.openDownloadedFile(c.getLong(c.getColumnIndex(DownloadManager.COLUMN_ID)));
    } catch (NumberFormatException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.d("MGR", "Error");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Log.d("MGR", "Error");
    }
}

Le problème est quand if(c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))==8) est-il évoqué. J'ai obtenu le statut -1 et une exception. Existe-t-il un meilleur moyen, comment ouvrir des fichiers téléchargés avec DownloadManager API? Dans mon exemple, je télécharge une grande image, dans une situation réelle, je téléchargerais un fichier APK et je dois afficher une boîte de dialogue d'installation immédiatement après la mise à jour.

Edit: J'ai compris que status = 8 est après un téléchargement réussi. Vous pouvez avoir une approche différente de "vérification du téléchargement réussi"

Merci

27
Waypoint

Vous devez enregistrer un récepteur lorsque le téléchargement est terminé:

registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

et un gestionnaire BroadcastReciever

BroadcastReceiver onComplete=new BroadcastReceiver() {
    public void onReceive(Context ctxt, Intent intent) {
        // Do Something
    }
};

Achetez au lieu de tout arnaquer, je vous suggère de vérifier ceci .

MODIFIER:

À titre de suggestion, je ne recommanderais pas encore d'utiliser l'API 9: http://developer.Android.com/resources/dashboard/platform-versions.html

Il existe des moyens de contourner cela, en créant votre propre gestionnaire de téléchargement, comme je l'ai fait, parce que nous ne voulions pas aliéner la plupart des utilisateurs de notre base Android, pour cela, vous aurez besoin de: Créer AsyncTask qui gère le téléchargement du fichier.

et je recommanderai de créer une boîte de dialogue de téléchargement (si vous dites que c'est un gros fichier, je le ferais apparaître dans la zone de notification).

et que vous devrez gérer l'ouverture du fichier:

protected void openFile(String fileName) {
    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setDataAndType(Uri.fromFile(new File(fileName)),
            "MIME-TYPE");
    startActivity(install);
}
29
Itai Sagi

Problème

API Android DownloadManager - ouverture du fichier après le téléchargement?

Solution

/**
 * Used to download the file from url.
 * <p/>
 * 1. Download the file using Download Manager.
 *
 * @param url      Url.
 * @param fileName File Name.
 */
public void downloadFile(final Activity activity, final String url, final String fileName) {
    try {
        if (url != null && !url.isEmpty()) {
            Uri uri = Uri.parse(url);
            activity.registerReceiver(attachmentDownloadCompleteReceive, new IntentFilter(
                    DownloadManager.ACTION_DOWNLOAD_COMPLETE));

            DownloadManager.Request request = new DownloadManager.Request(uri);
            request.setMimeType(getMimeType(uri.toString()));
            request.setTitle(fileName);
            request.setDescription("Downloading attachment..");
            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
            DownloadManager dm = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
            dm.enqueue(request);
        }
    } catch (IllegalStateException e) {
        Toast.makeText(activity, "Please insert an SD card to download file", Toast.LENGTH_SHORT).show();
    }
}

/**
 * Used to get MimeType from url.
 *
 * @param url Url.
 * @return Mime Type for the given url.
 */
private String getMimeType(String url) {
    String type = null;
    String extension = MimeTypeMap.getFileExtensionFromUrl(url);
    if (extension != null) {
        MimeTypeMap mime = MimeTypeMap.getSingleton();
        type = mime.getMimeTypeFromExtension(extension);
    }
    return type;
}

/**
 * Attachment download complete receiver.
 * <p/>
 * 1. Receiver gets called once attachment download completed.
 * 2. Open the downloaded file.
 */
BroadcastReceiver attachmentDownloadCompleteReceive = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
            long downloadId = intent.getLongExtra(
                    DownloadManager.EXTRA_DOWNLOAD_ID, 0);
            openDownloadedAttachment(context, downloadId);
        }
    }
};

/**
 * Used to open the downloaded attachment.
 *
 * @param context    Content.
 * @param downloadId Id of the downloaded file to open.
 */
private void openDownloadedAttachment(final Context context, final long downloadId) {
    DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(downloadId);
    Cursor cursor = downloadManager.query(query);
    if (cursor.moveToFirst()) {
        int downloadStatus = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
        String downloadLocalUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
        String downloadMimeType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
        if ((downloadStatus == DownloadManager.STATUS_SUCCESSFUL) && downloadLocalUri != null) {
            openDownloadedAttachment(context, Uri.parse(downloadLocalUri), downloadMimeType);
        }
    }
    cursor.close();
}

/**
 * Used to open the downloaded attachment.
 * <p/>
 * 1. Fire intent to open download file using external application.
 *
 * 2. Note:
 * 2.a. We can't share fileUri directly to other application (because we will get FileUriExposedException from Android7.0).
 * 2.b. Hence we can only share content uri with other application.
 * 2.c. We must have declared FileProvider in manifest.
 * 2.c. Refer - https://developer.Android.com/reference/Android/support/v4/content/FileProvider.html
 *
 * @param context            Context.
 * @param attachmentUri      Uri of the downloaded attachment to be opened.
 * @param attachmentMimeType MimeType of the downloaded attachment.
 */
private void openDownloadedAttachment(final Context context, Uri attachmentUri, final String attachmentMimeType) {
    if(attachmentUri!=null) {
        // Get Content Uri.
        if (ContentResolver.SCHEME_FILE.equals(attachmentUri.getScheme())) {
            // FileUri - Convert it to contentUri.
            File file = new File(attachmentUri.getPath());
            attachmentUri = FileProvider.getUriForFile(activity, "com.freshdesk.helpdesk.provider", file);;
        }

        Intent openAttachmentIntent = new Intent(Intent.ACTION_VIEW);
        openAttachmentIntent.setDataAndType(attachmentUri, attachmentMimeType);
        openAttachmentIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        try {
            context.startActivity(openAttachmentIntent);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(context, context.getString(R.string.unable_to_open_file), Toast.LENGTH_LONG).show();
        }
    }
}

Initialiser les détails de FileProvider

Déclarer FileProvider dans AndroidManifest

<provider
    Android:name="Android.support.v4.content.FileProvider"
    Android:authorities="com.freshdesk.helpdesk.provider"
    Android:exported="false"
    Android:grantUriPermissions="true">
    <meta-data
        Android:name="Android.support.FILE_PROVIDER_PATHS"
        Android:resource="@xml/file_path"/>
</provider>

Ajoutez le fichier suivant "res -> xml -> file_path.xml"

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <external-path name="attachment_file" path="."/>
</paths>

Remarque

Pourquoi utiliser FileProvider

  1. Depuis Android 7.0, nous ne pouvons pas partager FileUri avec d'autres applications.
  2. En utilisant "DownloadManager.COLUMN_LOCAL_URI", nous n'obtiendrons que FileUri, nous devons donc le convertir en ContentUri et partager avec une autre application.

Provblem avec l'utilisation de "DownloadManager.getUriForDownloadedFile (long id)"

  1. N'utilisez pas "DownloadManager.getUriForDownloadedFile (long id)" - Pour obtenir Uri de downloadId pour ouvrir le fichier à l'aide d'une application externe.
  2. Parce que de Android 6.0 & 7.0 "getUriForDownloadedFile" méthode retourne l'URI local (qui n'est accessible que par notre application), nous ne pouvons pas partager cet Uri avec une autre application car ils ne peuvent pas y accéder. uri (Mais il est corrigé dans Android 7.1 voir Android Commit Here ).
  3. Refere Android DownloadManager.Java & Downloads.Java
  4. Par conséquent, utilisez toujours la colonne "DownloadManager.COLUMN_LOCAL_URI" pour obtenir Uri.

Référence

  1. https://developer.Android.com/reference/Android/app/DownloadManager.html
  2. https://developer.Android.com/reference/Android/support/v4/content/FileProvider.html
42
Vasanth

rappelez-vous d'ajouter <uses-permission Android:name="Android.permission.REQUEST_INSTALL_PACKAGES" /> à votre fichier AndroidMannifest.xml

0
xiaoshitou