一级a做爰片迅雷网站/产品品牌推广策划方案
需求目的: 手机机通过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: FragmentVisitorBindinglateinit var mActivity: Activityprivate lateinit var mRoot: Viewcompanion object {const val TAG = "VisitorFragment"}private var mWebViewUrl: String = "file:///android_asset/vue_android_demo.html"var mAppName = MainApplication.instance.configuration.BASE_APP_LOGIN_IDENTITYvar mSystemName = WebViewConstant.DEFAULT_SYSTEM_NAMEprivate var mVisitorAndroidJs: VisitorAndroidJs = VisitorAndroidJs(this)private var mWebView: WebView? = nullvar mAndroidId: String = WebViewConstant.DEFAULT_DEVICE_SIGNvar mApiKey: String = WebViewConstant.DEFAULT_API_KEY//回传H5时使用的对象private var mUploadCallback: ValueCallback<Array<Uri>>? = null//拍照传递的路径uriprivate 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?) {//设置当前fragmentmAndroidId = 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? = activityactivity?.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.mainWebViewmWebView?.requestFocus()mWebView?.isHorizontalScrollBarEnabled = falsemWebView?.isVerticalScrollBarEnabled = falseval setting = mWebView?.settingssetting?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW;setting?.javaScriptEnabled = true//用于开启或禁用其 DOM(文档对象模型)存储功能,浏览器缓存这些数据setting?.domStorageEnabled = true//允许访问文件,默认允许setting?.allowFileAccess = true//设置不,会引起webView重新不急,默认NARROW_COLUMNSsetting?.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS//自动缩放setting?.setSupportZoom(true)setting?.builtInZoomControls = true//自适应屏幕setting?.useWideViewPort = truesetting?.loadWithOverviewMode = true//支持多窗口setting?.setSupportMultipleWindows(true)setting?.setAppCacheEnabled(true)setting?.domStorageEnabled = true//定位setting?.setGeolocationEnabled(true)//优先使用缓存数据,在缓存数据不存在的情况下才去获取网络数据setting?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORKsetting?.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.urlvar path = uri.pathLogUtils.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 resultreturn 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)}}@Overrideoverride 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"><WebViewandroid: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 resultreturn 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")//设置当前fragmentval fragment = mDashboardViewModel.fragment.valueLog.d(TAG, "fragment: $fragment")Log.d(TAG, "fragment.isResumed: ${fragment?.isResumed}")//界面返回时VisitorFragment还没有Resumedif (fragment is VisitorFragment) {val visitorFragment: VisitorFragment = fragmentvisitorFragment.onActivityResultResponse(requestCode, resultCode, data)}}
3.打开相机和相册的工具类
object ChoosePhotoFile {private const val TAG = "ChoosePhotoFile"const val REQUEST_CODE: Int = 12345fun takePhoto(activity: Activity): Uri {//相机可以访问的公共位置才能存储,获取时需要读取文件权限val file: String =Environment.getExternalStorageDirectory().toString() + File.separator + Environment.DIRECTORY_PICTURES + File.separatorval 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) {//从相册获取,返回的intentif (intent != null && intent.data != null) {var uri: Uri = intent.data as UriLogUtils.d(TAG, "file uri: $uri")filePathCallback?.onReceiveValue(arrayOf<Uri>(uri))} else {//从拍照中获取图片,已经返回的imageUriLogUtils.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 resultreturn 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 = 10012const 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.pathLogUtils.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.pathLogUtils.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: FragmentVisitorBindinglateinit var mActivity: Activityprivate lateinit var mRoot: Viewcompanion object {const val TAG = "VisitorFragment"}private var mWebViewUrl: String = "file:///android_asset/vue_android_demo.html"var mAppName = MainApplication.instance.configuration.BASE_APP_LOGIN_IDENTITYvar mSystemName = WebViewConstant.DEFAULT_SYSTEM_NAMEprivate var mVisitorAndroidJs: VisitorAndroidJs = VisitorAndroidJs(this)private var mWebView: WebView? = nullvar mAndroidId: String = WebViewConstant.DEFAULT_DEVICE_SIGNvar mApiKey: String = WebViewConstant.DEFAULT_API_KEY//回传H5时使用的对象private var mUploadCallback: ValueCallback<Array<Uri>>? = null//拍照传递的路径uriprivate 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?) {//设置当前fragmentmAndroidId = 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? = activityactivity?.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.mainWebViewmWebView?.requestFocus()mWebView?.isHorizontalScrollBarEnabled = falsemWebView?.isVerticalScrollBarEnabled = falseval setting = mWebView?.settingssetting?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW;setting?.javaScriptEnabled = true//用于开启或禁用其 DOM(文档对象模型)存储功能,浏览器缓存这些数据setting?.domStorageEnabled = true//允许访问文件,默认允许setting?.allowFileAccess = true//设置不,会引起webView重新不急,默认NARROW_COLUMNSsetting?.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS//自动缩放setting?.setSupportZoom(true)setting?.builtInZoomControls = true//自适应屏幕setting?.useWideViewPort = truesetting?.loadWithOverviewMode = true//支持多窗口setting?.setSupportMultipleWindows(true)setting?.setAppCacheEnabled(true)setting?.domStorageEnabled = true//定位setting?.setGeolocationEnabled(true)//优先使用缓存数据,在缓存数据不存在的情况下才去获取网络数据setting?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORKsetting?.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.urlvar path = uri.pathLogUtils.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 resultreturn 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)}}@Overrideoverride 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照片列表,并且使用前端方式展示
创造价值,乐哉分享!
相关文章:

H5获取手机相机或相册图片两种方式-Android通过webview传递多张照片给H5
需求目的: 手机机通过webView展示H5网页,在特殊场景下,需要使用相机拍照或者从相册获取照片,上传后台。 完整流程效果: 如下图 一、H5界面样例代码 使用html文件格式,文件直接打开就可以展示布局&#…...

mysql进阶学习 | DAY 14
存储引擎 体系结构 连接层 服务层 引擎层 存储层 存储引擎 表类型 查看引擎 查看建表语句 指定存储引擎 ENGINE SHOW engins InnoDB 默认存储引擎 遵循ACID模型 支持事务 行级锁 提高并发访问性能 支持外键 FOREIGN KEY约束 保证数据完整性和正确性 对应文件 xx…...

使用GPT生成python图表
首先,生成一脚本,读取到所需的excel表格 import xlrddata xlrd.open_workbook(xxxx.xls) # 打开xls文件 table data.sheet_by_index(0) # 通过索引获取表格# 初始化奖项字典 awards_dict {"一等奖": 0,"二等奖": 0,"三等…...

[深度学习]yolov9+deepsort+pyqt5实现目标追踪
【YOLOv9DeepSORTPyQt5追踪介绍】 随着人工智能技术的飞速发展,目标追踪在视频监控、自动驾驶等领域的应用日益广泛。其中,YOLOv9作为先进的目标检测算法,结合DeepSORT多目标追踪算法和PyQt5图形界面库,能够为用户提供高效、直观…...

C#_WaitAll、WhenAll、async及await
Task.WhenAll、Task.WaitAll Task.WhenAll 和 Task.WaitAll 都是用于等待多个任务完成的方法,但它们之间有一些重要的区别。 返回类型: Task.WhenAll: 返回一个 Task 对象,该对象表示所有输入任务的联合任务。 Task.WaitAll: 没有返回值。它是一个同步方…...

leetcode hot100零钱兑换Ⅱ
本题可以看出也是背包问题,但区别于之前的01背包问题,这个是完全背包问题的变形形式。 下面介绍01背包和完全背包的区别与联系: 01背包是背包中的物品只能用一次,不可以重复使用,而完全背包则是可以重复使用。01/完全…...

路由器配置DMZ主机映射
路由器配置DMZ主机映射 光猫路由模式配置方法 光猫路由模式是用光猫进行拨号连接,所有设备通过光猫访问互联网,只需要设置光猫的DMZ主机映射地址为局域网主机即可 光猫桥接模式配置方法 光猫桥接模式,是穿透光猫,通过路由器拨…...

ubuntu22.04@Jetson Orin Nano之CSI IMX219安装
ubuntu22.04Jetson Orin Nano之CSI IMX219安装 1. 源由2. 安装2.1 硬件安装2.2 软件配置2.3 新增摄像头 3. 效果4. 参考资料 1. 源由 折腾半天时间,捣鼓这个套装摄像头(IMX219)的安装,死活就是没有这个设备。世界总是这么小,看看遇到问题的大…...

Kettle下载地址
kettle是一款基于java开发的洗数工具,可以通过图像化的操作界面,拖拉拽的操作方式,实现数据导入导出清洗等功能,还支持编写脚本进行数据处理,功能十分强大。 kettle本身是开源免费的,但它的下载地址非常难…...

密码学基本概念
1、信息安全的属性:机密性、认证(消息认证、身份认证)、完整性、不可否认性、可靠性、可用性、可控性、审计。 2、密码学是研究解决机密性、认证(消息认证、身份认证)、完整性、不可否认性这些安全问题的手段…...

9个最受欢迎的开源自动化测试框架盘点!
自动化测试框架可以帮助测试人员评估多个Web和移动应用程序的功能,安全性,可用性和可访问性。尽管团队可以自己构建复杂的自动化测试框架,但是当他们可以使用现有的开源工具,库和测试框架获得相同甚至更好的结果时,通常…...

高速稳定、网络隔离,解析“向日葵控控”远控方案在医疗行业应用
在医疗大健康领域,依托高速发展的信息化技术加速布局智能化,通过远程手段提高医疗服务质量、促进医疗资源共享、提升医疗工作效率,已成为医院和各类社区诊所等提供关键医疗服务部门近年来的发展目标之一。 同时,根据医疗领域的特殊…...

抖音视频提取软件使用功能|抖音视频下载工具
我们的抖音视频提取软件是一款功能强大、易于操作的工具,旨在解决用户在获取抖音视频时需要逐个复制链接、下载的繁琐问题。我们的软件支持通过关键词搜索和分享链接两种方式获取抖音视频,方便用户快速找到自己感兴趣的内容。 主要功能模块:…...

Django入门指南:从环境搭建到模型管理系统的完整教程
环境安装: 由于我的C的Anaconda 是安装在C盘的,但是没内存了,所有我将环境转在e盘,下面的命令是创建环境到指定目录中. conda create --prefixE:\envs\dj42 python3.9进入环境中: conda activate E:\envs\dj42…...

Elasticsearch从入门到精通-01认识Elasticsearch
Elasticsearch从入门到精通-01认识Elasticsearch 👏作者简介:大家好,我是程序员行走的鱼 🍂博主从本篇正式开始ES学习,希望小伙伴可以一起探讨 📖 本篇主要介绍和大家一块简单认识下ES并了解ES中的主要角色…...

Element UI的安装和使用
Element UI 是一个基于 Vue 2.0 的桌面端组件库,广泛用于快速构建高质量的用户界面。以下是 Element UI 组件的安装和使用的详细步骤: 1. 安装 Element UI 在开始之前,确保你已经设置好了 Vue 项目环境。如果你还没有Vue项目,可…...

c++的指针完整教程
概述:C的指针是一种特殊的变量,它存储的是另一个变量的内存地址。指针的使用可以让我们更高效地操作内存,实现动态内存分配等功能。 声明指针变量 要声明一个指针变量,需要在变量类型前加上星号(*)。例如…...

WordPress前端如何使用跟后台一样的Dashicons图标字体?
很多站长都喜欢在站点菜单或其他地方添加一些图标字体,常用的就是添加Font Awesome 图标和阿里巴巴矢量库图标iconfont。其实我们使用的 WordPress 本身就有一套管理员使用的官方图标字体 Dashicons,登录我们站点后台就能看到这些图标字体。那么有没有可…...

redisson实现延迟队列
1.pom引入redisson <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.20.1</version></dependency>整合springboot配置,这个可以参考之前整合redisson的文章,…...

【教程】N2N V3内网穿透、异地组网,包括Win/Linux/Android,包括不同内网实现adb远程连接
目录 一、背景 二、Linux 配置 并运行 N2N - Supernode (必选) 三、Linux -- 配置 并运行 N2N - 边缘节点配置 Edge(可选步骤) 四、Windows -- 配置 并运行 N2N - 边缘节点配置 Edge (可选步骤) (一)配置 TAP 虚拟网卡 (二)配置 N...

JavaAPI常用类01
目录 概述 Object类 Object类_toString() 代码展示 重写toString()方法前后输出 Object类_equals() 代码展示 重写equals()方法前后输出对比 Arrays类 equals()方法 Binary Search(二分查找) copyOf()方法 sort()方法 了解sort()方法 进阶…...

在 where子句中使用子查询(二)
目录 ANY ANY :功能上与 IN 是没有任何区别的 >ANY :比子查询返回的最小值要大 ALL >AL :比子查询返回的最大值要大 EXISTS() 判断 NOT EXISTS Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209…...

TongWEB(东方通),部署WEB前后端项目步骤
我的系统: 银河麒麟桌面系统V10(SP1)(兆芯) 环境需要搭建好,什么redis,数据库等 1.准备项目前端war包 (我后端项目本就是war部署,jar转war自行百度一下吧) 进入前端打包好的dist文件夹,创建一个文件夹 WEB-INF ,再在 WEB-INF 里创建一个 web.xml 文件,文件内容: <web-…...

Vue中如何使用dayjs
Day.js中文网Day.js是一个极简的JavaScript库,可以为现代浏览器解析、验证、操作和显示日期和时间。https://dayjs.fenxianglu.cn/ 单位不区别大小写,支持复数和缩写形式 单位缩写描述 date D日期 [1,31]dayd星期 [0,6](星期日0,…...

数据库-MySQL
建立索引 mysql 添加索引的三种方法 - krt-wanyi - 博客园 (cnblogs.com) 跨库联表查询 MySQL不同数据库不同表连表查询(跨库连表查询)-CSDN博客 关于微服务跨数据库联合查询的一些解决思路_微服务跨库联表查询-CSDN博客 同一个连接不同数据库前缀 …...

C语言每日一题(61)盛最多水的容器
题目链接 力扣 11 盛最多水的容器 题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水…...

uni-app 经验分享,从入门到离职(四)——页面栈以及页面跳转的 API(开发经验总结)
文章目录 📋前言⏬关于专栏 🎯什么是页面栈🧩页面跳转方法📌 uni.navigateTo(OBJECT)📌 uni.redirectTo(OBJECT)📌 uni.reLaunch(OBJECT)📌 uni.switchTab(OBJECT)📌 uni.navigateBa…...

Go Module常用命令
Go Module常用命令TOC Go Module常用命令 go mod init #初始化go.mod go mod tidy #更新依赖文件 go mod download #下载依赖文件 go mod vendor #将依赖转移至本地的vendor文件 go mod edit #手…...

ubuntu压缩和解压
-c 创建 -x 解压 -v 显示过程 -f 文件名 xz格式 tar -tf arm-linux-gnueabi-5.4.0.tar.xz 查看压缩包的内容 tar -xf arm-linux-gnueabi-5.4.0.tar.xz -C / 解压 gz格式 t…...

华为HCIP Datacom H12-831 卷24
多选题 1、如图所示,某园区部署OSPF实现网络互通,其中Area1部署为NSSA区域。某工程师为了实现R1访问R4的环回口地址,在R4的OSPF进程中引入直连路由。以下关于该场景的描述,错误的有哪些项? A、在R4引入直连路由后,R1通过转换后的…...