Uploader un fichier sur un serveur avec OKHttp

 

Bonjour les amis 😀 , dans ce tutoriel on va créer une petite application qui aura pour but de permettre à l’utilisateur de choisir un fichier ( photo, pdf, etc…. ) qui se trouve sur son téléphone et de pouvoir l’uploader sur le serveur 🙂

CODE SOURCE

 

Côté serveur ( PHP )

  1. Dans votre dossier www de votre serveur, créer un fichier upload.php et copier le code ci-dessous, c’est un petit script php qui gère l’upload
    <?php if(isset($_FILES['file'])) { $max_size = 2097152; // cela vaut à 2 MB // Les extensions permises $extensions = array("jpeg", "jpg", "png", "txt", "pdf", "docx"); // Le chemin où l'on va uploader notre fichier $path_dir = "uploads/"; $file_name = $_FILES['file']['name']; $file_size = $_FILES['file']['size']; $file_tmp = $_FILES['file']['tmp_name']; $file_ext=strtolower(end(explode('.',$_FILES['file']['name']))); $error = false; // On vérifie si l'extension du fichier upload est permise if(in_array($file_ext,$extensions) === false) { $error = true; $response['message'] = "L'extension du fichier n'est pas permise"; } // On vérifie si notre fichier ne dépasse pas la limite autorisée if($file_size > $max_size) {
            $error = true;
            $response['message'] = "Votre fichier ne doit pas dépasser 2 MB";
        }				
    
        if (!$error && move_uploaded_file($file_tmp, $path_dir . $file_name)) {
            $response['success'] = 1;
            $response['message'] = 'Upload reussi';
        }
        else {
            $response['success'] = 0;
        }
    
        echo json_encode($response);
    
    }
    ?>
  2. Créer un dossier uploads, c’est là où nous retrouverons nos fichiers uploader.

 

Côté client ( Android )

  1. Dans Android studio, créer un nouveau projet en allant dans File->New->New Project 
  2. Dans Application name mettez “UploadFile” et Company domaine “androidpourtous.com”
  3. Dans Minimum SDK, choisissez API 14: Android 4.0, puis vous mettez Next jusqu’à Finish.
  4. Dans votre fichier build.gradle, copier le code suivant, ce sont les librairies que nous allons utiliser dans notre exemple
    // Pour avoir une belle progress bar BLING BLING
    compile 'com.github.tibolte:elasticdownload:1.0.+'
    
    // Pour les requêtes vers le serveur
    compile 'com.squareup.okhttp:okhttp:2.4.0'
    
    // Pour choisir un fichier depuis Android
    compile 'com.nononsenseapps:filepicker:2.1'
  5. Dans le fichier AndroidManifest.xml, copier cela, dedans il y a les autorisations nécessaire pour le fonctionnement de l’application et la librairie qui permet de choisir un fichier
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidpourtous.uploadfile" >
    
        <!-- Pour pouvoir accéder aux fichiers -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
        <!-- Pour l'accès à Internet -->
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
        <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
    
            <activity android:name=".MainActivity" android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
    
            <activity android:name="com.nononsenseapps.filepicker.FilePickerActivity" android:label="@string/app_name" android:theme="@style/FilePickerTheme">
                <intent-filter>
                    <action android:name="android.intent.action.GET_CONTENT" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
    
        </application>
    
    </manifest>
  6. Dans le fichier colors.xml qui se trouve dans res->values, copiez les ressources suivantes, si il n’existe pas n’hésitez pas à le créer
    <color name="primary">#607D8B</color>
    <color name="primary_dark">#455A64</color>
    <color name="accent">#536DFE</color>
  7. Dans res->values->styles.xml, copiez le thème suivant, il sert pour la librairie qui nous permet de choisir notre fichier
    <!-- You must inherit from Theme.AppCompat. Dark or light doesn't matter -->
    
    
    <style name="FilePickerTheme" parent="Theme.AppCompat.DialogWhenLarge">
        <!-- Set these to match your theme -->
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>
    
        <!-- Need to set this also to style create folder dialog -->
        <item name="alertDialogTheme">@style/FilePickerAlertDialogTheme</item>
    
        <!-- These are important. Handled by toolbar -->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
    
    
    
    
    
    <style name="FilePickerAlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>
    </style>
    
    </pre>
    <pre>
  8. Dans res->layout, créer un fichier activity_main.xml et copier le code suivant
    <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" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    
        <Button android:id="@+id/btn_choose_file" android:layout_centerHorizontal="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Choisir un fichier"/>
    
    
        <is.arontibo.library.ElasticDownloadView android:id="@+id/elastic_download_view" android:layout_below="@id/btn_choose_file" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/>
    
    </RelativeLayout>
  9. Dans notre package com.androidpourtous.uploadfile , créer la class suivant  CoutingFileRequestBody , je l’ai récupéré de StackOverFlow, elle nous servira pour l’affichage du pourcentage de l’upload, exemple ( 10%…20%…etc )
    package com.androidpourtous.uploadfile;
    
    import com.squareup.okhttp.MediaType;
    import com.squareup.okhttp.RequestBody;
    import com.squareup.okhttp.internal.Util;
    
    import java.io.File;
    import java.io.IOException;
    
    import okio.BufferedSink;
    import okio.Okio;
    import okio.Source;
    
    
    public class CountingFileRequestBody extends RequestBody {
    
        private static final int SEGMENT_SIZE = 2048; // okio.Segment.SIZE
    
        private final File file;
        private final ProgressListener listener;
        private final String contentType;
    
        public CountingFileRequestBody(File file, String contentType, ProgressListener listener) {
            this.file = file;
            this.contentType = contentType;
            this.listener = listener;
        }
    
        @Override
        public long contentLength() {
            return file.length();
        }
    
        @Override
        public MediaType contentType() {
            return MediaType.parse(contentType);
        }
    
        @Override
        public void writeTo(BufferedSink sink) throws IOException {
    
            Source source = null;
            try {
                source = Okio.source(file);
                long total = 0;
                long read;
    
                while ((read = source.read(sink.buffer(), SEGMENT_SIZE)) != -1) {
                    total += read;
                    sink.flush();
                    this.listener.transferred(total);
    
                }
            } finally {
                Util.closeQuietly(source);
            }
        }
    
        public interface ProgressListener {
            void transferred(long num);
        }
    
    }
  10. Et finalement copier le code suivant dans MainActivity 
    package com.androidpourtous.uploadfile;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Handler;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    import com.nononsenseapps.filepicker.FilePickerActivity;
    import com.squareup.okhttp.MultipartBuilder;
    import com.squareup.okhttp.OkHttpClient;
    import com.squareup.okhttp.Request;
    import com.squareup.okhttp.RequestBody;
    import com.squareup.okhttp.Response;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.io.File;
    import java.io.IOException;
    
    import is.arontibo.library.ElasticDownloadView;
    
    
    public class MainActivity extends AppCompatActivity {
    
        /**
         *  Le lien du script, qu'on appellera pour uploader notre fichier
         */
        private static final String URL_UPLOAD = "http://192.168.1.5/upload.php";
    
        private final OkHttpClient client = new OkHttpClient();
    
        private static final String CONTENT_TYPE = "application/octet-stream";
    
        private static final int FILE_CODE = 9999;
    
    
        private static final String FORM_NAME = "file";
    
        private static final String TAG_SUCCESS = "success";
        private static final String TAG_MESSAGE = "message";
    
        private ElasticDownloadView mElasticDownloadView;
        private Button button;
    
        private File fileToUpload;
    
        /**
         *  la taile de notre fichier
         */
        private long totalSize = 0;
    
        private Handler handler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            handler = new Handler(getMainLooper());
    
            mElasticDownloadView = (ElasticDownloadView) findViewById(R.id.elastic_download_view);
            button = (Button) findViewById(R.id.btn_choose_file);
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
                    Intent i = new Intent(MainActivity.this, FilePickerActivity.class);
    
                    // On ne permet que la sélection de UN seul fichier
                    i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
                    i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
                    i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_FILE);
    
                    // Configure initial directory by specifying a String.
                    // You could specify a String like "/storage/emulated/0/", but that can
                    // dangerous. Always use Android's API calls to get paths to the SD-card or
                    // internal memory.
                    i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath());
    
                    startActivityForResult(i, FILE_CODE);
                }
            });
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
            if (requestCode == FILE_CODE && resultCode == Activity.RESULT_OK) {
    
                Uri uri = data.getData();
    
                fileToUpload = new File(uri.getPath());
    
                try {
                    upload(fileToUpload);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
        }
    
    
        public void upload(final File file) throws Exception {
    
            new AsyncTask<Void, Integer, String>() {
    
                @Override
                protected void onPreExecute() {
                    super.onPreExecute();
    
                    mElasticDownloadView.startIntro();
                }
    
                @Override
                protected String doInBackground(Void... voids) {
    
                    totalSize = file.length();
    
                    RequestBody requestBody = new MultipartBuilder()
                            .type(MultipartBuilder.FORM)
                            .addFormDataPart(FORM_NAME, file.getName(),
                                    new CountingFileRequestBody(file, CONTENT_TYPE, new CountingFileRequestBody.ProgressListener() {
                                @Override
                                public void transferred(long num) {
    
                                    final float progress = (num / (float) totalSize) * 100;
    
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            onProgressUpdate((int) progress);
                                        }
                                    });
                                }
                            }))
                            .build();
    
                    Request request = new Request.Builder()
                            .url(URL_UPLOAD)
                            .post(requestBody)
                            .build();
    
                    Response response = null;
    
                    try {
                        // On exécute la requête
                        response = client.newCall(request).execute();
    
                        String responseStr = response.body().string();
    
                        return responseStr;
    
    
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                    return  null;
    
                }
    
                @Override
                protected void onProgressUpdate(Integer... values) {
                    super.onProgressUpdate(values);
                    // On affiche le pourcentage d'ulpoad
                    mElasticDownloadView.setProgress(values[0]);
                }
    
    
                @Override
                protected void onPostExecute(String s) {
                    super.onPostExecute(s);
    
                    try {
                        JSONObject jsonObject = new JSONObject(s);
    
                        int success = Integer.valueOf(jsonObject.getString(TAG_SUCCESS));
                        String message = jsonObject.getString(TAG_MESSAGE);
    
                        // Si c'est 1 donc l'upload s'est bien faite
                        if (success == 1)
                            mElasticDownloadView.success();
                        else
                            mElasticDownloadView.fail();
    
                        // On affiche le message à l'utilisateur
                        Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
    
    
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
    
                }
    
    
            }.execute();
    
    
        }
    
    
    }

 

Voilà maintenant vous pouvez lancer l’application, choisir le fichier que vous voulez et l’uploader sur le seveur 😀

PS : n’hésitez pas à me faire des remarques si vous n’avez pas compris quelque chose 🙂

Un commentaire sur “Uploader un fichier sur un serveur avec OKHttp

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *