关于在android webview中使用File Upload控件的问题

来源:互联网 发布:it狂人女主角 编辑:程序博客网 时间:2024/04/26 08:41

参考http://stackoverflow.com/questions/5907369/file-upload-in-webview的回答后,做了一个自定义的MyWebViewActivity类,即包含webView的Activity类,要用的时候,你的Activity继承该类即可。

详细的不说了,大伙自己慢慢看吧,类文件内容如下:

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;


import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebViewClient;
import android.widget.Toast;


/**
 * 带webView的Activity,用于解决html中的<input type="file"...>控件无法打开上传界面的问题。
 * 可以根据实际需要打开摄像头、摄像机、录音机等
 * @author hxc
 *
 */
public class MyWebViewActivity extends ActionBarActivity {


@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
return super.onKeyUp(keyCode, event);
}
private String mURL;
public void setURL(String mURL) {
this.mURL = mURL;
}
private WebView webview;
private long firstTime =0 ;
UploadHandler mUploadHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webview = new WebView(this);  
        //设置WebView属性,能够执行Javascript脚本  
initWebView(webview);
        webview.loadUrl(mURL);
        

}
private void initWebView(WebView webView) {


        WebSettings settings = webView.getSettings();

        settings.setJavaScriptEnabled(true);
        settings.setAllowFileAccess(true);
        
        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        settings.setLoadWithOverviewMode(true);
        settings.setUseWideViewPort(true);
        settings.setSupportZoom(true);
        settings.setDomStorageEnabled(true);   
        settings.setDatabaseEnabled(true);  
        settings.setDatabasePath(MyWebViewActivity.this.getApplicationContext().getCacheDir().getAbsolutePath());  
       

        // settings.setPluginsEnabled(true);
        methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
        // settings.setPluginState(PluginState.ON);
        methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { 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 });


        webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        webView.clearHistory();
        webView.clearFormData();
        webView.clearCache(true);
        webview.setWebViewClient(new MyWebViewClient());
        webView.setWebChromeClient(new MyWebChromeClient());
        // webView.setDownloadListener(downloadListener);
    }
class MyWebViewClient extends WebViewClient{


@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
MyWebViewActivity.this.setContentView(webview);  
}




}

private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
       try {
           Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
           m.invoke(obj, args);
       } catch (Exception e) {
           e.printStackTrace();
       }


       return null;
   }
class MyWebChromeClient extends WebChromeClient {
        public MyWebChromeClient() {


        }


        @SuppressLint("NewApi")
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(WebView view, String url, String message, final JsResult result) {
            String newTitle = getTitleFromUrl(url);


            new AlertDialog.Builder(MyWebViewActivity.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(WebView view, String url, String message, final JsResult result) {


            String newTitle = getTitleFromUrl(url);


            new AlertDialog.Builder(MyWebViewActivity.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(true).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
        @SuppressLint("NewApi")
public boolean onShowFileChooser(
                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 MyWebViewActivity.this;
        }
    }

public boolean onKeyDown(int keyCode, KeyEvent event) {  
       if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) {  
           webview.goBack(); //goBack()表示返回WebView的上一页面  
           return true;  
       } 
       else
       {
        long secondTime = System.currentTimeMillis();   
            if (secondTime - firstTime  > 2000) {                                         //如果两次按键时间间隔大于2秒,则不退出  
                Toast.makeText(this, "再按一次退出程序", Toast.LENGTH_SHORT).show();   
                firstTime = secondTime;//更新firstTime  
                return true;   
            } else {                                                    //两次按键小于2秒时,退出应用  
            return  super.onKeyDown(keyCode, event);
            }   
       }
         
}
 
@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 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(), "上传无效",
                       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,"选择上传文件");
       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 + "browser-photos");
       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);
   }
}
}


在你的工程的中,如果想用这个自定义的Activity,你可以这样做:

public class MainActivity extends MyWebViewActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
setURL("http://www.baidu.com");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

大家可以在R.layout.activity_main布局文件中写一些欢迎信息,或者产品Logo,当webview加载网页完毕的时候,就会替换这个页面。

1 0
原创粉丝点击