若是以为掘金上看图片放大看不清楚,能够跳到另外的同步发布的连接看,放大图片下部有个能够查看原图功能,很清楚:项目需求讨论 - WebView下拍照及图片选择功能html
如今不少app里面,都会有这么一个需求,就是上传图片的按钮,固然按了这个按钮以后,就会出现二种选择: 1. 直接拍照,2. 相册选择现有图片。android
由于如今的app这块功能会有二个大的状况:web
本文先讨论HyBrid的app的实现状况,下次再讨论原生,不过其实大部分实现都是类似的。bash
其实这种在WebView配合下实现这类功能的文章不少不少,可是大多数都是上传一大段代码,而后让你们本身看,千篇一概,因此本文主要是写的完整的思路。服务器
咱们知道用户会在网页上点击了某个按钮,而后调用起安卓方面的相关操做。而后实现完整的功能。app
其实网页端很简单,只须要实现一个简单的<input>
标签便可。async
整体思路是一个<input>
标签和一个<img>
标签重叠在一块儿(<input>
在上,<img>
在下,相似能够理解<img>
做为背景),当选完照片后,最后把图片赋值给<img>
标签。ide
可是在给<img>
赋值的时候我遇到过不一样的状况:ui
当在Android这边拍照或者进入图库选完照片后,把图片信息给了网页端后,<input>
标签的onchange监听到了图片选择好了,网页端直接把图片上传到服务器并传回来一个地址,显示时把地址拼接成能够找到路径的地址放在<img>
标签中就能够了。this
配合FileReader,FileReader是做为文件API的重要成员用于读取文件。能够参考: h5 实现调用系统拍照或者选择照片并预览
由于Android端访问网页大部分使用的是WebView
,因此咱们这里仍是用WebView
来讲明。
既然用户在网页上点击了<input>
,咱们确定须要WebView
能监听到,比如原生的Button
点击咱们要监听也要写一个OnclickListener
来实现监听。咱们这里使用的是WebChromeClient
。
public class ImgWebChromeClient extends WebChromeClient {
//.......
//.......
public ImgWebChromeClient(Activity activity) {
this.activity = activity;
}
}
复制代码
咱们实现咱们的类,继承WebChromeClient。而后咱们就能够把这个咱们本身定义的WebChromeClient设置给咱们的WebView。
webView.setWebChromeClient(new ImgWebChromeClient(this));
复制代码
咱们能够看到咱们在WebChromeClient在监听<input>
点击事件的时候,还要根据不一样的版原本区分,主要是以Android 5.0版原本进行大的划分。
Android 5.0及以上版本:
Android 5.0如下版本:
都是openFileChooser方法,不一样版本的里面参数不一样。
因此咱们能够看到主要是openFileChooser
和onShowFileChooser
方法。
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> valueCallback) {
***
}
// For Android >= 3.0
public void openFileChooser(ValueCallback valueCallback, String acceptType) {
***
}
//For Android >= 4.1
public void openFileChooser(ValueCallback<Uri> valueCallback,
String acceptType, String capture) {
***
}
// For Android >= 5.0
@Override
public boolean onShowFileChooser(WebView webView,
ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
***
return true;
}
复制代码
不论是什么版本,咱们看到这几个方法的参数里面都有ValueCallback
参数。
/**
* A callback interface used to provide values asynchronously.
*/
public interface ValueCallback<T> {
/**
* Invoked when the value is available.
* @param value The value.
*/
public void onReceiveValue(T value);
};
复制代码
因此咱们知道了,咱们最后是调用openFileChooser
和onShowFileChooser
方法里面的ValueCallback
参数,调用它的onReceiveValue
方法把咱们的选择的图片的Uri传入,网页端那边就会收到信息了,就知道用户到底选择了什么图片。
因此咱们最终目标就是获取选择的图片的Uri,而后给ValueCallback.onReceiveValue方法,这就是咱们整个文章的最主要的流程。
上面咱们提到了,咱们最终目标是获取用户选取的图片Uri
,而后传给ValueCallback
就能够。 因此咱们这里就要讲二大块:
Uri
。根据这二点,咱们一步步来分析。
咱们确定想到是用户点击了某个按钮后,咱们须要跳出一个弹框,而后上面有拍照和图库按钮: 好比我使用系统自带的选择框(不一样手机显示的弹框不一样):
因此咱们这里知道了这个又要细分任务:
emmm......这块我以为应该不须要花更多的时间来讲明了吧,主要就是:
而咱们要申请的权限无非就是 Camera的权限,还有读写外部存储的权限。
咱们先来看拍照:
咱们知道打开某个界面,就是startActivity(Intent);日常好比跳到拨号界面等。只要对Intent设定相应的Action便可。 具体咱们能够看谷歌的Android官方教程网页便可:
咱们能够看到有这些:
咱们能够这个目录中看到了相机,咱们具体看相机的介绍:
注:当您使用 ACTION_IMAGE_CAPTURE拍摄照片时,相机可能还会在结果 Intent 中返回缩小尺寸的照片副本(缩略图),这个副本以 Bitmap 形式保存在名为
data
的extra
字段中。
因此咱们这里跳到拍照界面也是同样,只要创建跳到相机界面的Intent便可:
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
复制代码
由于有些人须要在本身的APP中调用拍照的功能,存在本身指定的目录下面,因此须要在startActivity启动相机界面时候同时传递过去信息,告诉拍照了以后照片存的位置。
1.咱们先指定咱们的要存储的照片的路径Uri:
其实很简单,设定咱们接下去要拍的照片的完整存储路径,而后获得File
对象,再经过Uri.fromFile
方法再经过刚才咱们的File
对象来得到Uri
。
(固然若是这里你只须要打开系统相机,如下第二部分能够忽略)
2.获取全部相机的Intent集合:
由于咱们手机上面可能有不少个相机软件,因此咱们须要先找到能打开各自相机软件的Intent,咱们经过PackageManager.queryIntentActivities
的方式来进行符合拍照Action的Intent的软件,而后获得它们具体的详细信息,好比包名及对应的activity名字等,而后把相应的Intent变得更加详细便可。
3.把uri赋值给Intent:
在上面贴出的Android 官方网页上面的相机部分其实也提到过了如何设置存储位置:
因此这里咱们只须要找到相应的Intent,而后把咱们的Uri位置赋值给Intent便可:
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
复制代码
最后只须要startActivity去启动咱们这个指定了打开相机的特定Intent便可。
拍照说完了,咱们再来看在图库界面选择图片: 其实整体思路和拍照是如出一辙,无非就是指定Intent是打开了图库的Intent。
仍是在刚才的Android 官网咱们能够看到:
由于咱们是查看本地的图片,因此咱们要使用 ACTION_GET_CONTENT
,同时指定MIME
类型是图片类型,若是要进行图片多选,就再指定EXTRA_ALLOW_MULTIPLE
为true
。
同时也给出了实例代码:
这里我要提一下,咱们在设置Intent
的Action
的时候不仅是可使用ACTION_GET_CONTENT
,还可使用ACTION_PICK
。
咱们能够看到上面写着能够用来选择数据,而后返回被选中的选项。
可是在具体手机操做上有点不一样(不知道不一样的手机系统会不会结果不一样,我只测了模拟器):
ps:最坑的是用ACTION_GET_CONTEN时候多选图片要长按操做,一直觉得没成功,觉得多选图片功能没实现,后来在 Android: Intent.EXTRA_ALLOW_MULTIPLE allows only single picking 上面找到别人的答案,说须要长按
咱们能够看到能够自定义弹框,好比咱们设定固定的按钮,而后再点击特定按钮后启动咱们的上面提过的特定的Intent便可。
这里咱们讲若是只是给定咱们想要启动的多个Intent的选项,让系统帮咱们弹出弹框及相关按钮,关键字就是Intent.createChooser
方法
直接看图片便可,写的很详细了,或者你们搜相关的关键字也是有不少文章的。好比:Android createChooser方法源码简析等。
startActivity
确定不够,因此你们确定想到了使用
startActivityForResult
来启动,这样才能根据用户不一样的操做来进行相应的处理。
咱们知道须要复写onActivityResult
来处理,主要也就三个参数(int requestCode, int resultCode, Intent data)
。具体的内容图片里面也写的很清楚。
因此咱们ValueCallback实例在 WebChromeClient的方法里面拿到了,Uri也经过相机或者图库的选择下获取到了。最终调用把获取的Uri 赋值给ValueCallback.onReceiveValue()便可。
PS: 取消此次网页点击选取图片的请求,只须要调用onReceiveValue(null)便可。
emm.......你们轻喷便可。。。。