需求目的: 手机机通过webView展示H5网页,在特殊场景下,需要使用相机照相或者从相册获取照片,上传背景。
完备流程效果: 如下图
一、H5界面样例代码
使用html文件格式,文件直接打开就可以展示布局;一会在andriod webview中直接加载
- <!DOCTYPE html>
- <html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- </head>
- <div id="app">
- <h1>alllalalallalal 默认会被覆盖</h1>
- </div>
- <template id="why">
- <div>
- <h2>{{message}}</h2>
- <h2>{{counter}}</h2>
- <button @click="increment">+1</button>
- <button @click="decrement">-1</button>
- <h1 style="text-align: center;">{{ title }}</h1>
- <div>
- <h2 style="text-align: center;">android选中照片H5展示</h2>
- <!--HTML5提供了<input type="file">元素来实现选取文件的功能,在WebView表现为调用onShowFileChooser-->
- <input accept="image/*" capture="camera" ref="imgFile" type="file" multiple
- @change="previewFiles">
- <div id="preview">
- <img v-for="imgSrc in imageSources" :src="imgSrc" :key="imgSrc"
- style="max-width: 100px; max-height: 100px; margin: 10px;">
- </div>
- </div>
- </div>
- </template>
- <body>
- <!-- 引入 Vue 3 的 CDN 资源网络加载不了 -->
- <!-- <script src="https://unpkg.com/vue@next"></script> -->
- <!-- 引入 Vue 3 的 CDN 资源,本地引用 -->
- <script src="vue3.2.12global.js"></script>
- <script>
- Vue.createApp({
- template: '#why',
- data: function () {
- return {
- message: "功能开发中,敬请期待!",
- counter: 100,
- pictureSelectorContent: "相机选择结果:",
- imageSources: [] // 存储图片的数据URL
- }
- },
- // 在你的 Vue 组件中处理 Webview 传递的数据
- mounted() {
- // 设置全局函数,用于接收 WebView 调用
- // window.pictureSelectorResult = this.pictureSelectorResult;
- },
- methods: {
- increment() {
- this.counter++;
- console.log("点击了+1");
- },
- decrement() {
- this.counter--;
- consloe.log("点击了-1");
- },
- startPictureSelector() {
- window.android.startPictureSelector();
- },
- previewFiles() {
- const files = this.$refs.imgFile.files;
- this.imageSources = [];
- for (let i = 0; i < files.length; i++) {
- const file = files[i];
- const reader = new FileReader();
- reader.onload = (e) => {
- this.imageSources.push(e.target.result);
- };
- reader.readAsDataURL(file);
- }
- },
- },
- }).mount("#app")
- </script>
- <style>
- h1 {
- font-size: 80px;
- font-weight: bold;
- margin-bottom: 20px;
- }
- h2 {
- font-size: 20px;
- font-weight: bold;
- color: #C8EFD4;
- }
- h3 {
- font-size: 10px;
- font-weight: bold;
- color: #C8EFD4;
- }
- button1 {
- font-size: 60px;
- padding: 10px 20px;
- background-color: #007bff;
- color: #fff;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- margin-bottom: 20px;
- margin-top: 20px;
- text-align: center;
- /* 将文字水平居中显示 */
- display: flex;
- /* 将按钮设置为flex容器 */
- align-items: center;
- /* 将文字在垂直方向上居中显示 */
- }
- </style>
- </body>
- </html>
复制代码 上述代码是前端代码,使用vue3框架展示一个基础 加减demo界面(不紧张的冗余),以及 一个打开文件的按钮以及展示图片
此中HTML5提供了元素来实现选取文件的功能,当在WebView表现为调用onShowFileChooser后,回调图片uri列表一一获取并展示
二、Android打开相机以及相册的两种方式
方式一:android 原生方式
现实效果和流程示图
1.android界面逻辑代码
这边使用的是kotlin语言,使用的fragment界面展示,使用binding加载了布局,以及声明白webview组件,在webview上导入html链接,使当地H5界面展示
- class VisitorFragment : Fragment() {
- private lateinit var binding: FragmentVisitorBinding
- lateinit var mActivity: Activity
- private lateinit var mRoot: View
- companion object {
- const val TAG = "VisitorFragment"
- }
- private var mWebViewUrl: String = "file:///android_asset/vue_android_demo.html"
- var mAppName = MainApplication.instance.configuration.BASE_APP_LOGIN_IDENTITY
- var mSystemName = WebViewConstant.DEFAULT_SYSTEM_NAME
- private var mVisitorAndroidJs: VisitorAndroidJs = VisitorAndroidJs(this)
- private var mWebView: WebView? = null
- var mAndroidId: String = WebViewConstant.DEFAULT_DEVICE_SIGN
- var mApiKey: String = WebViewConstant.DEFAULT_API_KEY
- //回传H5时使用的对象
- private var mUploadCallback: ValueCallback<Array<Uri>>? = null
- //拍照传递的路径uri
- private var mImageUri: Uri? = null
- /**
- * onCreate方法是Activity生命周期的第一个回调方法
- * ,当Activity被创建时被调用。
- * 在这个方法中,你可以进行一些初始化的操作,比如设置布局、绑定控件、初始化数据等。
- *
- * @param savedInstanceState If the fragment is being re-created from
- * a previous saved state, this is the state.
- */
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = FragmentVisitorBinding.inflate(layoutInflater)
- mRoot = binding.root
- //记录
- val viewModel = ViewModelProvider(requireActivity())[DashboardViewModel::class.java]
- viewModel.setFragment(this)
- LogUtils.d(TAG, "onCreate")
- }
- /**
- * onCreateView方法是Fragment生命周期的回调方法,
- * 当Fragment创建并绘制其用户界面时被调用。
- * 在这个方法中,你可以通过返回一个View对象来定义Fragment的用户界面。
- * 它常用于加载布局文件、查找和初始化控件等操作。
- *
- * @return
- */
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- LogUtils.d(TAG, "onCreateView")
- initView(mRoot, layoutInflater, null)
- return mRoot
- }
- fun initView(parent: View?, inflater: LayoutInflater?, container: ViewGroup?) {
- //设置当前fragment
- mAndroidId = DeviceUtils.getUniqueId(mActivity)
- initWebView()
- mWebView?.loadUrl(mWebViewUrl)
- //弹出展示链接
- showToast("${getString(R.string.current_develop_environment)}$mWebViewUrl")
- initData()
- }
- override fun onAttach(context: Context) {
- super.onAttach(context)
- mActivity = context as Activity
- }
- /**
- * @param msg 内容
- */
- fun showToast(msg: String?) {
- val activity: Activity? = activity
- activity?.runOnUiThread {
- Toast.makeText(
- activity,
- msg,
- Toast.LENGTH_SHORT
- ).show()
- }
- }
- private fun initData() {
- }
- override fun onResume() {
- super.onResume()
- LogUtils.d(TAG, "onResume")
- }
- @SuppressLint("SetJavaScriptEnabled")
- private fun initWebView() {
- LogUtils.d(TAG, "initWebView")
- mWebView = binding.mainWebView
- mWebView?.requestFocus()
- mWebView?.isHorizontalScrollBarEnabled = false
- mWebView?.isVerticalScrollBarEnabled = false
- val setting = mWebView?.settings
- setting?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW;
- setting?.javaScriptEnabled = true
- //用于开启或禁用其 DOM(文档对象模型)存储功能,浏览器缓存这些数据
- setting?.domStorageEnabled = true
- //允许访问文件,默认允许
- setting?.allowFileAccess = true
- //设置不,会引起webView重新不急,默认NARROW_COLUMNS
- setting?.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS
- //自动缩放
- setting?.setSupportZoom(true)
- setting?.builtInZoomControls = true
- //自适应屏幕
- setting?.useWideViewPort = true
- setting?.loadWithOverviewMode = true
- //支持多窗口
- setting?.setSupportMultipleWindows(true)
- setting?.setAppCacheEnabled(true)
- setting?.domStorageEnabled = true
- //定位
- setting?.setGeolocationEnabled(true)
- //优先使用缓存数据,在缓存数据不存在的情况下才去获取网络数据
- setting?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
- setting?.savePassword = false
- //设置js接口
- mVisitorAndroidJs.let { mWebView?.addJavascriptInterface(it, "android") }
- //页面不跳转浏览器
- mWebView?.webViewClient = object : WebViewClient() {
- override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
- LogUtils.d(TAG, "url: $url")
- view.loadUrl(url)
- return true
- }
- override fun shouldInterceptRequest(
- view: WebView,
- request: WebResourceRequest
- ): WebResourceResponse? {
- var uri = request.url
- var path = uri.path
- LogUtils.d(TAG, "uri: $uri, path: $path")
- return super.shouldInterceptRequest(view, request)
- }
- }
- //webView官方打开文件选取方法onShowFileChooser,把网页回传文件
- mWebView?.webChromeClient = object : WebChromeClient() {
- //API >=21(android 5.0.1)回调此方法
- override fun onShowFileChooser(
- webView: WebView?,
- filePathCallback: ValueCallback<Array<Uri>>?,
- fileChooserParams: FileChooserParams?
- ): Boolean {
- mUploadCallback = filePathCallback
- //使用拍照或者打开文件
- mImageUri = ChoosePhotoFile.takePhoto(mActivity)
- //设置false会IllegalStateException: Duplicate showFileChooser result
- return true
- }
- }
- }
- fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) {
- LogUtils.d(
- TAG,
- "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode"
- )
- // 扫描二维码/条码回传
- if (requestCode == ScanCodeUtils.REQUEST_CODE_SCAN && resultCode == Activity.RESULT_OK) {
- LogUtils.d(TAG, "onActivityResultResponse ${intent?.extras}")
- if (intent == null) {
- //弹出展示链接
- showToast("扫描结果为空")
- return
- }
- //传递给js,格式是"scanCodeResult('${data.extras}')",其中单引号很重要,可能导致js script error
- //codedContent是组件中定义的参数名
- setEvaluateJavascript("scanCodeResult('${intent.getStringExtra("codedContent")}')")
- } else if (requestCode == ChoosePhotoFile.REQUEST_CODE) {
- //拍照,界面跳回后,结果文件的使用
- ChoosePhotoFile.takeActivityResult(requestCode, intent, mUploadCallback, mImageUri)
- }
- }
- @Override
- override fun onDestroy() {
- //防止更新dialog内存泄漏
- super.onDestroy()
- }
- /**
- * 登录成功后跳转
- */
- open fun loginSuccessJump() {
- }
- /**
- * 给网页传值
- * 传递给js,格式是"scanCodeResult('${data.extras}')"
- * 其中单引号很重要,可能导致js script error
- */
- private fun setEvaluateJavascript(jspMethodAndValue: String) {
- LogUtils.d(
- TAG,
- "setEvaluateJavascript mWebView ${mWebView}, jspMethodAndValue $jspMethodAndValue"
- )
- mWebView?.evaluateJavascript(jspMethodAndValue, ValueCallback<String>() {
- LogUtils.d(TAG, "给网页传值为: $jspMethodAndValue")
- })
- }
- }
复制代码 android layout布局
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <WebView
- android:id="@+id/main_web_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
复制代码 2.获取照片的主要思路是两个方法:
- webView官方打开文件选取方法onShowFileChooser,把网页回传文件
- //webView官方打开文件选取方法onShowFileChooser,把网页回传文件
- mWebView?.webChromeClient = object : WebChromeClient() {
- //API >=21(android 5.0.1)回调此方法
- override fun onShowFileChooser(
- webView: WebView?,
- filePathCallback: ValueCallback<Array<Uri>>?,
- fileChooserParams: FileChooserParams?
- ): Boolean {
- mUploadCallback = filePathCallback
- //使用拍照或者打开文件
- mImageUri = ChoosePhotoFile.takePhoto(mActivity)
- //设置false会IllegalStateException: Duplicate showFileChooser result
- return true
- }
- }
复制代码
- 照相或者相册选中后界面跳回后,使用ValueCallback<Array>回传
- fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) {
- LogUtils.d(
- TAG,
- "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode"
- )
- if (requestCode == ChoosePhotoFile.REQUEST_CODE) {
- //拍照或者相册选中后界面跳回后,结果文件的使用
- ChoosePhotoFile.takeActivityResult(requestCode, intent, mUploadCallback, mImageUri)
- }
- }
复制代码
- 以上onActivityResultResponse方法需要在actvity onActivityResult方法中使用
(由于我这里是activity嵌套fragment的,如果直接在activity使用webview就不需我这太贫苦)
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
- LogUtils.d(
- TAG,
- "onActivityResult requestCode11 $requestCode, resultCode:$resultCode"
- )
- //设置当前fragment
- val fragment = mDashboardViewModel.fragment.value
- Log.d(TAG, "fragment: $fragment")
- Log.d(TAG, "fragment.isResumed: ${fragment?.isResumed}")
- //界面返回时VisitorFragment还没有Resumed
- if (fragment is VisitorFragment) {
- val visitorFragment: VisitorFragment = fragment
- visitorFragment.onActivityResultResponse(requestCode, resultCode, data)
- }
- }
复制代码 3.打开相机和相册的工具类
- object ChoosePhotoFile {
- private const val TAG = "ChoosePhotoFile"
- const val REQUEST_CODE: Int = 12345
- fun takePhoto(activity: Activity): Uri {
- //相机可以访问的公共位置才能存储,获取时需要读取文件权限
- val file: String =
- Environment.getExternalStorageDirectory()
- .toString() + File.separator + Environment.DIRECTORY_PICTURES + File.separator
- val fileName = "Image_${SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())}.jpg"
- val realFile = File(file, fileName)
- val imageUri = Uri.fromFile(realFile)
- LogUtils.d(TAG, "realFile:$realFile, imageUri: $imageUri")
- // 拍照后获取图片需要文件权限,界面跳转直接拿文件不需要权限
- //检查申请读文件权限
- CheckPermissionUtils.requestPermissions(
- activity,
- arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
- )
- //调起相机,拍一张照片
- val captureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
- captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
- //调起相册,取一张照片
- val photoIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
- //选择方式,拍照或者相册
- val chooserIntent = Intent.createChooser(photoIntent, "Image Chooser")
- chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf<Parcelable>(captureIntent))
- activity.startActivityForResult(chooserIntent, REQUEST_CODE)
- return imageUri
- }
- /**
- * H5针对从拍照或者相册中选中的图片做处理
- * @param imageUri 拍照返回的数据,
- */
- fun takeActivityResult(
- requestCode: Int,
- intent: Intent?,
- filePathCallback: ValueCallback<Array<Uri>>?,
- imageUri: Uri?
- ) {
- if (requestCode == REQUEST_CODE) {
- //从相册获取,返回的intent
- if (intent != null && intent.data != null) {
- var uri: Uri = intent.data as Uri
- LogUtils.d(TAG, "file uri: $uri")
- filePathCallback?.onReceiveValue(arrayOf<Uri>(uri))
- } else {
- //从拍照中获取图片,已经返回的imageUri
- LogUtils.d(TAG, "take photo imageUri: $imageUri")
- if (imageUri != null) {
- filePathCallback?.onReceiveValue(arrayOf<Uri>(imageUri))
- } else {
- filePathCallback?.onReceiveValue(null)
- }
- }
- }
- }
- }
复制代码 方式二:使用android 组件库是实现-朋侪圈获取照片功能
现实效果和流程示图
1.获取照片的主要思路是两个方法-替换
- webView官方打开文件选取方法onShowFileChooser,把网页回传文件
- //webView官方打开文件选取方法onShowFileChooser,把网页回传文件
- mWebView?.webChromeClient = object : WebChromeClient() {
- //API >=21(android 5.0.1)回调此方法
- override fun onShowFileChooser(
- webView: WebView?,
- filePathCallback: ValueCallback<Array<Uri>>?,
- fileChooserParams: FileChooserParams?
- ): Boolean {
- mUploadCallback = filePathCallback
- //使用拍照或者打开文件
- // mImageUri = ChoosePhotoFile.takePhoto(mActivity)
- //模拟微信朋友圈获取照片模式
- LogUtils.d(TAG,"onShowFileChooser")
- PictureSelectorUtils.startPictureSelector(mActivity)
- //设置false会IllegalStateException: Duplicate showFileChooser result
- return true
- }
- }
复制代码
- 照相或者相册选中后界面跳回后,使用ValueCallback<Array>回传
- fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) {
- LogUtils.d(
- TAG,
- "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode"
- )
- if (requestCode == PictureSelectorUtils.REQUEST_PICTURE_SELECTOR) {
- LogUtils.d(TAG, "onActivityResultResponse REQUEST_PICTURE_SELECTOR")
- PictureSelectorUtils.takeActivityResult(requestCode, intent, mUploadCallback)
- }
- }
复制代码 2.打开相机和相册的工具类
- object PictureSelectorUtils {
- const val REQUEST_PICTURE_SELECTOR = 10012
- const val TAG = "PictureSelectorUtils"
- fun startPictureSelector(activity: Activity) {
- LogUtils.d(TAG, "startPictureSelector")
- // 拍照后获取图片需要文件权限,界面跳转直接拿文件不需要权限
- //检查申请读文件权限
- // CheckPermissionUtils.requestPermissions(
- // activity,
- // arrayOf(
- // Manifest.permission.CAMERA,
- // Manifest.permission.READ_EXTERNAL_STORAGE,
- // Manifest.permission.WRITE_EXTERNAL_STORAGE
- // )
- // )
- //插件里自带了静态权限以及权限校验
- PictureSelector.create(activity).openGallery(PictureMimeType.ofImage())
- .imageEngine(GlideEngine) // Please refer to the Demo GlideEngine.java
- .isWeChatStyle(true) // 是否开启微信图片选择风格
- .selectionMode(PictureConfig.MULTIPLE).forResult(REQUEST_PICTURE_SELECTOR)
- }
- fun getPictures(data: Intent): MutableList<Uri> {
- val selectList = PictureSelector.obtainMultipleResult(data)
- LogUtils.d(TAG, "getPicture selectList: $selectList")
- // 将照片路径转换成 Uri 列表
- val imageUris: MutableList<Uri> = ArrayList()
- if (selectList.isEmpty()) {
- LogUtils.d(TAG, "getPicture selectList isEmpty")
- return imageUris
- }
- for (imagePath in selectList) {
- var path = imagePath.path
- LogUtils.d(TAG, "path: $path")
- val uri = Uri.parse(path)
- LogUtils.d(TAG, "uri: $uri")
- imageUris.add(uri)
- }
- LogUtils.d(TAG, "imageUris: ${imageUris.toString()}")
- return imageUris
- }
- /**
- * H5针对从文件钟选中的图片做处理
- */
- fun takeActivityResult(
- requestCode: Int,
- intent: Intent?,
- filePathCallback: ValueCallback<Array<Uri>>?,
- ) {
- if (requestCode == REQUEST_PICTURE_SELECTOR) {
- val selectList = PictureSelector.obtainMultipleResult(intent)
- LogUtils.d(TAG, "getPicture selectList: $selectList")
- // 将照片路径转换成 Uri 列表
- val imageUris: MutableList<Uri> = ArrayList()
- if (selectList.isEmpty()) {
- LogUtils.d(TAG, "getPicture selectList isEmpty")
- filePathCallback?.onReceiveValue(null)
- return
- }
- for (imagePath in selectList) {
- var path = imagePath.path
- LogUtils.d(TAG, "path: $path")
- val uri = Uri.parse(path)
- LogUtils.d(TAG, "uri: $uri")
- imageUris.add(uri)
- }
- LogUtils.d(TAG, "imageUris: ${imageUris.toString()}")
- filePathCallback?.onReceiveValue(imageUris.toTypedArray())
- }
- }
- }
复制代码 此中使用第三方组件库-实现类似朋侪圈获取照片的样式,需要引入一下依赖
- //照片获取类微信朋友圈
- implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
复制代码 照相后获取图片需要文件权限,界面跳转直接拿文件不需要权限,且第三方插件库里自带了静态权限以及权限哀求
3.我完备的代码——类似朋侪圈获取界面逻辑
- class VisitorFragment : Fragment() { private lateinit var binding: FragmentVisitorBinding lateinit var mActivity: Activity private lateinit var mRoot: View companion object { const val TAG = "VisitorFragment" } private var mWebViewUrl: String = "file:///android_asset/vue_android_demo.html" var mAppName = MainApplication.instance.configuration.BASE_APP_LOGIN_IDENTITY var mSystemName = WebViewConstant.DEFAULT_SYSTEM_NAME private var mVisitorAndroidJs: VisitorAndroidJs = VisitorAndroidJs(this) private var mWebView: WebView? = null var mAndroidId: String = WebViewConstant.DEFAULT_DEVICE_SIGN var mApiKey: String = WebViewConstant.DEFAULT_API_KEY //回传H5时使用的对象 private var mUploadCallback: ValueCallback<Array<Uri>>? = null //照相通报的路径uri private var mImageUri: Uri? = null /** * onCreate方法是Activity生命周期的第一个回调方法 * ,当Activity被创建时被调用。 * 在这个方法中,你可以举行一些初始化的操作,比如设置布局、绑定控件、初始化数据等。 * * @param savedInstanceState If the fragment is being re-created from * a previous saved state, this is the state. */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = FragmentVisitorBinding.inflate(layoutInflater) mRoot = binding.root //记录 val viewModel = ViewModelProvider(requireActivity())[DashboardViewModel::class.java] viewModel.setFragment(this) LogUtils.d(TAG, "onCreate") } /** * onCreateView方法是Fragment生命周期的回调方法, * 当Fragment创建并绘制其用户界面时被调用。 * 在这个方法中,你可以通过返回一个View对象来定义Fragment的用户界面。 * 它常用于加载布局文件、查找和初始化控件等操作。 * * @return */ override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { LogUtils.d(TAG, "onCreateView") initView(mRoot, layoutInflater, null) return mRoot } fun initView(parent: View?, inflater: LayoutInflater?, container: ViewGroup?) { //设置当前fragment mAndroidId = DeviceUtils.getUniqueId(mActivity) initWebView() mWebView?.loadUrl(mWebViewUrl) //弹出展示链接 showToast("${getString(R.string.current_develop_environment)}$mWebViewUrl") initData() } override fun onAttach(context: Context) { super.onAttach(context) mActivity = context as Activity } /** * @param msg 内容 */ fun showToast(msg: String?) { val activity: Activity? = activity activity?.runOnUiThread { Toast.makeText( activity, msg, Toast.LENGTH_SHORT ).show() } } private fun initData() { } override fun onResume() { super.onResume() LogUtils.d(TAG, "onResume") } @SuppressLint("SetJavaScriptEnabled") private fun initWebView() { LogUtils.d(TAG, "initWebView") mWebView = binding.mainWebView mWebView?.requestFocus() mWebView?.isHorizontalScrollBarEnabled = false mWebView?.isVerticalScrollBarEnabled = false val setting = mWebView?.settings setting?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW; setting?.javaScriptEnabled = true //用于开启或禁用其 DOM(文档对象模子)存储功能,浏览器缓存这些数据 setting?.domStorageEnabled = true //允许访问文件,默认允许 setting?.allowFileAccess = true //设置不,会引起webView重新不急,默认NARROW_COLUMNS setting?.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS //主动缩放 setting?.setSupportZoom(true) setting?.builtInZoomControls = true //自适应屏幕 setting?.useWideViewPort = true setting?.loadWithOverviewMode = true //支持多窗口 setting?.setSupportMultipleWindows(true) setting?.setAppCacheEnabled(true) setting?.domStorageEnabled = true //定位 setting?.setGeolocationEnabled(true) //优先使用缓存数据,在缓存数据不存在的情况下才去获取网络数据 setting?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK setting?.savePassword = false //设置js接口 mVisitorAndroidJs.let { mWebView?.addJavascriptInterface(it, "android") } //页面不跳转浏览器 mWebView?.webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { LogUtils.d(TAG, "url: $url") view.loadUrl(url) return true } override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest ): WebResourceResponse? { var uri = request.url var path = uri.path LogUtils.d(TAG, "uri: $uri, path: $path") return super.shouldInterceptRequest(view, request) } } //webView官方打开文件选取方法onShowFileChooser,把网页回传文件
- mWebView?.webChromeClient = object : WebChromeClient() {
- //API >=21(android 5.0.1)回调此方法
- override fun onShowFileChooser(
- webView: WebView?,
- filePathCallback: ValueCallback<Array<Uri>>?,
- fileChooserParams: FileChooserParams?
- ): Boolean {
- mUploadCallback = filePathCallback
- //使用拍照或者打开文件
- // mImageUri = ChoosePhotoFile.takePhoto(mActivity)
- //模拟微信朋友圈获取照片模式
- LogUtils.d(TAG,"onShowFileChooser")
- PictureSelectorUtils.startPictureSelector(mActivity)
- //设置false会IllegalStateException: Duplicate showFileChooser result
- return true
- }
- }
- } fun onActivityResultResponse(requestCode: Int, resultCode: Int, intent: Intent?) { LogUtils.d( TAG, "onActivityResultResponse requestCode $requestCode, resultCode:$resultCode" ) // 扫描二维码/条码回传 if (requestCode == ScanCodeUtils.REQUEST_CODE_SCAN && resultCode == Activity.RESULT_OK) { LogUtils.d(TAG, "onActivityResultResponse ${intent?.extras}") if (intent == null) { //弹出展示链接 showToast("扫描效果为空") return } //通报给js,格式是"scanCodeResult('${data.extras}')",此中单引号很紧张,大概导致js script error //codedContent是组件中定义的参数名 setEvaluateJavascript("scanCodeResult('${intent.getStringExtra("codedContent")}')")// } else if (requestCode == ChoosePhotoFile.REQUEST_CODE) {// //照相,界面跳回后,效果文件的使用// ChoosePhotoFile.takeActivityResult(requestCode, intent, mUploadCallback, mImageUri) } else if (requestCode == PictureSelectorUtils.REQUEST_PICTURE_SELECTOR) { LogUtils.d(TAG, "onActivityResultResponse REQUEST_PICTURE_SELECTOR") PictureSelectorUtils.takeActivityResult(requestCode, intent, mUploadCallback) } } @Override override fun onDestroy() { //防止更新dialog内存走漏 super.onDestroy() } /** * 登录乐成后跳转 */ open fun loginSuccessJump() { } /** * 给网页传值 * 通报给js,格式是"scanCodeResult('${data.extras}')" * 此中单引号很紧张,大概导致js script error */ private fun setEvaluateJavascript(jspMethodAndValue: String) { LogUtils.d( TAG, "setEvaluateJavascript mWebView ${mWebView}, jspMethodAndValue $jspMethodAndValue" ) mWebView?.evaluateJavascript(jspMethodAndValue, ValueCallback<String>() { LogUtils.d(TAG, "给网页传值为: $jspMethodAndValue") }) }}
复制代码 三、总结一下
- H5调用公共获取图片文件方法,
- 在android手机端,H5主要依赖Webview,
- 这边在webview声明并重写该方法onShowFileChooser
- 使用工具类打开相机或相册,可以两种方式安卓原生方式或者使用第三方组件库方式
- 选中图片,返回uri列表给H5
- H5收到uri照片列表,而且使用前端方式展示
创造价值,乐哉分享!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |