【版权申明】非商业目的可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/97634019
出自:shusheng007
系列文章
Android开发之Webview中原生与JS交互
Android开发之在Webview中全屏播放视频
文章目录
概述
出于对成本或者其他原因的考虑,在移动开发中有时会采用混合开发的方式。即Web页面可以跑在原生的WebView里面,那么就会遇到各种各样的交互需求 ,我们今天要谈的从web页面选择图片或者文件就是其中之一。
实现方法
这个需求大概有两种实现方式:
第一种:使用Webview
与JS
交互的方式。当点击H5
页面中的选择文件按钮(不要求是<input>
标签),通过JS
调用原生的方法在这个方法里面使用原生的方式打开文件选择器。
第二种:使用H5
的<input type="file">
标签,通过webview
提供的内置机制来打开文件选择器。
如何选择
哪种方式更加合适呢,这个需要放到具体应用场景去谈论才有意义。
-
当你的APP中已经存在一套H5与原生交互的机制,而且App对文件选择器的定制要求较高,例如点击上传图片按钮打开像微信那样的自定义图片选择器,那么第一种方式更加适合。
-
当选择文件这个功能不太重要而且使用非常低频,或者要求不是很高,那么选择第二种较为方便。
总体来说,第一种方式灵活性更大,自定义能力更强。第二种会存在各种适配性问题,但是简单粗暴。
本文主要介绍第二种方式,第一种方式请参考 Android开发之Webview中原生与JS交互
WebView内置方案
主要是通过重写WebChromeClient
来实现的,如下面的代码所示。基本思想也很简单:通过WebChromeClient
的方法以startActivityForResult
的方式打开系统的文件选择器,选择文件后在onActivityResult
中将结果回传给Webview
即可。
当你的App最低支持版本为Android5.0
及以上就很简单了,只要重写WebChromeClient
中的 onShowFileChooser()
的方法即可。但是如果是5.0以下,那么还需要提供几个适配的方法,如下面的代码所示。
public class WebviewFileChooserAct extends AppCompatActivity{
private static final int REQUEST_CODE_FILE_CHOOSER = 1;
private ValueCallback<Uri> mUploadCallbackForLowApi;
private ValueCallback<Uri[]> mUploadCallbackForHighApi;
private WebView mWebView;
private WebChromeClient myWebChromeClient = new WebChromeClient() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
mUploadCallbackForHighApi = filePathCallback;
Intent intent = fileChooserParams.createIntent();
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
startActivityForResult(intent, REQUEST_CODE_FILE_CHOOSER);
} catch (ActivityNotFoundException e) {
mUploadCallbackForHighApi = null;
Toast.makeText(EShopAiCustomServiceAct.this, R.string.cant_open_file_chooser, Toast.LENGTH_LONG).show();
return false;
}
return true;
}
// For 3.0+
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFilerChooser(uploadMsg);
}
//For Android 4.1+
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
openFilerChooser(uploadMsg);
}
};
private WebViewClient myWebViewClient = new WebViewClient() {
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return;
}
//Web页面加载失败
}
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
if (request.isForMainFrame()) {
//Web页面加载失败
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_market_ai_custom_service);
mWebView = findViewById(R.id.webview);
configWebView(mWebView);
mWebView.loadUrl("you webpage url");
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_FILE_CHOOSER && (resultCode == RESULT_OK || resultCode == RESULT_CANCELED)) {
afterFileChooseGoing(resultCode, data);
}
}
private void afterFileChooseGoing(int resultCode, Intent data) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mUploadCallbackForHighApi == null) {
return;
}
mUploadCallbackForHighApi.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
mUploadCallbackForHighApi = null;
} else {
if (mUploadCallbackForLowApi == null) {
return;
}
Uri result = data == null ? null : data.getData();
mUploadCallbackForLowApi.onReceiveValue(result);
mUploadCallbackForLowApi = null;
}
}
private void configWebView(WebView webView) {
WebSettings settings = webView.getSettings();
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setJavaScriptEnabled(true);
webView.setWebViewClient(myWebViewClient);
webView.setWebChromeClient(myWebChromeClient);
}
private void openFilerChooser(ValueCallback<Uri> uploadMsg) {
mUploadCallbackForLowApi = uploadMsg;
startActivityForResult(Intent.createChooser(getFilerChooserIntent(), "File Chooser"), REQUEST_CODE_FILE_CHOOSER);
}
private Intent getFilerChooserIntent() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
return intent;
}
}
让我们对上面的实现方式做一个小的梳理
- 在web页面中加入
<input type="file">
标签
<input id="uploadImage" type="file" accept="image/*" name="myPhoto" >
accept 是接收文件的类型,上面的标签只接受image的类型
- 重写
WebChromeClient
中的onShowFileChooser()
的方法,并在其中打开文件选择器。 - 提供兼容低版本的方法
openFileChooser
,注意方法名称不可改变。 - 在
onActivityResult()
方法中接收选择结果并处理
notes:
1:注意同时处理成功选择文件及放弃选择文件两种情况,如果不对放弃这种操作进行处理就会遇到下次点击没有响应的情况。
2:Android 4.4据说不起作用,我没有做过相关验证。
概述
用心传播知识,只为后辈生活更美好(少加班,多陪家人,或者有更多的时间去做其他有意义的事情)。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/14745.html