【Android WebView】实现选择本地图片拍照功能

相关文章

【Android WebView】仿微信加载H5页面进度条实现

【Android WebView】Android和JS互调,BridgeWebView的使用


前言

Android中通过WebViewH5页面进行交互,有时候会有其他需求比如H5页面需要从手机本地文件中选择图片。本篇以BridgeWebView介绍功能的实现。

1、自定义ProgressWebView


class ProgressWebView(context: Context, attr: AttributeSet) : BridgeWebView(context, attr) {

 	//xml布局中使用,所以用两个构造参数的构造函数
    private var progressBar: ProgressBar? = null
    //页面加载完成标志
    private var hasComplate: Boolean = false
    //选择图片回调Activity监听
    private var listener: OnImageSelectorListener? = null

	//初始化
    init {
        //设置ProgressBar是横向
        progressBar = ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal)

        //设置进度条属性
        progressBar!!.progressDrawable = context.resources.getDrawable(R.drawable.webview_hori_progress)

        //设置ProgressBar的布局参数
        val layoutParams = FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, 6, 0)

         //绑定参数
        progressBar!!.layoutParams = layoutParams

         //将ProgressBar添加到WebView上 默认头部
        addView(progressBar)

        //设置WebView辅助类WebChromeClient,获取实时加载进度
        webChromeClient = object : WebChromeClient() {
		   //进度改变监听
            override fun onProgressChanged(view: WebView?, newProgress: Int) {
                super.onProgressChanged(view, newProgress)
				//页面加载完成,进度条隐藏,设置完成标志
                if (progress == 100) {
                    hasComplate = true
                    progressBar!!.visibility = View.GONE
                } else {
                    if (!hasComplate) {
                        progressBar!!.visibility = View.VISIBLE
                        //设置进度
                        progressBar!!.progress = progress
                    }
                     //防止页面重定向,进度条重新刷新
                    hasComplate = false
                }
            }

               //Android 4.1+ 
            fun openFileChooser(valueCallback: android.webkit.ValueCallback<Uri>, acceptType: String, capture: String) {
                 listener!!.chooseImageFromSys4(valueCallback)
            }

		    //Android 5.0+
            override fun onShowFileChooser(webView: WebView?, filePathCallback: android.webkit.ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean {

                listener!!.chooseImageFromSys(filePathCallback)
                return true
            }
        }
    }

    interface OnImageSelectorListener {
        //Android 5.0+
        fun chooseImageFromSys(filePathCallback: ValueCallback<Array<Uri>>?)

        //Android 4.1+
        fun chooseImageFromSys4(valueCallback: android.webkit.ValueCallback<Uri>)
    }

    fun setOnSelectListener(listener: OnImageSelectorListener) {
        this.listener = listener
    }
}

之前有篇博客介绍了仿微信加载H5进度条的实现,以此为基础,之前在加载csdn网站时,出现了一个现象,监听页面加载progress时,已经到了100后,进度又会重新加载一次,具体产生原因不知,猜测是加载页面后网址进行了重定向。所以这里做了一个小优化,加载完成后设置标志位让进度条不再显示。

openFileChooseronShowFileChooser这两个方式是WebView辅助类WebChromeClient用来监听Javascriptinput type='file'事件,事件用来调用系统文件。当监听到后回调到Activity进行选择图片操作。

ValueCallback,这个类的作用是,将我们选择的图片回调给Javascript。而回调的类型是图片的UriValueCallback提供了一个方法onReceiveValue


2、XML声明自定义的View


<com.ho.yyyyy.csdn.ProgressWebView
   android:id="@+id/progressWebView"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />
   

3、设置WebView,选择图片回调

3-1、配置WebView

这里是WebView几个重要必要的配置选项,其他配置根据自己情况而定


val setting = progressWebView!!.settings
//允许读取文件
setting!!.allowFileAccess = true
//不禁用js代码
setting.javaScriptEnabled = true
//本地缓存,无从网络拉取
setting.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
//设置代理人名称,表示是app发起的
setting.userAgentString = setting.userAgentString + "penglaiapp"
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
      setting.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}

//注册Android和JS通信回调
progressWebView!!.setDefaultHandler(MyHadlerCallBack())

//创建内部类,自定义类继承DefaultHandler
private inner class MyHadlerCallBack : DefaultHandler() {
        override fun handler(data: String?, function: CallBackFunction?) {
            if (function != null) {
                Toast.makeText(this@IssueInvoiceActivity, "自定义类继承DefaultHandler:" + data!!, Toast.LENGTH_SHORT).show()
            }
        }
    }


<!-------------------分割线-------------------->
		<!--这里是Android和JS回调代码-->
	

//设置JS需要的参数,具体的值这里不显示了
val params = HashMap<String, Any>()
params["token"] = "token"
params["money"] = invoiceMoney
params["invoiceflag"] = invoiceType

//"invoice"字段 JS也要注册,名字随意,Android传参给JS
progressWebView.callHandler("invoice", Gson().toJson(params)) {

}

//"goBack"字段 JS传递给Android,执行相应方法
progressWebView!!.registerHandler("goBack") { _, _ ->
        finish()
}
		
//加载H5页面-
progressWebView!!.loadUrl(invoiceUrl)

3-2、WebView回调Activity

WebView回调选择图片操作在Activity里进行。


progressWebView!!.setOnSelectListener(object : ProgressWebView.OnImageSelectorListener {
  	   //4.0以上系统
       override fun chooseImageFromSys4(valueCallback: ValueCallback<Uri>) {
           uploadMessage = valueCallback
           chooseImageFromSys()
       }

       //5.0以上系统
       override fun chooseImageFromSys(filePathCallback: ValueCallback<Array<Uri>>?) {
           uploadMessageAboveL = filePathCallback
           chooseImageFromSys()
       }
 })
 

这里是自定义的弹窗选择拍照或者相册方式。


private fun chooseImageFromSys() {
    SelectorDialog.Builder(this)
        .addItem(1, resources.getString(R.string.camera))
        .addItem(2, resources.getString(R.string.gallery))
        .setCancelable(false).setOnSelectedListener { id, name ->
            when (id) {
             	//选择相机拍照 这里默认已经获取权限
                1 -> 
                  onPickFromCameraClicked()
            	 //相册选择
                2 ->
                     onPickFromGaleryClicked()
                //ValueCallback对象置空,否则无法再次获取JS事件     
                -1 -> {
		 		//取消按钮   
                    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                         uploadMessageAboveL!!.onReceiveValue(null)
                         uploadMessageAboveL = null
                     } else {
                         uploadMessage!!.onReceiveValue(null)
                         uploadMessage = null
                        }
                     }
}
   }.build().show()
}

3-3、相册选择与相机拍照

3-3-1.相册选择图片

//相册选择RequestCode
private val PICK_IMAGE_FROM_GALERY = 0x0002

private fun onPickFromGaleryClicked() {
    val intent = Intent(Intent.ACTION_PICK)
    intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
    startActivityForResult(intent, PICK_IMAGE_FROM_GALERY)
}

3-3-2、调用相机拍照


private var imageUri: Uri? = null		  	//拍照Uri对象
private var tempCameraFile: File? = null  	//拍照获取File文件对象
private val PICK_IMAGE_FROM_CAMERA = 0x0001	//拍照RequestCode

private fun openCamera() {
      tempCameraFile = File(externalCacheDir, getString(R.string.cache__image, System.currentTimeMillis()))
   //7.0以上 FileProvider 获取Uri
      imageUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
           //通过FileProvider创建一个content类型的Uri
           FileProvider.getUriForFile(this, "com.xxx.yyyy.fileProvider", tempCameraFile)
       } else {
           Uri.fromFile(tempCameraFile)
       }
       val intent = Intent()
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
           //添加这一句表示对目标应用临时授权该Uri所代表的文件
           intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
       }
       //设置Action为拍照
       intent.action = MediaStore.ACTION_IMAGE_CAPTURE
       //将拍取的照片保存到指定URI
       intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
       startActivityForResult(intent, PICK_IMAGE_FROM_CAMERA)
}

3-4、选择图片回调


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
		//选择图片取消时,要将ValueCallback对象置空,否则无法再次获取JS事件
        if (resultCode == RESULT_CANCELED) {
	        //系统版本5.0+
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                uploadMessageAboveL!!.onReceiveValue(null)
                uploadMessageAboveL = null
            } else {
                uploadMessage!!.onReceiveValue(null)
                uploadMessage = null
            }
        }

        when (requestCode) {
	        //相册选择
            PICK_IMAGE_FROM_GALERY -> {
                tempCropFile = File(externalCacheDir,
                        "pl_cover" + System.currentTimeMillis() + ".jpg")
				    //这里不考虑4.4版本以下
                    handleImageOnKitKat(data)
               
            }
			//相机拍照
            PICK_IMAGE_FROM_CAMERA-> {
                if (tempCameraFile!!.exists()) {
                    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                      	uploadMessageAboveL!!.onReceiveValue(arrayOf(Uri.fromFile(tempCameraFile)))
                        uploadMessageAboveL = null
                    } else {
	               		uploadMessage!!.onReceiveValue(Uri.fromFile(tempCameraFile))
                        uploadMessage = null
                    }
                }
            }
        }
    }
    

//相册选择 获取uri
private fun handleImageOnKitKat(data: Intent?) {
      imagePath = null
      if (data != null) {
          imageUri = data.data
          if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
             uploadMessageAboveL!!.onReceiveValue(arrayOf(imageUri))
              uploadMessageAboveL = null
          } else {
              uploadMessage!!.onReceiveValue(imageUri)
              uploadMessage = null
          }
    }
}

效果图

这里写图片描述


总结

本篇介绍了WebView中选择图片功能实现。目前已经测试可用,大家也可以做参考。也有功能需要完善比如图片剪裁压缩等功能等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值