Envoyer une demande multipart avec Android SDK




http multipartform-data (8)

J'essaie de faire quelque chose que je pensais être relativement simple: télécharger une image sur un serveur avec le SDK Android. Je trouve beaucoup d'exemple de code:

http://groups.google.com/group/android-developers/browse_thread/thread/f9e17bbaf50c5fc/46145fcacd450e48

http://linklens.blogspot.com/2009/06/android-multipart-upload.html

Mais ni travailler pour moi. La confusion que je continue à courir est ce qui est vraiment nécessaire pour faire une demande en plusieurs parties. Quel est le moyen le plus simple d'avoir un téléchargement multipart (avec une image) pour Android?

Toute aide ou conseil serait grandement apprécié!


Comme MultiPartEntity est obsolète . Alors voici la nouvelle façon de le faire! Et vous n'avez besoin que de httpcore.jar(latest) et de httpmime.jar(latest) télécharger depuis le site Apache.

try
{
    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(URL);

    MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
    entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

    entityBuilder.addTextBody(USER_ID, userId);
    entityBuilder.addTextBody(NAME, name);
    entityBuilder.addTextBody(TYPE, type);
    entityBuilder.addTextBody(COMMENT, comment);
    entityBuilder.addTextBody(LATITUDE, String.valueOf(User.Latitude));
    entityBuilder.addTextBody(LONGITUDE, String.valueOf(User.Longitude));

    if(file != null)
    {
        entityBuilder.addBinaryBody(IMAGE, file);
    }

    HttpEntity entity = entityBuilder.build();
    post.setEntity(entity);
    HttpResponse response = client.execute(post);
    HttpEntity httpEntity = response.getEntity();
    result = EntityUtils.toString(httpEntity);
    Log.v("result", result);
}
catch(Exception e)
{
    e.printStackTrace();
}

Essaye ça:

    public void SendMultipartFile() {
    Log.d(TAG, "UPLOAD: SendMultipartFile");
    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpPost httppost = new HttpPost( <url> );

    File file = new File("/sdcard/spider.jpg");

    Log.d(TAG, "UPLOAD: setting up multipart entity");

    MultipartEntity mpEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
    Log.d(TAG, "UPLOAD: file length = " + file.length());
    Log.d(TAG, "UPLOAD: file exist = " + file.exists());

    try {
        mpEntity.addPart("datafile", new FileBody(file, "application/octet"));
        mpEntity.addPart("id", new StringBody("1"));
    } catch (UnsupportedEncodingException e1) {
        Log.d(TAG, "UPLOAD: UnsupportedEncodingException");
        e1.printStackTrace();
    }

    httppost.setEntity(mpEntity);
    Log.d(TAG, "UPLOAD: executing request: " + httppost.getRequestLine());
    Log.d(TAG, "UPLOAD: request: " + httppost.getEntity().getContentType().toString());


    HttpResponse response;
    try {
        Log.d(TAG, "UPLOAD: about to execute");
        response = httpclient.execute(httppost);
        Log.d(TAG, "UPLOAD: executed");
        HttpEntity resEntity = response.getEntity();
        Log.d(TAG, "UPLOAD: respose code: " + response.getStatusLine().toString());
        if (resEntity != null) {
            Log.d(TAG, "UPLOAD: " + EntityUtils.toString(resEntity));
        }
        if (resEntity != null) {
            resEntity.consumeContent();
        }
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Je recommande fortement Loopj.

Je l'ai utilisé avec succès pour télécharger plusieurs fichiers à la fois, y compris les différents types mime. Faites simplement ceci:

File myVideo = new File("/path/to/myvideo.mp4");
File myPic = new File("/path/to/mypic.jpg");
RequestParams params = new RequestParams();
try {
  params.put("profile_picture", myPic);
  params.put("my_video", myVideo);
} catch(FileNotFoundException e) {}

Pour les fichiers volumineux ou nombreux, vous devrez peut-être augmenter le délai d'attente, sinon le délai d'expiration par défaut est utilisé, ce qui peut être trop court:

client.setTimeout(500000) //make this the appropriate timeout in milliseconds

S'il vous plaît voir ces liens pour une description complète de loopj et comment l'utiliser, de loin la bibliothèque http async la plus facile que j'ai rencontrée:

http://loopj.com/android-async-http/ http://loopj.com/android-async-http/doc/com/loopj/android/http/AsyncHttpClient.html



Supprimez toute votre dépendance httppient, httpmime et ajoutez cette dépendance compile 'commons-httpclient:commons-httpclient:3.1' . Cette dépendance a intégré dans MultipartRequestEntity afin que vous puissiez facilement télécharger un ou plusieurs fichiers sur le serveur

public class FileUploadUrlConnection extends AsyncTask<String, String, String> {
private Context context;
private String url;
private List<File> files;

public FileUploadUrlConnection(Context context, String url, List<File> files) {
    this.context = context;
    this.url = url;
    this.files = files;
}

@Override
protected String doInBackground(String... params) {

    HttpClient client = new HttpClient();
    PostMethod post = new PostMethod(url);
    HttpClientParams connectionParams = new HttpClientParams();

    post.setRequestHeader(// Your header goes here );

    try {
        Part[] parts = new Part[files.size()];
        for (int i=0; i<files.size(); i++) {
            Part part = new FilePart(files.get(i).getName(), files.get(i));
            parts[i] = part;
        }

        MultipartRequestEntity entity = new MultipartRequestEntity(parts, connectionParams);

        post.setRequestEntity(entity);

        int statusCode = client.executeMethod(post);
        String response = post.getResponseBodyAsString();

        Log.v("Multipart "," "+response);
        if(statusCode == 200) {
            return response;
        }
    } catch (IOException e) {
        e.printStackTrace();
    } 
 return null;
}

Vous pouvez également ajouter la demande et le délai de réponse

client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 10000);

Voici la solution LIGHT WEIGHTED qui a fonctionné pour moi sans HTTPCore externe et de telles libs. Je faisais face à un problème de méthodes 64K, donc je n'ai plus d'option pour éviter les bibliothèques HTTPCore

import java.util.List;

import java.io.BufferedReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

/**
 * This utility class provides an abstraction layer for sending multipart HTTP
 * POST requests to a web server.
 *
 * @author www.codejava.net
 */
public class MultipartUtility {
    private final String boundary;
    private static final String LINE_FEED = "\r\n";
    private HttpURLConnection httpConn;
    private String charset;
    private OutputStream outputStream;
    private PrintWriter writer;

    /**
     * This constructor initializes a new HTTP POST request with content type
     * is set to multipart/form-data
     *
     * @param requestURL
     * @param charset
     * @throws IOException
     */
    public MultipartUtility(String requestURL, String charset)
            throws IOException {
        this.charset = charset;

        // creates a unique boundary based on time stamp
        boundary = "===" + System.currentTimeMillis() + "===";

        URL url = new URL(requestURL);
        httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setUseCaches(false);
        httpConn.setDoOutput(true); // indicates POST method
        httpConn.setDoInput(true);
        httpConn.setRequestProperty("Content-Type",
                "multipart/form-data; boundary=" + boundary);
        httpConn.setRequestProperty("User-Agent", "CodeJava Agent");
        httpConn.setRequestProperty("Test", "Bonjour");
        outputStream = httpConn.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
                true);
    }

    /**
     * Adds a form field to the request
     *
     * @param name  field name
     * @param value field value
     */
    public void addFormField(String name, String value) {
        writer.append("--" + boundary).append(LINE_FEED);
        writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
                .append(LINE_FEED);
        writer.append("Content-Type: text/plain; charset=" + charset).append(
                LINE_FEED);
        writer.append(LINE_FEED);
        writer.append(value).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a upload file section to the request
     *
     * @param fieldName  name attribute in <input type="file" name="..." />
     * @param uploadFile a File to be uploaded
     * @throws IOException
     */
    public void addFilePart(String fieldName, File uploadFile)
            throws IOException {
        String fileName = uploadFile.getName();
        writer.append("--" + boundary).append(LINE_FEED);
        writer.append(
                "Content-Disposition: form-data; name=\"" + fieldName
                        + "\"; filename=\"" + fileName + "\"")
                .append(LINE_FEED);
        writer.append(
                "Content-Type: "
                        + URLConnection.guessContentTypeFromName(fileName))
                .append(LINE_FEED);
        writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
        writer.append(LINE_FEED);
        writer.flush();

        FileInputStream inputStream = new FileInputStream(uploadFile);
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.flush();
        inputStream.close();

        writer.append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a header field to the request.
     *
     * @param name  - name of the header field
     * @param value - value of the header field
     */
    public void addHeaderField(String name, String value) {
        writer.append(name + ": " + value).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Completes the request and receives response from the server.
     *
     * @return a list of Strings as response in case the server returned
     * status OK, otherwise an exception is thrown.
     * @throws IOException
     */
    public List<String> finish() throws IOException {
        List<String> response = new ArrayList<String>();

        writer.append(LINE_FEED).flush();
        writer.append("--" + boundary + "--").append(LINE_FEED);
        writer.close();

        // checks server's status code first
        int status = httpConn.getResponseCode();
        if (status == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    httpConn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                response.add(line);
            }
            reader.close();
            httpConn.disconnect();
        } else {
            throw new IOException("Server returned non-OK status: " + status);
        }

        return response;
    }
}

USAGE

private void uploadMedia() {
        try {

            String charset = "UTF-8";
            File uploadFile1 = new File("/sdcard/myvideo.mp4");
            String requestURL = Data.BASE_URL+Data.URL_UPLOAD_REACTION_TEST;

            MultipartUtility multipart = new MultipartUtility(requestURL, charset);

//            multipart.addHeaderField("User-Agent", "CodeJava");
//            multipart.addHeaderField("Test-Header", "Header-Value");

            multipart.addFormField("friend_id", "Cool Pictures");
            multipart.addFormField("userid", "Java,upload,Spring");

            multipart.addFilePart("uploadedfile", uploadFile1);

            List<String> response = multipart.finish();

            Log.v("rht", "SERVER REPLIED:");

            for (String line : response) {
                Log.v("rht", "Line : "+line);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

Code PHP pour accepter le téléchargement

<?php

    $friend_id = $_REQUEST['friend_id'];
    $userid = $_REQUEST['userid'];

    echo 'friend_id : '.$friend_id. ' userid '.$userid;

    move_uploaded_file($_FILES['uploadedfile']['tmp_name'], "./uploads/".$_FILES["uploadedfile"]["name"]);

?>

Mise à jour le 29 avril 2014:

Ma réponse est plutôt ancienne et je suppose que vous préférez utiliser une sorte de bibliothèque de haut niveau telle que Retrofit .

Sur la base de ce blog, j'ai trouvé la solution suivante: http://blog.tacticalnuclearstrike.com/2010/01/using-multipartentity-in-android-applications/

Vous devrez télécharger des bibliothèques supplémentaires pour faire fonctionner MultipartEntity !

1) Téléchargez httpcomponents-client-4.1.zip depuis http://james.apache.org/download.cgi#Apache_Mime4J et ajoutez apache-mime4j-0.6.1.jar à votre projet.

2) Téléchargez httpcomponents-client-4.1-bin.zip depuis http://hc.apache.org/downloads.cgi et ajoutez httpclient-4.1.jar, httpcore-4.1.jar et httpmime-4.1.jar à votre projet.

3) Utilisez le code d'exemple ci-dessous.

private DefaultHttpClient mHttpClient;


public ServerCommunication() {
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
    mHttpClient = new DefaultHttpClient(params);
}


public void uploadUserPhoto(File image) {

    try {

        HttpPost httppost = new HttpPost("some url");

        MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);  
        multipartEntity.addPart("Title", new StringBody("Title"));
        multipartEntity.addPart("Nick", new StringBody("Nick"));
        multipartEntity.addPart("Email", new StringBody("Email"));
        multipartEntity.addPart("Description", new StringBody(Settings.SHARE.TEXT));
        multipartEntity.addPart("Image", new FileBody(image));
        httppost.setEntity(multipartEntity);

        mHttpClient.execute(httppost, new PhotoUploadResponseHandler());

    } catch (Exception e) {
        Log.e(ServerCommunication.class.getName(), e.getLocalizedMessage(), e);
    }
}

private class PhotoUploadResponseHandler implements ResponseHandler<Object> {

    @Override
    public Object handleResponse(HttpResponse response)
            throws ClientProtocolException, IOException {

        HttpEntity r_entity = response.getEntity();
        String responseString = EntityUtils.toString(r_entity);
        Log.d("UPLOAD", responseString);

        return null;
    }

}

public class Multipart{
    private final Map<String, String> headrs;
    private String url;
    private HttpURLConnection con;
    private OutputStream os;

    private String delimiter = "--";
    private String boundary = "TRR" + Long.toString(System.currentTimeMillis()) + "TRR";

    public Multipart (String url, Map<String, String> headers) {
        this.url = url;
        this.headrs = headers;
    }

    public void connectForMultipart() throws Exception {
        con = (HttpURLConnection) (new URL(url)).openConnection();
        con.setRequestMethod("POST");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setRequestProperty("Connection", "Keep-Alive");
        for (Map.Entry<String, String> entry : headrs.entrySet()) {
            con.setRequestProperty(entry.getKey(), entry.getValue());
        }
        con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        con.connect();
        os = con.getOutputStream();
    }

    public void addFormPart(String paramName, String value) throws Exception {
        writeParamData(paramName, value);
    }

    public void addFilePart(String paramName, String fileName, byte[] data) throws Exception {
        os.write((delimiter + boundary + "\r\n").getBytes());
        os.write(("Content-Disposition: form-data; name=\"" + paramName + "\"; filename=\"" + fileName + "\"\r\n").getBytes());
        os.write(("Content-Type: application/octet-stream\r\n").getBytes());
        os.write(("Content-Transfer-Encoding: binary\r\n").getBytes());
        os.write("\r\n".getBytes());

        os.write(data);

        os.write("\r\n".getBytes());
    }

    public void finishMultipart() throws Exception {
        os.write((delimiter + boundary + delimiter + "\r\n").getBytes());
    }


    public String getResponse() throws Exception {
        InputStream is = con.getInputStream();
        byte[] b1 = new byte[1024];
        StringBuffer buffer = new StringBuffer();

        while (is.read(b1) != -1)
            buffer.append(new String(b1));

        con.disconnect();

        return buffer.toString();
    }


    private void writeParamData(String paramName, String value) throws Exception {


        os.write((delimiter + boundary + "\r\n").getBytes());
        os.write("Content-Type: text/plain\r\n".getBytes());//;charset=utf-8
        os.write(("Content-Disposition: form-data; name=\"" + paramName + "\"\r\n").getBytes());
        ;
        os.write(("\r\n" + value + "\r\n").getBytes());


    }
}

Puis appelez ci-dessous

Multipart multipart = new Multipart(url__, map);
            multipart .connectForMultipart();
multipart .addFormPart(entry.getKey(), entry.getValue());
multipart .addFilePart(KeyName, "FileName", imagedata);
multipart .finishMultipart();




android-sdk-2.1