我一直在努力从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中,当我点击“选择” 文件”,什么都没有发生,没有文件对话框被打开!


当前回答

自定义WebChromeClient:

class AppChromeClient(private val fragmentWeakReference: WeakReference<WebViewFragment>) :
WebChromeClient() {
private var openFileCallback: ValueCallback<Array<Uri>>? = null

override fun onShowFileChooser(
    webView: WebView?,
    filePathCallback: ValueCallback<Array<Uri>>?,
    fileChooserParams: FileChooserParams?
): Boolean {
    if (filePathCallback == null) {
        return (super.onShowFileChooser(webView, filePathCallback, fileChooserParams))
    }
    openFileCallback = filePathCallback
    val webViewFragment = fragmentWeakReference.get() ?: return false
    webViewFragment.launchGetMultipleContents("*/*")

    return true
}

fun receiveFileCallback(result: Array<Uri>) {
    openFileCallback?.onReceiveValue(result)
    openFileCallback = null
}
}

WebViewFragment:

class WebViewFragment : Fragment() {
    private var _binding: FragmentWebviewBinding? = null
    private val binding get() = _binding!!
    private lateinit var webView: WebView
    private val chromeClient = AppChromeClient(WeakReference(this))
    private var contentLauncher: ActivityResultLauncher<String> = getMultipleContentLauncher()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentWebviewBinding.inflate(inflater, container, false)

        webView.webChromeClient = chromeClient
        val url = requireContext().getString(R.string.app_domain)
        webView.setting.javaScriptEnabled = true
        webView.loadUrl(url)
        return binding.root
    }


    private fun getMultipleContentLauncher(): ActivityResultLauncher<String> {
        return this.registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { list ->
            if (list.isEmpty()) {
                showToast("No files selected")
            }
            chromeClient.receiveFileCallback(list.toTypedArray())
        }
    }


    fun launchGetMultipleContents(type: String) {
        contentLauncher.launch(type)
    }
}

其他回答

我花了将近一个月的时间研究这个问题。一切都失败了。在多个网站中看到的所有代码都不工作。但这里存在最好的解决方案

https://github.com/chiclaim/android-webview-upload-file

步骤

1)点击克隆或下载

2)在本地目录中获取zip fle

3)解压压缩文件

4)开放Android工作室

5)转到文件---->打开>导航到你解压内容的目录。

6)在webView中更改所需的web url。loadUrl(“您的url hre”);在MainActivity.java

7)适用于Android studio 3.4.2版本

在棒棒糖5.0中,谷歌添加了一个官方方法WebChromeClient.onShowFileChooser。它们甚至提供了一种自动生成文件选择器意图的方法,以便它使用输入接受mime类型。

public class MyWebChromeClient extends WebChromeClient {
        // reference to activity instance. May be unnecessary if your web chrome client is member class.
    private MyActivity activity;

    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        // make sure there is no existing message
        if (myActivity.uploadMessage != null) {
            myActivity.uploadMessage.onReceiveValue(null);
            myActivity.uploadMessage = null;
        }

        myActivity.uploadMessage = filePathCallback;

        Intent intent = fileChooserParams.createIntent();
        try {
            myActivity.startActivityForResult(intent, MyActivity.REQUEST_SELECT_FILE);
        } catch (ActivityNotFoundException e) {
            myActivity.uploadMessage = null;
            Toast.makeText(myActivity, "Cannot open file chooser", Toast.LENGTH_LONG).show();
            return false;
        }

        return true;
    }
}


public class MyActivity extends ... {
    public static final int REQUEST_SELECT_FILE = 100;
    public ValueCallback<Uri[]> uploadMessage;

    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        if (requestCode == REQUEST_SELECT_FILE) {
                if (uploadMessage == null) return;
                uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                uploadMessage = null;
            }
        }
    }
}

对于KitKat之前的Android版本,其他答案中提到的私有方法是有效的。我还没有为KitKat(4.4)找到一个好的解决方案。

我发现我需要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);
    }
}