Vinicius
Vinicius

Reputation: 69

Multiple file upload in Android Webview

Please, How can I enable or something else my Android Webview to upload multiple files?

When I upload only a file works very well, but I can't select more than one file to upload at the same time.

Is it possible? I think yes, but don't know how =/.

Upvotes: 6

Views: 8597

Answers (2)

shah0651
shah0651

Reputation: 335

Take a look of my code to upload multiple image , it will give you nice idea for other type of file also.

For selecting multiple image from gallery

i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);

An Ultimate Solution for multiple image upload with camera option also for Android Lollipop to Android 10, SDK 30.

private static final int FILECHOOSER_RESULTCODE   = 1;
private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mUploadMessages;
private Uri mCapturedImageURI = null;

Add this to OnCreate of MainActivity

mWebView.setWebChromeClient(new WebChromeClient() {

            // openFileChooser for Android 3.0+

            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType){
                mUploadMessage = uploadMsg;
                openImageChooser();
            }

            // For Lollipop 5.0+ Devices

            public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                mUploadMessages = filePathCallback;
                openImageChooser();
                return true;
            }

            // openFileChooser for Android < 3.0

            public void openFileChooser(ValueCallback<Uri> uploadMsg){
                openFileChooser(uploadMsg, "");
            }

            //openFileChooser for other Android versions

            public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
                openFileChooser(uploadMsg, acceptType);
            }

private void openImageChooser() {
    try {
        File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "FolderName");
        if (!imageStorageDir.exists()) {
            imageStorageDir.mkdirs();
        }
        File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
        mCapturedImageURI = Uri.fromFile(file);

        final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);

        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
        Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{captureIntent});

        startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

        });

onActivityResult

public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {


        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == FILECHOOSER_RESULTCODE) {

            if (null == mUploadMessage && null == mUploadMessages) {
                return;
            }

            if (null != mUploadMessage) {
                handleUploadMessage(requestCode, resultCode, data);

            } else if (mUploadMessages != null) {
                handleUploadMessages(requestCode, resultCode, data);
            }
        }





    }

    private void handleUploadMessage(final int requestCode, final int resultCode, final Intent data) {
        Uri result = null;
        try {
            if (resultCode != RESULT_OK) {
                result = null;
            } else {
                // retrieve from the private variable if the intent is null

                result = data == null ? mCapturedImageURI : data.getData();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;

        // code for all versions except of Lollipop
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

                result = null;

                try {
                    if (resultCode != RESULT_OK) {
                        result = null;
                    } else {
                        // retrieve from the private variable if the intent is null
                        result = data == null ? mCapturedImageURI : data.getData();
                    }
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), "activity :" + e, Toast.LENGTH_LONG).show();
                }

                mUploadMessage.onReceiveValue(result);
                mUploadMessage = null;
            }

        } // end of code for all versions except of Lollipop






    private void handleUploadMessages(final int requestCode, final int resultCode, final Intent data) {
        Uri[] results = null;
        try {
            if (resultCode != RESULT_OK) {
                results = null;
            } else {
                if (data != null) {
                    String dataString = data.getDataString();
                    ClipData clipData = data.getClipData();
                    if (clipData != null) {
                        results = new Uri[clipData.getItemCount()];
                        for (int i = 0; i < clipData.getItemCount(); i++) {
                            ClipData.Item item = clipData.getItemAt(i);
                            results[i] = item.getUri();
                        }
                    }
                    if (dataString != null) {
                        results = new Uri[]{Uri.parse(dataString)};
                    }
                } else {
                    results = new Uri[]{mCapturedImageURI};
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        mUploadMessages.onReceiveValue(results);
        mUploadMessages = null;
    }

Upvotes: 2

Vinicius
Vinicius

Reputation: 69

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();

    setContentView(R.layout.activity_webview);

    WebView webView = (WebView) findViewById(R.id.activity_main_webview);

    progress = (ProgressBar) findViewById(R.id.progressBar);
    progress.setVisibility(View.GONE);

    initWebView(webView);


    webView.loadUrl("URL"); // TODO input your url

}

private void initWebView(android.webkit.WebView webView) {

    WebSettings settings = webView.getSettings();

    settings.setJavaScriptEnabled(true);
    settings.setAllowFileAccess(true);
    settings.setDomStorageEnabled(true);
    settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
    settings.setLoadWithOverviewMode(true);
    settings.setUseWideViewPort(true);
    settings.setSupportZoom(true);
    settings.setSupportMultipleWindows(true);
    // settings.setPluginsEnabled(true);
    methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
    // settings.setPluginState(PluginState.ON);
    methodInvoke(settings, "setPluginState", new Class[] { WebSettings.PluginState.class }, new Object[] { WebSettings.PluginState.ON });
    // settings.setPluginsEnabled(true);
    methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
    // settings.setAllowUniversalAccessFromFileURLs(true);
    methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
    // settings.setAllowFileAccessFromFileURLs(true);
    methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });

    methodInvoke(settings, "setMixedContentAllowed", new Class[] { boolean.class }, new Object[] { true });


    webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
    webView.clearHistory();
    webView.clearFormData();
    webView.clearCache(true);

}

UploadHandler mUploadHandler;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

    if (requestCode == Controller.FILE_SELECTED) {
        // Chose a file from the file picker.
        if (mUploadHandler != null) {
            mUploadHandler.onResult(resultCode, intent);
        }
    }

    super.onActivityResult(requestCode, resultCode, intent);
}

class MyWebChromeClient extends WebChromeClient {
    public MyWebChromeClient() {

    }

    private String getTitleFromUrl(String url) {
        String title = url;
        try {
            URL urlObj = new URL(url);
            String host = urlObj.getHost();
            if (host != null && !host.isEmpty()) {
                return urlObj.getProtocol() + "://" + host;
            }
            if (url.startsWith("file:")) {
                String fileName = urlObj.getFile();
                if (fileName != null && !fileName.isEmpty()) {
                    return fileName;
                }
            }
        } catch (Exception e) {
            // ignore
        }

        return title;
    }

    @Override
    public boolean onJsAlert(android.webkit.WebView view, String url, String message, final JsResult result) {
        String newTitle = getTitleFromUrl(url);

        new AlertDialog.Builder(WebViewClass.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                result.confirm();
            }
        }).setCancelable(false).create().show();
        return true;
        // return super.onJsAlert(view, url, message, result);
    }

    @Override
    public boolean onJsConfirm(android.webkit.WebView view, String url, String message, final JsResult result) {

        String newTitle = getTitleFromUrl(url);

        new AlertDialog.Builder(WebViewClass.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                result.confirm();
            }
        }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                result.cancel();
            }
        }).setCancelable(false).create().show();
        return true;

        // return super.onJsConfirm(view, url, message, result);
    }

    // Android 2.x
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        openFileChooser(uploadMsg, "");
    }

    // Android 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        openFileChooser(uploadMsg, "", "filesystem");
    }

    // Android 4.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        mUploadHandler = new UploadHandler(new Controller());
        mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
    }

    // Android 4.4, 4.4.1, 4.4.2
    // openFileChooser function is not called on Android 4.4, 4.4.1, 4.4.2,
    // you may use your own java script interface or other hybrid framework.

    // Android 5.0.1
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public boolean onShowFileChooser(
            android.webkit.WebView webView, ValueCallback<Uri[]> filePathCallback,
            FileChooserParams fileChooserParams) {

        String acceptTypes[] = fileChooserParams.getAcceptTypes();

        String acceptType = "";
        for (int i = 0; i < acceptTypes.length; ++ i) {
            if (acceptTypes[i] != null && acceptTypes[i].length() != 0)
                acceptType += acceptTypes[i] + ";";
        }
        if (acceptType.length() == 0)
            acceptType = "*/*";

        final ValueCallback<Uri[]> finalFilePathCallback = filePathCallback;

        ValueCallback<Uri> vc = new ValueCallback<Uri>() {

            @Override
            public void onReceiveValue(Uri value) {

                Uri[] result;
                if (value != null)
                    result = new Uri[]{value};
                else
                    result = null;

                finalFilePathCallback.onReceiveValue(result);

            }
        };

        openFileChooser(vc, acceptType, "filesystem");


        return true;
    }
};

class Controller {
    final static int FILE_SELECTED = 4;

    Activity getActivity() {
        return WebViewClass.this;
    }
}

// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
// import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {

class UploadHandler {
    /*
     * The Object used to inform the WebView of the file to upload.
     */
    private ValueCallback<Uri> mUploadMessage;
    private String mCameraFilePath;
    private boolean mHandled;
    private boolean mCaughtActivityNotFoundException;
    private Controller mController;
    public UploadHandler(Controller controller) {
        mController = controller;
    }
    String getFilePath() {
        return mCameraFilePath;
    }
    boolean handled() {
        return mHandled;
    }
    void onResult(int resultCode, Intent intent) {
        if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
            // Couldn't resolve an activity, we are going to try again so skip
            // this result.
            mCaughtActivityNotFoundException = false;
            return;
        }
        Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
                : intent.getData();
        // As we ask the camera to save the result of the user taking
        // a picture, the camera application does not return anything other
        // than RESULT_OK. So we need to check whether the file we expected
        // was written to disk in the in the case that we
        // did not get an intent returned but did get a RESULT_OK. If it was,
        // we assume that this result has came back from the camera.
        if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
            File cameraFile = new File(mCameraFilePath);
            if (cameraFile.exists()) {
                result = Uri.fromFile(cameraFile);
                // Broadcast to the media scanner that we have a new photo
                // so it will be added into the gallery for the user.
                mController.getActivity().sendBroadcast(
                        new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
            }
        }
        mUploadMessage.onReceiveValue(result);
        mHandled = true;
        mCaughtActivityNotFoundException = false;
    }
    void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        final String imageMimeType = "image/*";
        final String videoMimeType = "video/*";
        final String audioMimeType = "audio/*";
        final String mediaSourceKey = "capture";
        final String mediaSourceValueCamera = "camera";
        final String mediaSourceValueFileSystem = "filesystem";
        final String mediaSourceValueCamcorder = "camcorder";
        final String mediaSourceValueMicrophone = "microphone";
        // According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
        // or 'microphone' and the default value should be 'filesystem'.
        String mediaSource = mediaSourceValueFileSystem;
        if (mUploadMessage != null) {
            // Already a file picker operation in progress.
            return;
        }
        mUploadMessage = uploadMsg;
        // Parse the accept type.
        String params[] = acceptType.split(";");
        String mimeType = params[0];
        if (capture.length() > 0) {
            mediaSource = capture;
        }
        if (capture.equals(mediaSourceValueFileSystem)) {
            // To maintain backwards compatibility with the previous implementation
            // of the media capture API, if the value of the 'capture' attribute is
            // "filesystem", we should examine the accept-type for a MIME type that
            // may specify a different capture value.
            for (String p : params) {
                String[] keyValue = p.split("=");
                if (keyValue.length == 2) {
                    // Process key=value parameters.
                    if (mediaSourceKey.equals(keyValue[0])) {
                        mediaSource = keyValue[1];
                    }
                }
            }
        }
        //Ensure it is not still set from a previous upload.
        mCameraFilePath = null;
        if (mimeType.equals(imageMimeType)) {
            if (mediaSource.equals(mediaSourceValueCamera)) {
                // Specified 'image/*' and requested the camera, so go ahead and launch the
                // camera directly.
                startActivity(createCameraIntent());
                return;
            } else {
                // Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
                // In all these cases we show a traditional picker filetered on accept type
                // so launch an intent for both the Camera and image/* OPENABLE.
                Intent chooser = createChooserIntent(createCameraIntent());
                chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
                startActivity(chooser);
                return;
            }
        } else if (mimeType.equals(videoMimeType)) {
            if (mediaSource.equals(mediaSourceValueCamcorder)) {
                // Specified 'video/*' and requested the camcorder, so go ahead and launch the
                // camcorder directly.
                startActivity(createCamcorderIntent());
                return;
            } else {
                // Specified just 'video/*', capture=filesystem or an invalid capture parameter.
                // In all these cases we show an intent for the traditional file picker, filtered
                // on accept type so launch an intent for both camcorder and video/* OPENABLE.
                Intent chooser = createChooserIntent(createCamcorderIntent());
                chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
                startActivity(chooser);
                return;
            }
        } else if (mimeType.equals(audioMimeType)) {
            if (mediaSource.equals(mediaSourceValueMicrophone)) {
                // Specified 'audio/*' and requested microphone, so go ahead and launch the sound
                // recorder.
                startActivity(createSoundRecorderIntent());
                return;
            } else {
                // Specified just 'audio/*',  capture=filesystem of an invalid capture parameter.
                // In all these cases so go ahead and launch an intent for both the sound
                // recorder and audio/* OPENABLE.
                Intent chooser = createChooserIntent(createSoundRecorderIntent());
                chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
                startActivity(chooser);
                return;
            }
        }
        // No special handling based on the accept type was necessary, so trigger the default
        // file upload chooser.
        startActivity(createDefaultOpenableIntent());
    }
    private void startActivity(Intent intent) {
        try {
            mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
        } catch (ActivityNotFoundException e) {
            // No installed app was able to handle the intent that
            // we sent, so fallback to the default file upload control.
            try {
                mCaughtActivityNotFoundException = true;
                mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
                        Controller.FILE_SELECTED);
            } catch (ActivityNotFoundException e2) {
                // Nothing can return us a file, so file upload is effectively disabled.
                Toast.makeText(mController.getActivity(), R.string.action_settings,
                        Toast.LENGTH_LONG).show();
            }
        }
    }
    private Intent createDefaultOpenableIntent() {
        // Create and return a chooser with the default OPENABLE
        // actions including the camera, camcorder and sound
        // recorder where available.
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("*/*");
        Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
                createSoundRecorderIntent());
        chooser.putExtra(Intent.EXTRA_INTENT, i);
        return chooser;
    }
    private Intent createChooserIntent(Intent... intents) {
        Intent chooser = new Intent(Intent.ACTION_CHOOSER);
        chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
        chooser.putExtra(Intent.EXTRA_TITLE,
                mController.getActivity().getResources()
                        .getString(R.string.action_settings));
        return chooser;
    }
    private Intent createOpenableIntent(String type) {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType(type);
        return i;
    }
    private Intent createCameraIntent() {
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        File externalDataDir = Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DCIM);
        File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
                File.separator + "Webbme");
        cameraDataDir.mkdirs();
        mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
                System.currentTimeMillis() + ".jpg";
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
        return cameraIntent;
    }
    private Intent createCamcorderIntent() {
        return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    }
    private Intent createSoundRecorderIntent() {
        return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
    }
}

Upvotes: 0

Related Questions