我一直在努力从WebView上传文件。我在谷歌上搜索并实施了所有建议的解决方案(例如这篇SO帖子),但没有一个可行。

我有一个HTML页面与以下代码上传文件。

<form method="POST" enctype="multipart/form-data">
  File to upload: <input type="file" name="uploadfile">&nbsp;&nbsp;
  <input type="submit" value="Press to Upload..."> to upload the file!
</form>

它在桌面浏览器如Firefox和内置浏览器中运行良好 的模拟器/ AVD,即,当我点击“浏览…”按钮渲染 元素,浏览器打开一个对话框 框,在那里我可以选择一个文件上传。

然而,在android 3.0模拟器/ AVD中,当我点击“选择” 文件”,什么都没有发生,没有文件对话框被打开!


当前回答

这是一个完整的解决方案,所有的android版本,我有一个艰难的时间与此。

public class MyWb extends Activity {
/** Called when the activity is first created. */

WebView web;
ProgressBar progressBar;

private ValueCallback<Uri> mUploadMessage;  
 private final static int FILECHOOSER_RESULTCODE=1;  

 @Override  
 protected void onActivityResult(int requestCode, int resultCode,  
                                    Intent intent) {  
  if(requestCode==FILECHOOSER_RESULTCODE)  
  {  
   if (null == mUploadMessage) return;  
            Uri result = intent == null || resultCode != RESULT_OK ? null  
                    : intent.getData();  
            mUploadMessage.onReceiveValue(result);  
            mUploadMessage = null;  
  }
  }  

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    web = (WebView) findViewById(R.id.webview01);
    progressBar = (ProgressBar) findViewById(R.id.progressBar1);

    web = new WebView(this);  
    web.getSettings().setJavaScriptEnabled(true);
    web.loadUrl("http://www.script-tutorials.com/demos/199/index.html");
    web.setWebViewClient(new myWebClient());
    web.setWebChromeClient(new WebChromeClient()  
    {  
           //The undocumented magic method override  
           //Eclipse will swear at you if you try to put @Override here  
        // For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {  

            mUploadMessage = uploadMsg;  
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);  
            i.addCategory(Intent.CATEGORY_OPENABLE);  
            i.setType("image/*");  
            MyWb.this.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);  

           }

        // For Android 3.0+
           public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
           mUploadMessage = uploadMsg;
           Intent i = new Intent(Intent.ACTION_GET_CONTENT);
           i.addCategory(Intent.CATEGORY_OPENABLE);
           i.setType("*/*");
           MyWb.this.startActivityForResult(
           Intent.createChooser(i, "File Browser"),
           FILECHOOSER_RESULTCODE);
           }

        //For Android 4.1
           public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
               mUploadMessage = uploadMsg;  
               Intent i = new Intent(Intent.ACTION_GET_CONTENT);  
               i.addCategory(Intent.CATEGORY_OPENABLE);  
               i.setType("image/*");  
               MyWb.this.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MyWb.FILECHOOSER_RESULTCODE );

           }

    });  


    setContentView(web);  


}

public class myWebClient extends WebViewClient
{
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        // TODO Auto-generated method stub
        super.onPageStarted(view, url, favicon);
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // TODO Auto-generated method stub

        view.loadUrl(url);
        return true;

    }

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

        progressBar.setVisibility(View.GONE);
    }
}

//flipscreen not loading again
@Override
public void onConfigurationChanged(Configuration newConfig){        
    super.onConfigurationChanged(newConfig);
}

// To handle "Back" key press event for WebView to go back to previous screen.
/*@Override
public boolean onKeyDown(int keyCode, KeyEvent event) 
{
    if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) {
        web.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}*/
}

我还想补充一点,像这个例子中的“上传页面”,不会在< 4个版本上工作,因为它有一个图像预览功能,如果你想让它工作,使用一个简单的php上传没有预览。

更新:

请在这里找到棒棒糖装置的解决方案,感谢gauntface

更新2:

完整的解决方案,所有android设备,直到奥利奥这里,这是更高级的版本,你应该看看,也许它可以帮助。

其他回答

Android 8的Kotlin解决方案:

private var mUploadMessage: ValueCallback<Uri>? = null
private var uploadMessage: ValueCallback<Array<Uri>>? = null

常量:

const val FILECHOOSER_RESULTCODE = 1
const val REQUEST_SELECT_FILE = 100

WebView设置:

webView.webChromeClient = object : WebChromeClient() {
        override fun onPermissionRequest(request: PermissionRequest?) {
            Log.d("MainActivity", "onPermissionRequest")
            requestPermission(request)
        }


        // For Android 3.0+
        fun openFileChooser(uploadMsg: ValueCallback<*>, acceptType: String) {
            mUploadMessage = uploadMsg as ValueCallback<Uri>
            val i = Intent(Intent.ACTION_GET_CONTENT)
            i.addCategory(Intent.CATEGORY_OPENABLE)
            i.type = "*/*"
            this@MainActivity.startActivityForResult(
                    Intent.createChooser(i, "File Browser"),
                    FILECHOOSER_RESULTCODE)
        }

        //For Android 4.1
        fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String, capture: String) {
            mUploadMessage = uploadMsg
            val i = Intent(Intent.ACTION_GET_CONTENT)
            i.addCategory(Intent.CATEGORY_OPENABLE)
            i.type = "image/*"
            this@MainActivity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE)

        }

        protected fun openFileChooser(uploadMsg: ValueCallback<Uri>) {
            mUploadMessage = uploadMsg
            val intent = Intent(Intent.ACTION_GET_CONTENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            intent.type = "*/*"
            startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE)
        }

        override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean {
            uploadMessage?.onReceiveValue(null)
            uploadMessage = null

            uploadMessage = filePathCallback

            val intent = fileChooserParams!!.createIntent()
            try {
                startActivityForResult(intent, REQUEST_SELECT_FILE)
            } catch (e: ActivityNotFoundException) {
                uploadMessage = null
                Toast.makeText(applicationContext, "Cannot Open File Chooser", Toast.LENGTH_LONG).show()
                return false
            }

            return true
        }

    }

onactivityresult部分:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        if (requestCode === REQUEST_SELECT_FILE) {
            if (uploadMessage == null)
                return
            print("result code = " + resultCode)
            var results: Array<Uri>? = WebChromeClient.FileChooserParams.parseResult(resultCode, data)
            uploadMessage?.onReceiveValue(results)
            uploadMessage = null
        }
    } else if (requestCode === FILECHOOSER_RESULTCODE) {
        if (null == mUploadMessage)
            return
        // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
        // Use RESULT_OK only if you're implementing WebView inside an Activity
        val result = if (intent == null || resultCode !== RESULT_OK) null else intent.data
        mUploadMessage?.onReceiveValue(result)
        mUploadMessage = null
    } else
        Toast.makeText(applicationContext, "Failed to Upload Image", Toast.LENGTH_LONG).show()
}

请注意,我们的意图变量称为“数据”。

蜂窝(API 11)到Android 11的工作方法

由swati vishnoi更新,这适用于派和以上

static WebView mWebView;
private ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> uploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;

修改onActivityResult ()

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    {
        if (requestCode == REQUEST_SELECT_FILE)
        {
            if (uploadMessage == null)
                return;
            uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
            uploadMessage = null;
        }
    }
    else if (requestCode == FILECHOOSER_RESULTCODE)
    {
        if (null == mUploadMessage)
            return;
    // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
    // Use RESULT_OK only if you're implementing WebView inside an Activity
        Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData();
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;
    }
    else
        Toast.makeText(getActivity().getApplicationContext(), "Failed to Upload Image", Toast.LENGTH_LONG).show();
}

现在在onCreate()或onCreateView()中粘贴以下代码

    WebSettings mWebSettings = mWebView.getSettings();
    mWebSettings.setJavaScriptEnabled(true);
    mWebSettings.setSupportZoom(false);
    mWebSettings.setAllowFileAccess(true);
    mWebSettings.setAllowContentAccess(true);

mWebView.setWebChromeClient(new WebChromeClient()
{
    // For 3.0+ Devices (Start)
    // onActivityResult attached before constructor
    protected void openFileChooser(ValueCallback uploadMsg, String acceptType)
    {
        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
    }
   

    // For Lollipop 5.0+ Devices
    public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
    {
        if (uploadMessage != null) {
            uploadMessage.onReceiveValue(null);
            uploadMessage = null;
        }

        uploadMessage = filePathCallback;

        Intent intent = fileChooserParams.createIntent();
        try
        {
            startActivityForResult(intent, REQUEST_SELECT_FILE);
        } catch (ActivityNotFoundException e)
        {
            uploadMessage = null;
            Toast.makeText(getActivity().getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
            return false;
        }
        return true;
    }
    
    //For Android 4.1 only
    protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
    {
        mUploadMessage = uploadMsg;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
    }

    protected void openFileChooser(ValueCallback<Uri> uploadMsg)
    {
        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
    }
});

我发现我需要3个接口定义,以处理不同版本的android。

public void openFileChooser(ValueCallback < Uri > uploadMsg) {
  mUploadMessage = uploadMsg;
  Intent i = new Intent(Intent.ACTION_GET_CONTENT);
  i.addCategory(Intent.CATEGORY_OPENABLE);
  i.setType("image/*");
  FreeHealthTrack.this.startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILECHOOSER_RESULTCODE);
}

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

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

你访问过这个链接吗? http://groups.google.com/group/android-developers/browse_thread/thread/dcaf8b2fdd8a90c4/62d5e2ffef31ebdb

http://moazzam-khan.com/blog/?tag=android-upload-file

http://evgenyg.wordpress.com/2010/05/01/uploading-files-multipart-post-apache/

通过javalib Apache Commons上传文件的简明示例

我想你会从中得到帮助的

这是我发现的唯一有效的解决方案!

WebView webview;

private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1;

@Override
protected void onActivityResult(int requestCode, int resultCode,
        Intent intent) {
    if (requestCode == FILECHOOSER_RESULTCODE) {
        if (null == mUploadMessage)
            return;
        Uri result = intent == null || resultCode != RESULT_OK ? null
                : intent.getData();
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;

    }
}

// Next part 

class MyWebChromeClient extends WebChromeClient {
    // The undocumented magic method override
    // Eclipse will swear at you if you try to put @Override here
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {

        mUploadMessage = uploadMsg;
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        Cv5appActivity.this.startActivityForResult(
                Intent.createChooser(i, "Image Browser"),
                FILECHOOSER_RESULTCODE);
    }
}