Créer clic téléchargement fichier pdf android [Résolu]

- 21 oct. 2018 à 17:07 - Dernière réponse :  iKelSilver
- 24 oct. 2018 à 16:33
Bonjour,
Je suis sur un projet mobile qui demande d'intégrer des fichiers pdf dans cette application. J'ai mis tous ces fichiers dans le dossier < isset >. J'utilise Androïd studio.
Je veux que tous les fichiers soient lus en local sur le téléphone de l'utilisateur lorsqu'il dispose d'un lecteur pdf sur son téléphone sinon, lui afficher un message.
Dans une activité, j'ai créé des Layout qui doivent recevoir des clics. Et au clic sur un Layout, que le fichier pdf qui lui est attaché se lance en téléchargement automatique.
Bref, je veux que lorsque l'utilisateur clique sur un Layout, qu'un fichier pdf soit téléchargé automatiquement.
Comment réaliser cela ?
Je ne suis qu'un débutant.
J'ai à première idée faire une lecture en local dans mon application, mais, tous les testes et recherches ne me donnent pas de bons résultats. Voilà pourquoi je veux proposer un téléchargement à l'utilisateur dès qu'il clique sur un Layout.
Aidez-moi avec des liens ou des propositions de codes.
Merci
Afficher la suite 

Votre réponse

14 réponses

Messages postés
5292
Date d'inscription
dimanche 4 mai 2003
Statut
Modérateur
Dernière intervention
12 novembre 2018
- 22 oct. 2018 à 08:17
0
Merci
Salut,

J'ai pas tout compris, mais si tu veux lire un fichier qui est dans le répertoire assets de ton projet il suffit d'utiliser la méthode open disponible via l'asset manager, (getAssets depuis le context (au mieux celui de l'application)).
Context c = getApplicationContext();
try {
  InputStreamReader isr = new InputStreamReader(c.getAssets().open("fichier.pdf"));
} catch(IOException ie) {
  Log.e(getClass().getSimpleName(), "IOException: " + ie.getMessage(), ie);
}


Par contre, ici, tu ne pourras pas le modifier, donc si c'est cela que tu souhaites faire il te faudra faire une copie de ce dernier dans le répertoire data de ton application.

private static File copyFileFromAssets(final Context context, final String assetFolder, final String fileName)
      throws PackageManager.NameNotFoundException, IOException {
  final PackageManager m = context.getPackageManager();
  String newPath = context.getPackageName();

  final PackageInfo p = m.getPackageInfo(newPath, 0);
  newPath = p.applicationInfo.dataDir + "/" + fileName;

  File f = new File(newPath);
  if(f.exists())
    //noinspection ResultOfMethodCallIgnored
    f.delete();
    
  InputStream in = null;
  FileOutputStream out = null;
  try {   
    in = context.getAssets().open(assetFolder + fileName);
    out = new FileOutputStream(f);
    int read;
    final byte[] buffer = new byte[4096];
    while ((read = in.read(buffer)) > 0)
      out.write(buffer, 0, read);
  } catch(IOException ioe) {
    throw new IOException(ioe);
  } finally {
    if(out != null)
      out.close();
    if(in != null)
      in.close();
  }
  return f;
}

/* utilisation*/
Context c = getApplicationContext();
try {
  File fileInDataDir = copyFileFromAssets(c /* Context */,
      "" /* le fichier pourrait être dans le un sous répertoire, ex: foo dans ce cas il faudra mettre 'foo/' */,
      "fichier.pdf" /* fichier dans l'assets */);
} catch(Exception e) {
  Log.e(getClass().getSimpleName(), "Exception: " + e.getMessage(), e);
}

Messages postés
5292
Date d'inscription
dimanche 4 mai 2003
Statut
Modérateur
Dernière intervention
12 novembre 2018
- 23 oct. 2018 à 15:09
Comme tu ne m'as pas repris dessus, je suis resté sur mon idée, mais ils sont où les fichiers ? dans "assets" (embarqué dans ton apk?) ou dans un répertoire "isset" ???? Si il s'agit d'un répertoire isset, pour toi, il est où physiquement sur le téléphone?
Tous mes fichiers pdf sont dans le répertoire < assets > intégrés directement dans l'apk.
Messages postés
5292
Date d'inscription
dimanche 4 mai 2003
Statut
Modérateur
Dernière intervention
12 novembre 2018
- 23 oct. 2018 à 16:48
Ok,

A ma connaissance, une application externe (Intente and co) n'est pas en mesure d'accéder à un fichier qui est placé en assets d'une application et même cette dernière n'a d'autre choix que de passer par la méthode getAssets().open(...) pour y accéder.

Du coup ce que je te montre depuis le début c'est comment tu dois t'y prendre pour faire ce que tu veux. Soit copier le fichier de l'assets vers un emplacement qui est accessible.


Pour donner suite à ton précédent message, tu dis:

Mais, je ne comprends toujours pas ce que vous dites.
Ok, tu ne comprends pas quelle partie ?

Je voulais ouvrir le fichier pdf situant actuellement dans le répertoire isset au clic sur un Layout avec l'application de lecture par défaut du fichier pdf.
Ok, comme dit plus haut, il faut dans un premier temps sortir le fichier de cette zone pour qu'il soit accessible, donc le copier sur la flash interne ou une sd externe.

Si pouvez m'organiser ce code afin que je puisse vous suivre.
En gros :
//Au clic sur ce Layout, que le téléchargement du fichier .pdf soit démarré automatique
LinearLayout afficher_lecture_pdf = (LinearLayout) findViewById(R.id.lecture_pdf);
afficher_lecture_pdf.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {                
    Context c = getApplicationContext();
    try {
      /* Pense à mettre les permissions WRITE_EXTERNAL_STORAGE et READ_EXTERNAL_STORAGE. */
      File fileInDataDir = copyFileFromAssets(c, "", "LE_NOM_DE_TON_FICHIER.pdf");
      Intent intent = new Intent(Intent.ACTION_VIEW);
      /* Si tu as une exception de type android.os.FileUriExposedException: xxxxxx exposed beyond app through Intent.getData(), voir le lien 'solution' plus haut */
      intent.setDataAndType(Uri.fromFile(fileInDataDir), "application/pdf");
      intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
      startActivity(intent);
    } catch(Exception e) {
      Log.e(getClass().getSimpleName(), "Exception: " + e.getMessage(), e);
    }
  }
});

...
private static File copyFileFromAssets(final Context context, final String assetFolder, final String fileName)
      throws PackageManager.NameNotFoundException, IOException {
...
}
...
Donc, en gros, je dois avoir un truc complet comme ceci :
//Au clic sur ce Layout, que le téléchargement du fichier .pdf soit démarré automatique
        LinearLayout afficher_lecture_pdf = (LinearLayout) findViewById(R.id.lecture_pdf);
        afficher_lecture_pdf.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Context c = getApplicationContext();
                try {
                     /* Pense à mettre les permissions WRITE_EXTERNAL_STORAGE et READ_EXTERNAL_STORAGE. */
                    File fileInDataDir = copyFileFromAssets(c, "", "teste.pdf");
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                     /* Si tu as une exception de type android.os.FileUriExposedException: xxxxxx exposed beyond app through Intent.getData(), voir le lien 'solution' plus haut */
                    intent.setDataAndType(Uri.fromFile(fileInDataDir), "application/pdf");
                    intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                    startActivity(intent);
                } catch(Exception e) {
                    Log.e(getClass().getSimpleName(), "Exception: " + e.getMessage(), e);
                }
            }
        });

        private static File copyFileFromAssets(final Context context, final String assetFolder, final String fileName)
      throws PackageManager.NameNotFoundException, IOException {
            final PackageManager m = context.getPackageManager();
            String newPath = context.getPackageName();

            final PackageInfo p = m.getPackageInfo(newPath, 0);
            newPath = p.applicationInfo.dataDir + "/" + fileName;

            File f = new File(newPath);
            if(f.exists())
                //noinspection ResultOfMethodCallIgnored
                f.delete();

            InputStream in = null;
            FileOutputStream out = null;
            try {
                in = context.getAssets().open(assetFolder + fileName);
                out = new FileOutputStream(f);
                int read;
                final byte[] buffer = new byte[4096];
                while ((read = in.read(buffer)) > 0)
                    out.write(buffer, 0, read);
            } catch(IOException ioe) {
                throw new IOException(ioe);
            } finally {
                if(out != null)
                    out.close();
                if(in != null)
                    in.close();
            }
            return f;
        }


Je travaille dans Androïd studio. Je vois beaucoup d'erreurs dans le code.
Je ne comprends toujours pas
Messages postés
5292
Date d'inscription
dimanche 4 mai 2003
Statut
Modérateur
Dernière intervention
12 novembre 2018
- 23 oct. 2018 à 21:30
Yep,

"Je vois beaucoup d'erreurs dans le code. "
>> Mais encore? tu as ajoutés les imports de File/PackageInfo/PackageManager/etc... ?
Commenter la réponse de Twinuts
Messages postés
5292
Date d'inscription
dimanche 4 mai 2003
Statut
Modérateur
Dernière intervention
12 novembre 2018
- 23 oct. 2018 à 22:18
0
Merci
Ci après un exemple complet:

Le fichier Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.myapplication">

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

  <application
    android:allowBackup="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>

</manifest>


Le fichier layout activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity">

  <Button
    android:id="@+id/openPdf"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Open PDF"
    android:layout_centerInParent="true"/>

</RelativeLayout>


Le fichier java:
package com.example.myapplication;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.StrictMode;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    /* Workaround pour le pb URI (PAS PROPRE et surement inutile si tu n'es pas sur Nougat ou plus) */
    try{
      Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
      m.invoke(null);
    }catch(Exception e){
      e.printStackTrace();
    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    /* clic sur le bouton */
    findViewById(R.id.openPdf).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        Context c = getApplicationContext();
        try {
          File fileInDataDir = copyFileFromAssetsToDownloads(c, "", "file.pdf");
          Intent intent = new Intent(Intent.ACTION_VIEW);
          intent.setDataAndType(Uri.fromFile(fileInDataDir), "application/pdf");
          intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
          startActivity(intent);
        } catch(Exception e) {
          Log.e(getClass().getSimpleName(), "Exception: " + e.getMessage(), e);
        }
      }
    });

    /* Permissions Nougat et +*/
    ActivityCompat.requestPermissions(this, new String[] {
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.READ_EXTERNAL_STORAGE,
    }, 1);
  }

  private static File copyFileFromAssetsToDownloads(final Context context, final String assetFolder, final String fileName)
      throws IOException {
    /* utilisation du répertoire download pour pour que l'application externe puisse lire le fichier sinon ça semble coincer. */
    File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + fileName);
    if(f.exists())
      //noinspection ResultOfMethodCallIgnored
      f.delete();
    InputStream in = null;
    FileOutputStream out = null;
    try {
      in = context.getAssets().open(assetFolder + fileName);
      out = new FileOutputStream(f);
      int read;
      final byte[] buffer = new byte[4096];
      while ((read = in.read(buffer)) > 0)
        out.write(buffer, 0, read);
    } catch(IOException ioe) {
      throw new IOException(ioe);
    } finally {
      if(out != null)
        out.close();
      if(in != null)
        in.close();
    }
    return f;
  }
}


J'ai modifié l'emplacement de stockage du fichier PDF pour le mettre dans le répertoire Download (chez moi /storage/emulated/0/Download/)
Pour ce qui est du fichier pdf que j'ai placé dans le répertoire assets du projet, j'ai utilisé celui-ci que j'ai renommé en file.pdf (en lieu et place de pdf.pdf)

Pour le reste des fichiers, ils sont inchangés par rapport à la création du projet sous Android Studio 3.1.4

Twinuts, tu es vraiment super.
Tu m'as sauvé. ) :
Messages postés
5292
Date d'inscription
dimanche 4 mai 2003
Statut
Modérateur
Dernière intervention
12 novembre 2018
- 24 oct. 2018 à 08:35
Salut,

Pense à valider le sujet si ton problème est résolu.

++
Bonjour,
J'ai validé depuis ma boîte mail en cliquant sur < Votre question est résolue > plusieurs fois, mais, ça ne donne toujours aucun résultat.
Merci pour tout
Commenter la réponse de Twinuts

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.