前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android开发笔记(一百五十二)H5通过WebView上传图片

Android开发笔记(一百五十二)H5通过WebView上传图片

作者头像
aqi00
发布2019-01-18 15:16:23
1.2K0
发布2019-01-18 15:16:23
举报

上一篇文章介绍了WebView与JS之间的数据交互,其实就是把字符串传来传去,这对文本格式的信息传输来说倒还凑合,倘若要传输图片信息就不管用了。所以,要想让h5网页支持从手机上传图片,还得另外想办法,当然各版本的Android系统也都提供了相应的解决办法。在Android 4.*系统上面,开发者可以重写WebChromeClient的openFileChooser函数;在Android 5.0以上的系统,开发者可以重写WebChromeClient的onShowFileChooser函数。话虽如此,可实际编码的时候,会发现并不容易,因为不但要兼容各种版本的安卓系统,而且要考虑不同操作方式下面的处理步骤。 首先是Android不同系统的适配问题,对于4.*版本要重写openFileChooser方法,对于5.0以上版本要重写onShowFileChooser方法。另外注意二者的回调方式也不一样,4.*的回调参数类型是ValueCallback<Uri>,而5.0以上的回调参数类型是ValueCallback<Uri[]>,因此要声明两个回调参数变量,分别用来保存二者各自的回调信息。相关代码如下所示:

	private static ValueCallback<Uri> mUploadMessage;
	private static ValueCallback<Uri[]> mUploadMessageLollipop;
	
	private class MyWebChromeClient extends WebChromeClient {

		// Android 4.*(包括4.1、4.2、4.3、4.4)
		public void openFileChooser(ValueCallback<Uri> uploadMsg,
				String acceptType, String capture) {
			Log.d(TAG, "openFileChooser 4.*");
			mUploadMessage = uploadMsg;
			openSelectDialog();
		}

		// Android 5.0+(包括5.*、6.0、7.*、8.*)
		@Override
		public boolean onShowFileChooser(WebView webView,
				ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
			Log.d(TAG, "openFileChooser 5.0+");
			mUploadMessageLollipop = filePathCallback;
			openSelectDialog();
			return true;
		}
	}

然后就上传图片这个功能而言,既要支持从手机相册中挑选已有的图片,也要支持现场拍照并即时上传拍摄好的照片。如此一来,就不能仅仅从相册选择文件,而要弹出一个列表对话框,好让用户决定是从相册上传图片,还是当场拍照当场上传。所以接下来得同时实现这两种上传方式,示例代码如下:

	private String mCameraPhotoPath = null;
	
	private void openSelectDialog() {
		// 声明相机的拍照行为
		Intent photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
		if (photoIntent.resolveActivity(getPackageManager()) != null) {
			mCameraPhotoPath = "file:" + getExternalFilesDir(Environment.DIRECTORY_PICTURES)
							.toString() + "/" + DateUtil.getNowDateTime("") + ".jpg";
			Log.d(TAG, "photoFile=" + mCameraPhotoPath);
			photoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.parse(mCameraPhotoPath));
		}
		Intent[] intentArray = new Intent[] { photoIntent };
		// 声明相册的打开行为
		Intent selectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
		selectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
		selectionIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
		selectionIntent.setType("image/*");
		// 弹出含相机和相册在内的列表对话框
		Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
		chooserIntent.putExtra(Intent.EXTRA_INTENT, selectionIntent);
		chooserIntent.putExtra(Intent.EXTRA_TITLE, "请拍照或选择图片");
		chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
		startActivityForResult(Intent.createChooser(chooserIntent, "选择图片"), 1);
	}

选择好图片确定后(含拍照和从相册选取),App代码进入到onActivityResult方法内部,开发者在此校验结果代码,根据图片选取形式分别获得具体的图片数据,然后区分4.*系统和5.+系统将图片传给h5页面。下面是onActivityResult方法的处理代码:

	private static final int FILE_SELECT_CODE = 1;
	private int mResultCode = Activity.RESULT_CANCELED;
	
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		Log.d(TAG, "onActivityResult requestCode=" + requestCode + ", resultCode=" + resultCode);
		if (requestCode != FILE_SELECT_CODE
				|| (mUploadMessage == null && mUploadMessageLollipop == null)) {
			super.onActivityResult(requestCode, resultCode, data);
			return;
		}
		mResultCode = resultCode;
		Log.d(TAG, "mCameraPhotoPath=" + mCameraPhotoPath);
		if (resultCode == Activity.RESULT_OK) {
			uploadPhoto(resultCode, data);
		}
	}

	private void uploadPhoto(int resultCode, Intent data) {
		long fileSize = 0;
		try {
			String file_path = mCameraPhotoPath.replace("file:", "");
			File file = new File(file_path);
			fileSize = file.length();
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (data != null || mCameraPhotoPath != null) {
			Integer count = 1;
			ClipData images = null;
			try {
				images = data.getClipData();
			} catch (Exception e) {
				e.printStackTrace();
			}

			if (images == null && data != null && data.getDataString() != null) {
				count = data.getDataString().length();
			} else if (images != null) {
				count = images.getItemCount();
			}
			Uri[] results = new Uri[count];
			// Check that the response is a good one
			if (resultCode == Activity.RESULT_OK) {
				Log.d(TAG, "fileSize=" + fileSize);
				if (fileSize != 0) {
					// If there is not data, then we may have taken a photo
					if (mCameraPhotoPath != null) {
						results = new Uri[] { Uri.parse(mCameraPhotoPath) };
					}
				} else if (data.getClipData() == null) {
					results = new Uri[] { Uri.parse(data.getDataString()) };
				} else {
					for (int i = 0; i < images.getItemCount(); i++) {
						results[i] = images.getItemAt(i).getUri();
					}
				}
			}
			// 区分不同系统分别返回上传结果
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
				mUploadMessageLollipop.onReceiveValue(results);
				mUploadMessageLollipop = null;
			} else {
				mUploadMessage.onReceiveValue(results[0]);
				mUploadMessage = null;
			}
		}
	}

其后还要注意,用户打开相册或者打开相机的时候,也有可能什么都不做就返回到原页面,由于这个取消选择的操作没有走完全流程,导致h5网页的回调资源没有回收,用户再去上传图片之时会发现页面不会响应了,因此开发者要在代码中手工替h5页面回收回调资源,这样下次用户才能继续上传图片。手工回收资源的办法是重写Activity的onResume函数,具体实现代码见下:

	@Override
	protected void onResume() {
		super.onResume();
		// 取消选择时需要回调onReceiveValue,否则网页会挂住,不会再响应点击事件
		if (mResultCode == Activity.RESULT_CANCELED) {
			try {
				if (mUploadMessageLollipop != null) {
					mUploadMessageLollipop.onReceiveValue(null);
				}
				if (mUploadMessage != null) {
					mUploadMessage.onReceiveValue(null);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

接着即可打开实际的h5页面进行图片上传测试啦,这里的h5测试网址用的是http://m.54php.cn/demo/h5_upload,测试的调用代码很简单,设置好WebView的访问地址以及浏览器对象就好了,例子代码如下所示:

		WebView webView = (WebView) findViewById(R.id.webView);
		WebSettings webSettings = webView.getSettings();
		webSettings.setJavaScriptEnabled(true);
		webSettings.setBuiltInZoomControls(true);
		webView.loadUrl("http://m.54php.cn/demo/h5_upload");
		webView.setWebViewClient(new MyWebViewClient(this));
		webView.setWebChromeClient(new MyWebChromeClient());

最后观察一下WebView配合上述测试网址的运行界面,先看看Android4.4手机的测试画面,下面的左图为打开测试网址的初始界面,右图为点击上传按钮后在屏幕中央弹出选择对话框:

先在对话框中选择从相册上传,成功上传图片后的h5页面如下面的左图所示;重新点击上传按钮,这次选择使用相机拍照,并把照片成功上传后的h5页面如下面的右图所示:

再来看看Android6.0手机的测试画面,下面的左图为打开测试网址的初始界面,右图为点击上传按钮后在屏幕下方弹出选择对话框:

先在对话框中选择从相册上传,成功上传图片后的h5页面如下面的左图所示;重新点击上传按钮,这次选择使用相机拍照,并把照片成功上传后的h5页面如下面的右图所示:

点此查看Android开发笔记的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年01月19日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档