赞
踩
在安卓开发过程中,会出现对接H5需要拍照及选择本地图片上传的需求。这个功能的实现需要调用安卓的相关操作,然后将获取到的图片路径传给H5。
input
标签中type="file"
可用于文件上传,accept="image/*"
表示上传的类型为Image类型,点击可通知安卓执行上传操作
<input type="file"
accept="image/*"
id="inputimg"/>
H5通过img
标签展示安卓端传过来的图片
<img id="image" style="width: 300px; height: 300px;">
在JavaScript中执行接收操作
<script type="text/javascript">
var input = document.getElementById("inputimg");
var image = document.getElementById("image");
input.onchange = function () {
var file = this.files[0];
var url = URL.createObjectURL(file);
image.src=url;
}
</script>
WebView中通过重写WebChromeClinet
的onShowFileChooser
或openFileChooser
方法来实现文件的上传
onShowFileChooser是5.0以上版本使用的,openFileChooser是4.1以上版本使用,但两个版本的API均有
ValueCallback
参数,通过调用ValueCallback参数的onReceiveValue
方法即可将选择图片的Uri传给H5。
因为两个API的实现方式类似,这里只介绍5.0以上的实现方法,不再介绍4.1+的API实现。
// 5.0+ @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { if (mFilePathCallback != null) { mFilePathCallback.onReceiveValue(null); } mFilePathCallback = filePathCallback; Intent intent = gotoChooseFile(); // 选择文件及拍照 startActivityForResult(intent, REQUEST_CODE_LOLIPOP); return true; } // 4.1+ public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) { }
使用系统自带的选择器弹出拍照或选择图片弹框,选中需要上传的图片后回到当前页面。
**注意事项:**
1、安卓6.0+的设备需要
动态添加拍照及读写内存的权限
,具体实现不再展示;
2、获取图片intent部分的ACTION_GET_CONTENT
也可以用ACTION_PICK
的方法代替。但不管使用ACTION_GET_CONTENT还是ACTION_PICK,在不同系统的手机上表现不同,例如:在6.0手机上,可能会出现相机、相册、文件管理,如果安装了其他相机,也会出现其他相机的选项;在5.x设备上,可能展示为相机、文档…
/** * 选择文件及拍照 */ private Intent gotoChooseFile() { String saveName = Environment.getExternalStorageDirectory().getPath() + "/" + Environment.DIRECTORY_DCIM + "/Camera/"; /** * 打开相机intent */ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(this.getPackageManager()) != null) { File photoFile = null; photoFile = new File(saveName + randomFileName() + ".jpg"); if (!photoFile.exists()) { mCameraPhotoPath = "file:" + photoFile.getAbsolutePath(); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); // 把Uri赋值给takePictureIntent } else { takePictureIntent = null; } } Intent[] takeoutArray = null; if (takePictureIntent != null) { takeoutArray = new Intent[]{takePictureIntent}; } else { takeoutArray = new Intent[0]; } /** * 获取图片intent */ Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); contentSelectionIntent.setType("image/*"); /** * 使用系统选择器 */ Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, takeoutArray); // 额外的intent return chooserIntent; } /** * 随机产生文件名 */ private String randomFileName() { return UUID.randomUUID().toString(); }
在onActivityResult中将从拍照或者文件中获取的图片Uri传递给H5
若没有选中图片而是点击了空白区域,则onReceiveValue一定要传null,否则无法再次唤起选择器。
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_LOLIPOP) { // 选择文件返回 5.0+ Uri[] results = null; if (resultCode == RESULT_OK) { if (data == null) { if (mCameraPhotoPath != null) { results = new Uri[]{Uri.parse(mCameraPhotoPath)}; } } else { String dataString = data.getDataString(); if (dataString != null) { results = new Uri[]{Uri.parse(dataString)}; } } } mFilePathCallback.onReceiveValue(results); // 当获取要传图片的Uri,通过该方法回调通知 mFilePathCallback = null; } }
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!DOCTYPE html> <html> <body> <input type="file" accept="image/*" id="inputimg"/> <img id="image" style="width: 300px; height: 300px;"> </body> <script type="text/javascript"> var input = document.getElementById("inputimg"); var image = document.getElementById("image"); input.onchange = function () { var file = this.files[0]; var url = URL.createObjectURL(file); image.src=url; } </script> </html>
public class MainActivity extends AppCompatActivity { private WebView mWebView = null; private ValueCallback<Uri[]> mFilePathCallback = null; private int REQUEST_CODE_LOLIPOP = 1; // 5.0以上版本 private String mCameraPhotoPath = ""; // 拍照的图片路径 @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base_webview); mWebView = (WebView) findViewById(R.id.base_web_view); showWebView(); } @SuppressLint({"SetJavaScriptEnabled"}) private void showWebView() { WebSettings webSettings = mWebView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setJavaScriptCanOpenWindowsAutomatically(true); mWebView.loadUrl("file:///android_asset/test2.html"); showCustomWebChromeClient(); } private void showCustomWebChromeClient() { mWebView.setWebChromeClient(new WebChromeClient() { // 5.0+ @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { if (mFilePathCallback != null) { mFilePathCallback.onReceiveValue(null); } mFilePathCallback = filePathCallback; Intent intent = gotoChooseFile(); // 选择文件及拍照 startActivityForResult(intent, REQUEST_CODE_LOLIPOP); return true; } // 4.1+ public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) { } }); } /** * 选择文件及拍照 */ private Intent gotoChooseFile() { String saveName = Environment.getExternalStorageDirectory().getPath() + "/" + Environment.DIRECTORY_DCIM + "/Camera/"; /** * 打开相机intent */ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(this.getPackageManager()) != null) { File photoFile = null; photoFile = new File(saveName + randomFileName() + ".jpg"); if (!photoFile.exists()) { mCameraPhotoPath = "file:" + photoFile.getAbsolutePath(); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); // 把Uri赋值给takePictureIntent } else { takePictureIntent = null; } } Intent[] takeoutArray = null; if (takePictureIntent != null) { takeoutArray = new Intent[]{takePictureIntent}; } else { takeoutArray = new Intent[0]; } /** * 获取图片intent */ Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); contentSelectionIntent.setType("image/*"); /** * 使用系统选择器 */ Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, takeoutArray); // 额外的intent return chooserIntent; } /** * 随机产生文件名 */ private String randomFileName() { return UUID.randomUUID().toString(); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_LOLIPOP) { // 选择文件返回 5.0+ Uri[] results = null; if (resultCode == RESULT_OK) { if (data == null) { if (mCameraPhotoPath != null) { results = new Uri[]{Uri.parse(mCameraPhotoPath)}; } } else { String dataString = data.getDataString(); if (dataString != null) { results = new Uri[]{Uri.parse(dataString)}; } } } mFilePathCallback.onReceiveValue(results); // 当获取要传图片的Uri,通过该方法回调通知 mFilePathCallback = null; } } @Override protected void onDestroy() { mWebView.removeAllViews(); mWebView.destroy(); super.onDestroy(); } }
可在这里下载WebView实现拍照及选择图片的demo,如果6.0以上版本demo拍照异常,看一下应用管理中拍照及存储权限是否没有打开。最好在代码中加上动态设置权限的部分。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。