录相机上NET闪烁是NET网络什么意思思

最近在开发过程中遇到一个问题,主要是调用第三方的实名认证,需要拍照和录像;
办过支付宝大宝卡和腾讯的大王卡的都知道这玩意,办卡的时候就需要进行实名认证,人脸识别;
本来第三方平台(xxx流量公司)说的是直接用WebView加载这个H5界面就完事了,我心想这么简单,那不是分分钟的事,放着后面做(公司就我一个安卓,所以开发都是我说的算^_^,独立开发有的时候还是挺爽);
结果到项目快要上线的时候,只想说一句mmp,根本调不了相机,这个时候怎么搞,只有自己去实现了,才发现自己已经进了webview的深坑;
到处找资料,发现webview根本不能让h5自己调用,ios是可以的,项目经理就说是我的锅,真特么又一句mmp(关键是这个H5还特么不能改,不能提供给我调用的方法);
进入正题,首先来了解webview,这里我分享两篇大佬的博客
看完这两篇基本你已经可以随意操作webview了,
但是,当你调用相机的时候你才发现这只是入坑的开始
调用相机之后,文件回调不了,其实根本就是没有回调.这个时候你要去检查你的webview的Settings了关键代码,是否给足了权限;
WebSettings settings = webView.getSettings();
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setDomStorageEnabled(true);
settings.setDefaultTextEncodingName("UTF-8");
settings.setAllowContentAccess(true);
settings.setAllowFileAccess(true);
settings.setAllowFileAccessFromFileURLs(false);
settings.setAllowUniversalAccessFromFileURLs(false);
settings.setJavaScriptEnabled(true);
settings.setSupportZoom(true);
其中settings.setDomStorageEnabled(true);这个方法当时我没加,血崩了一次;
WebChromeClient的openFileChooser()只调用了一次
首先了解为什么这个方法只调用了一次,看这篇博客就可
看了他基本你就了解怎么回事了
怎么区分是要调用相机是需要拍照还是录视频
这个时候你就要看WebViewClient的 shouldOverrideUrlLoading()方法了,我是通过拦截url来判断url里面是拍照还是录制视频来加一个flag
这样你调用你的相机的时候就可以分别处理了
android 7.0的FileProvider的坑
看洪阳大佬的这篇博客基本就了解了
最后附上我自己的代码吧
package com.sihaiwanlian.cmccnev.feature.verify.
import android.annotation.TargetA
import android.app.A
import android.content.ClipD
import android.content.I
import android.net.U
import android.os.B
import android.os.B
import android.os.E
import android.os.SystemC
import android.provider.MediaS
import android.support.annotation.RequiresA
import android.support.v4.content.FileP
import android.support.v7.app.AppCompatA
import android.text.TextU
import android.util.L
import android.view.KeyE
import android.webkit.ValueC
import android.webkit.WebChromeC
import android.webkit.WebS
import android.webkit.WebV
import android.webkit.WebViewC
import android.widget.B
import android.widget.ImageV
import android.widget.TextV
import com.orhanobut.logger.L
import com.sihaiwanlian.cmccnev.R;
import com.sihaiwanlian.cmccnev.utils.PhotoU
import java.io.F
import butterknife.BindV
import butterknife.ButterK
import butterknife.OnC
public class Certifica extends AppCompatActivity {
private final static String TAG = "villa";
@BindView(R.id.titleBar_iv_back)
ImageView mTitleBarIvB
@BindView(R.id.titleBar_btn_back)
Button mTitleBarBtnB
@BindView(R.id.titleBar_centerTV)
TextView mTitleBarCenterTV;
private WebView webV
private ValueCallback&Uri& mUploadM
private ValueCallback&Uri[]& mUploadCallbackAboveL;
private final static int PHOTO_REQUEST = 100;
private final static int VIDEO_REQUEST = 120;
private final static String url = "your_url";
private boolean videoFlag = false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_certifica);
ButterKnife.bind(this);
initToolBar();
initWebView();
private void initToolBar() {
mTitleBarCenterTV.setText("实名认证");
private void initWebView() {
webView = (WebView) this.findViewById(R.id.certifi_webview);
initWebViewSetting();
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void initWebViewSetting() {
WebSettings settings = webView.getSettings();
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setDomStorageEnabled(true);
settings.setDefaultTextEncodingName("UTF-8");
settings.setAllowContentAccess(true);
settings.setAllowFileAccess(true);
settings.setAllowFileAccessFromFileURLs(false);
settings.setAllowUniversalAccessFromFileURLs(false);
settings.setJavaScriptEnabled(true);
settings.setSupportZoom(true);
webView.setWebViewClient(new MyWebViewClient());
webView.setWebChromeClient(new MyChromeWebClient());
webView.loadUrl(url);
@OnClick(R.id.titleBar_btn_back)
public void onViewClicked() {
if (webView.canGoBack()) {
webView.goBack();
private class MyWebViewClient extends WebViewClient {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Logger.e(url);
if (!TextUtils.isEmpty(url)) {
videoFlag = url.contains("vedio");
if (url.trim().startsWith("tel")) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
String port = url.substring(url.lastIndexOf(":") + 1, url.lastIndexOf("/"));
if (port.equals("808")) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
view.loadUrl(url);
return true;
private File fileUri = new File(Environment.getExternalStorageDirectory().getPath() + "/" + SystemClock.currentThreadTimeMillis() + ".jpg");
private Uri imageU
public class MyChromeWebClient extends WebChromeClient {
public void openFileChooser(ValueCallback&Uri& uploadMsg) {
Log.d(TAG, "openFileChoose(ValueCallback&Uri& uploadMsg)");
mUploadMessage = uploadM
if (videoFlag) {
recordVideo();
takePhoto();
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
Log.d(TAG, "openFileChoose( ValueCallback uploadMsg, String acceptType )");
mUploadMessage = uploadM
if (videoFlag) {
recordVideo();
takePhoto();
public void openFileChooser(ValueCallback&Uri& uploadMsg, String acceptType, String capture) {
Log.d(TAG, "openFileChoose(ValueCallback&Uri& uploadMsg, String acceptType, String capture)");
mUploadMessage = uploadM
if (videoFlag) {
recordVideo();
takePhoto();
public boolean onShowFileChooser(WebView webView, ValueCallback&Uri[]& filePathCallback, FileChooserParams fileChooserParams) {
Log.d(TAG, "onShowFileChooser(ValueCallback&Uri& uploadMsg, String acceptType, String capture)");
mUploadCallbackAboveL = filePathC
if (videoFlag) {
recordVideo();
takePhoto();
return true;
private void takePhoto() {
imageUri = Uri.fromFile(fileUri);
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.N) {
imageUri = FileProvider.getUriForFile(Certifica.this, getPackageName() + ".fileprovider", fileUri);
PhotoUtils.takePicture(Certifica.this, imageUri, PHOTO_REQUEST);
private void recordVideo() {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
startActivityForResult(intent, VIDEO_REQUEST);
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
return super.onKeyDown(keyCode, event);
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PHOTO_REQUEST) {
if (null == mUploadMessage && null == mUploadCallbackAboveL) return;
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
if (mUploadCallbackAboveL != null) {
onActivityResultAboveL(requestCode, resultCode, data);
} else if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else if (requestCode == VIDEO_REQUEST) {
if (null == mUploadMessage && null == mUploadCallbackAboveL) return;
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
if (mUploadCallbackAboveL != null) {
if (resultCode == RESULT_OK) {
mUploadCallbackAboveL.onReceiveValue(new Uri[]{result});
mUploadCallbackAboveL = null;
mUploadCallbackAboveL.onReceiveValue(new Uri[]{});
mUploadCallbackAboveL = null;
} else if (mUploadMessage != null) {
if (resultCode == RESULT_OK) {
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
mUploadMessage.onReceiveValue(Uri.EMPTY);
mUploadMessage = null;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {
if (requestCode != PHOTO_REQUEST || mUploadCallbackAboveL == null) {
Uri[] results = null;
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
results = new Uri[]{imageUri};
String dataString = data.getDataString();
ClipData clipData = data.getClipData();
if (clipData != null) {
results = new Uri[clipData.getItemCount()];
for (int i = 0; i & clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
results[i] = item.getUri();
if (dataString != null)
results = new Uri[]{Uri.parse(dataString)};
mUploadCallbackAboveL.onReceiveValue(results);
mUploadCallbackAboveL = null;
protected void onDestroy() {
super.onDestroy();
if (webView != null) {
webView.setWebViewClient(null);
webView.setWebChromeClient(null);
webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
webView.clearHistory();
webView.destroy();
webView = null;
这里面有个photoUtils,已经封装好了各种调用,简单好用
public class PhotoUtils {
private static final String TAG = "PhotoUtils";
* activity
当前activity
* imageUri
拍照后照片存储路径
* requestCode 调用系统相机请求码
public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
Intent intentCamera = new Intent();
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.N) {
intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
if (activity!=null){
activity.startActivityForResult(intentCamera, requestCode);
* activity
当前activity
* requestCode 打开相册的请求码
public static void openPic(Activity activity, int requestCode) {
Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
photoPickerIntent.setType("image/*");
activity.startActivityForResult(photoPickerIntent, requestCode);
* activity
当前activity
剪裁原图的Uri
剪裁后的图片的Uri
X方向的比例
Y方向的比例
剪裁图片的宽度
剪裁图片高度
* requestCode 剪裁图片的请求码
public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
Intent intent = new Intent("com.android.camera.action.CROP");
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.N) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(orgUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
intent.putExtra("outputX", width);
intent.putExtra("outputY", height);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true);
activity.startActivityForResult(intent, requestCode);
* 读取uri所在的图片
图片对应的Uri
* mContext 上下文对象
* 获取图像的Bitmap
public static Bitmap getBitmapFromUri(Uri uri, Context mContext) {
Bitmap bitmapFormUri = getBitmapFormUri(mContext, uri);
return bitmapFormU
} catch (Exception e) {
e.printStackTrace();
return null;
* 通过uri获取图片并进行压缩
public static Bitmap getBitmapFormUri(Context ac, Uri uri) throws FileNotFoundException, IOException {
InputStream input = ac.getContentResolver().openInputStream(uri);
BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
onlyBoundsOptions.inJustDecodeBounds = true;
onlyBoundsOptions.inDither = true;
onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
input.close();
int originalWidth = onlyBoundsOptions.outW
int originalHeight = onlyBoundsOptions.outH
if ((originalWidth == -1) || (originalHeight == -1)){
return null;
float hh = 800f;
float ww = 480f;
int be = 1;
if (originalWidth & originalHeight && originalWidth & ww) {
be = (int) (originalWidth / ww);
} else if (originalWidth & originalHeight && originalHeight & hh) {
be = (int) (originalHeight / hh);
if (be &= 0){
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize =
bitmapOptions.inDither = true;
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
input = ac.getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
input.close();
return compressImage(bitmap);
* 质量压缩方法
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
while (baos.toByteArray().length / 1024 & 100) {
baos.reset();
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
options -= 10;
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
* context 上下文对象
当前相册照片的Uri
* 解析后的Uri对应的String
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT &= Build.VERSION_CODES.KITKAT;
String pathHead = "file:///";
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return pathHead + Environment.getExternalStorageDirectory() + "/" + split[1];
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return pathHead + getDataColumn(context, contentUri, null, null);
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return pathHead + getDataColumn(context, contentUri, selection, selectionArgs);
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return pathHead + getDataColumn(context, uri, null, null);
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return pathHead + uri.getPath();
return null;
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
The context.
The Uri to query.
* selection
(Optional) Filter used in the query.
* selectionArgs (Optional) Selection arguments used in the query.
* The value of the _data column, which is typically a file path.
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
} finally {
if (cursor != null){
cursor.close();
return null;
* uri The Uri to check.
* Whether the Uri authority is ExternalStorageProvider.
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
* uri The Uri to check.
* Whether the Uri authority is DownloadsProvider.
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
* uri The Uri to check.
* Whether the Uri authority is MediaProvider.
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
Android WebView中打开相机拍照和选择相册
一般在项目中与js交互,可能会遇到上传文件图片等操作,避免不了一些坑,下面简单说一下,Android 在不同版本中webView调用相机,选择相册的方法是不一样的,3.0以下的调用 public vo...
H5 调用android原生相机代码分析
H5 页面在webView中调用原声相机:
H5 端的代码:如下:
//文本输入框;
android端的代码:
webView.setWebChromeClient(new
[Android] WebView中拍照或从相册上传图片
WebView 上传图片, 想必很多人都碰到过这样的场景. 而且 WebView 在4.4前后的区别非常大, 比如对URL跳转的格式, 对JS的注入声明等等, 4.4以后的WebView 已经是chr...
H5通过input直接调用android摄像头
public class ControlFragment extends BaseFragment {
private static ProgressWebView webV
Android WebView 选择图片并上传(调用相机拍照/相册/选择文件)
这个功能其实我才刚接触。不熟...在这个给大家提供的都是经过本人验证之后的一些案例。可以在项目中跑的。
最近项目嵌入混合开发,都是使用WebView来跳转,页面展示。有用到这个图片上传的功能。...
【相机】(2)——WebView中打开相机、文件选择器的问题和解决方法
上一篇[Intent调相机的2种方式以及那些你知道的和不知道的坑]中完成了对 Intent 调起系统相机、结果处理以及一些问题的应对。其实上篇文章还是因为今天的主题 **WebView中调用系统相机*...
Android Webview实现图片、文件上传及启动相机功能
直接上代码,体会Webview强大的功能。
webView.setWebChromeClient(webChromeClient);
private String mCameraFilePath = ...
关于android webview调用相册和相机
android webView 调用系统相册和相机
这里我只展示选择图库的代码,调用相册和相机的完整代码到这里下载点击打开链接
private ValueCallback mFilePathCall...
没有更多推荐了,&>&web电子版通讯录
web电子版通讯录
上传大小:555KB
基于asp.net的电子通讯录。使用access数据库。实现新建联系人。对联系人进行分组的操作
综合评分:0
{%username%}回复{%com_username%}{%time%}\
/*点击出现回复框*/
$(".respond_btn").on("click", function (e) {
$(this).parents(".rightLi").children(".respond_box").show();
e.stopPropagation();
$(".cancel_res").on("click", function (e) {
$(this).parents(".res_b").siblings(".res_area").val("");
$(this).parents(".respond_box").hide();
e.stopPropagation();
/*删除评论*/
$(".del_comment_c").on("click", function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_invalid/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parents(".conLi").remove();
alert(data.msg);
$(".res_btn").click(function (e) {
var parentWrap = $(this).parents(".respond_box"),
q = parentWrap.find(".form1").serializeArray(),
resStr = $.trim(parentWrap.find(".res_area_r").val());
console.log(q);
//var res_area_r = $.trim($(".res_area_r").val());
if (resStr == '') {
$(".res_text").css({color: "red"});
$.post("/index.php/comment/do_comment_reply/", q,
function (data) {
if (data.succ == 1) {
var $target,
evt = e || window.
$target = $(evt.target || evt.srcElement);
var $dd = $target.parents('dd');
var $wrapReply = $dd.find('.respond_box');
console.log($wrapReply);
//var mess = $(".res_area_r").val();
var mess = resS
var str = str.replace(/{%header%}/g, data.header)
.replace(/{%href%}/g, 'http://' + window.location.host + '/user/' + data.username)
.replace(/{%username%}/g, data.username)
.replace(/{%com_username%}/g, data.com_username)
.replace(/{%time%}/g, data.time)
.replace(/{%id%}/g, data.id)
.replace(/{%mess%}/g, mess);
$dd.after(str);
$(".respond_box").hide();
$(".res_area_r").val("");
$(".res_area").val("");
$wrapReply.hide();
alert(data.msg);
}, "json");
/*删除回复*/
$(".rightLi").on("click", '.del_comment_r', function (e) {
var id = $(e.target).attr("id");
$.getJSON('/index.php/comment/do_comment_del/' + id,
function (data) {
if (data.succ == 1) {
$(e.target).parent().parent().parent().parent().parent().remove();
$(e.target).parents('.res_list').remove()
alert(data.msg);
//填充回复
function KeyP(v) {
var parentWrap = $(v).parents(".respond_box");
parentWrap.find(".res_area_r").val($.trim(parentWrap.find(".res_area").val()));
评论共有0条
综合评分:
积分/C币:3
综合评分:
积分/C币:5
VIP会员动态
CSDN下载频道资源及相关规则调整公告V11.10
下载频道用户反馈专区
下载频道积分规则调整V1710.18
spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip
资源所需积分/C币
当前拥有积分
当前拥有C币
输入下载码
为了良好体验,不建议使用迅雷下载
web电子版通讯录
会员到期时间:
剩余下载个数:
剩余积分:0
为了良好体验,不建议使用迅雷下载
积分不足!
资源所需积分/C币
当前拥有积分
您可以选择
程序员的必选
绿色安全资源
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
为了良好体验,不建议使用迅雷下载
资源所需积分/C币
当前拥有积分
当前拥有C币
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
无法举报自己的资源
你当前的下载分为234。
你还不是VIP会员
开通VIP会员权限,免积分下载
你下载资源过于频繁,请输入验证码
您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:!
若举报审核通过,可返还被扣除的积分
被举报人:
请选择类型
资源无法下载 ( 404页面、下载失败、资源本身问题)
资源无法使用 (文件损坏、内容缺失、题文不符)
侵犯版权资源 (侵犯公司或个人版权)
虚假资源 (恶意欺诈、刷分资源)
含色情、危害国家安全内容
含广告、木马病毒资源
*投诉人姓名:
*投诉人联系方式:
*版权证明:
*详细原因:
web电子版通讯录

我要回帖

更多关于 NET是什么意思? 的文章

 

随机推荐