当前位置: 首页 > news >正文

长沙培训网站建设广州做网站多少

长沙培训网站建设,广州做网站多少,广州黄埔做网站,做资料分享网站有哪些系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现(一) HarmonyOS Next 系列之验证码输入组件实现(二) HarmonyOS Next 系列之底部标签栏TabBar实现(三) HarmonyOS Next 系列之HTTP请求封装和Token…

系列文章目录

HarmonyOS Next 系列之省市区弹窗选择器实现(一)
HarmonyOS Next 系列之验证码输入组件实现(二)
HarmonyOS Next 系列之底部标签栏TabBar实现(三)
HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)
HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)


文章目录

  • 系列文章目录
  • 前言
  • 一、实现步骤总结
  • 二、代码实现
    • 1.媒体读写权限检查和申请
    • 2.从手机存储选择图片或拍照
    • 3.复制图片到缓存目录下
    • 4. 接口请求上传图片
  • 三、完整代码
    • 页面调用:


前言

HarmonyOS Next(基于API11)实现从手机选择图片或拍照上传功能,常用于头像上传等操作


一、实现步骤总结

1、媒体读写权限检查和申请
2、从手机存储选择图片或拍照
3、把图片复制到缓存目录
4、接口请求上传图片

分析说明:
图片上传使用API request.uploadFile 而该api上传文件的本地路径只支持internal协议

在这里插入图片描述

所以选择完图片/或拍照后需要把图片从内部存储复制到cache目录下,该操作需要外部存储设备媒体读写权限,且是用户级别的权限,因此每次复制图片前需要检查权限如果没权限需弹窗口让用户授权,最后在通过该api实现上传

在这里插入图片描述

二、代码实现

1.媒体读写权限检查和申请

(1)检查权限

工具类文件:

import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Context, Permissions } from '@ohos.abilityAccessCtrl';//校验应用是否授予权限
//@params permissions:权限名称数组
//@return permissionabilityAccessCtrl:权限名称
async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {let atManager = abilityAccessCtrl.createAtManager();let grantStatus: abilityAccessCtrl.GrantStatus = 0;// 获取应用程序的accessTokenIDlet tokenId: number = 0;try {let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;tokenId = appInfo.accessTokenId;} catch (err) {console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);}// 校验应用是否被授予权限try {grantStatus = await atManager.checkAccessToken(tokenId, permission);} catch (err) {console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);}return grantStatus;
}//检查用户权限
//@params permissions:权限名称数组
export  async function checkPermissions(permissions: Permissions): Promise<boolean> {try {let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions);return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED}catch (e) {return Promise.reject(e)}
}

调用:

      const READ_MEDIA_PERMISSION: Permissions = 'ohos.permission.READ_MEDIA' //媒体读取权限const WRITE_MEDIA_PERMISSION: Permissions = 'ohos.permission.WRITE_MEDIA' //媒体写入权限let permissionList: Permissions[] = []; //需要申请选项列表let readPermission = await checkPermissions(READ_MEDIA_PERMISSION)//检查是否有媒体读取权限!readPermission && permissionList.push(READ_MEDIA_PERMISSION)let writePermission = await checkPermissions(WRITE_MEDIA_PERMISSION)//检查是否有媒体写入权限!writePermission && permissionList.push(READ_MEDIA_PERMISSION)

(2)申请权限
工具类文件:

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import common from '@ohos.app.ability.common'interface rejectObj {code: numbermessage: string
}
/*** 申请权限* @params context:AblitiyContext* @params permissions:权限名称数组* @returns  Promise<boolean>:是否授权成功*/
export async function applyPermission(context: common.UIAbilityContext, permissions: Array<Permissions>): Promise<boolean> {let atManager = abilityAccessCtrl.createAtManager();return new Promise((resolve: (res: boolean) => void, reject: (e: rejectObj) => void) => {atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResults;resolve(grantStatus.every(item => item === 0))}).catch((err: rejectObj) => {reject(err)})})
}

调用:

       private context = getContext(this) as common.UIAbilityContext; //UIAbilityContext...............//申请权限let res: boolean = await applyPermission(this.context, permissionList)if (!res) {//用户未同意授权AlertDialog.show({title: "提示",message: "无权限读写用户外部存储中的媒体文件信息,请前往系统设置开启",alignment: DialogAlignment.Center,secondaryButton: {value: '关闭',action: () => {}}})}

2.从手机存储选择图片或拍照

(1)从手机存储选择图片

    import picker from '@ohos.file.picker';........//从相册选择let PhotoSelectOptions = new picker.PhotoSelectOptions();PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;PhotoSelectOptions.maxSelectNumber = 1;let photoPicker = new picker.PhotoViewPicker();photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {if (PhotoSelectResult.photoUris.length) {console.log(`图片本地路径:${PhotoSelectResult.photoUris[0]}`)} })

(2)拍照

    import camera from '@ohos.multimedia.camera';import camerapicker from '@ohos.multimedia.cameraPicker';import { BusinessError } from '@ohos.base';........try{let pickerProfile: camerapicker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK};let pickerResult: camerapicker.PickerResult = await camerapicker.pick(this.context,[camerapicker.PickerMediaType.PHOTO, camerapicker.PickerMediaType.PHOTO], pickerProfile);} catch (error) {let err = error as BusinessError;console.error(`the pick call failed. error code: ${err.code}`);}   

3.复制图片到缓存目录下

默认复制图片到缓存目录cache根路径下,移动后文件名前面加上当前时间戳区分:timestamep+原name.格式

import fs from '@ohos.file.fs';/*** 复制文件到缓存目录下* @param path :文件路径* @param context :Context* @returns Promise<string> 移动后文件路径*/
export async function copyFileToCache(path: string,context:Context): Promise<string> {try {let file =  fs.openSync(path, fs.OpenMode.READ_WRITE)if (file) {let fileDir: string = `${context.cacheDir}` //临时文件目录//时间戳生成随机文件名let newPath: string =  `${new Date().getTime()}_${path.split("/")[path.split("/").length-1]}`let targetPath: string = `${fileDir}/${newPath}`fs.copyFileSync(file.fd, targetPath)return  newPath}else {return ''}} catch (e) {return Promise.resolve('')}
}

4. 接口请求上传图片

  //开始上传图片 path:图片路径后缀(图片名称)async uploadImage(path: string) {let uri=`internal://cache/${path}` //上传图片全路径let uploadConfig: request.UploadConfig = {url:"http://xxxxxxx",header:{},method: "POST",files: [{ filename: path, name: "file", uri, type: path.split('.')[path.split('.').length-1] }],data: [],};try {let uploadTask:request.UploadTask=await request.uploadFile(this.context, uploadConfig)//上传中回调uploadTask.on('progress', (size,total) => {console.log(size.toString(),total.toString(),'上传进度')})//上传完成回调uploadTask.on('complete', (taskStates: request.TaskState[]) => {console.info("upOnComplete complete taskState:" + JSON.stringify(taskStates));})//上传失败回调uploadTask.on('fail', (taskStates: request.TaskState[]) => {console.info("upOnComplete fail taskState:" + JSON.stringify(taskStates));})}catch (e){console.log( JSON.stringify(e),'e')}}

需要注意的是我们在复制图片步骤中通过context.cacheDir获取到的缓存目录路径如下所示:

"path":"/data/storage/el2/base/haps/entry/cache/1717854801890_IMG_20240603_170235.jpg"

需转换成internal协议路径,
前面 “/data/storage/el2/base/haps/entry/cache"实际等价于"internal://cache”
所以在上传接口拼接uri参数时候只需要知道图片名称+格式即可,最终上传参数拼接后路径为internal://cache/1717854801890_IMG_20240603_170235.jpg


三、完整代码

完整代码将封装一个完整的组件,自定义底部弹窗菜单选择拍照或从手机相册选择,选完自动上传。
在这里插入图片描述

代码目录结构
在这里插入图片描述

utils/index.ets(工具类):


import fs from '@ohos.file.fs';
import bundleManager from '@ohos.bundle.bundleManager';
import abilityAccessCtrl, { Context, Permissions } from '@ohos.abilityAccessCtrl';
import common from '@ohos.app.ability.common'/*** 复制文件到缓存目录下* @param path :文件路径* @param context :Context* @returns Promise<string> 移动后文件路径*/
export async function copyFileToCache(path: string,context:Context): Promise<string> {try {let file =  fs.openSync(path, fs.OpenMode.READ_WRITE)if (file) {let fileDir: string = `${context.cacheDir}` //临时文件目录//时间戳生成随机文件名let newPath: string =  `${new Date().getTime()}_${path.split("/")[path.split("/").length-1]}`let targetPath: string = `${fileDir}/${newPath}`fs.copyFileSync(file.fd, targetPath)return  newPath}else {return ''}} catch (e) {return Promise.resolve('')}
}//校验应用是否授予权限
//@params permissions:权限名称数组
//@return permissionabilityAccessCtrl:权限名称
async function checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {let atManager = abilityAccessCtrl.createAtManager();let grantStatus: abilityAccessCtrl.GrantStatus = 0;// 获取应用程序的accessTokenIDlet tokenId: number = 0;try {let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;tokenId = appInfo.accessTokenId;} catch (err) {console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);}// 校验应用是否被授予权限try {grantStatus = await atManager.checkAccessToken(tokenId, permission);} catch (err) {console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);}return grantStatus;
}//检查用户权限
//@params permissions:权限名称数组
export  async function checkPermissions(permissions: Permissions): Promise<boolean> {try {let grantStatus: abilityAccessCtrl.GrantStatus = await checkAccessToken(permissions);return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED}catch (e) {return Promise.reject(e)}
}interface rejectObj {code: numbermessage: string
}
/*** 申请权限* @params context:AblitiyContext* @params permissions:权限名称数组* @returns  Promise<boolean>:是否授权成功*/
export async function applyPermission(context: common.UIAbilityContext, permissions: Array<Permissions>): Promise<boolean> {let atManager = abilityAccessCtrl.createAtManager();return new Promise((resolve: (res: boolean) => void, reject: (e: rejectObj) => void) => {atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResults;resolve(grantStatus.every(item => item === 0))}).catch((err: rejectObj) => {reject(err)})})
}

ImageUploadDialog.ets(图片上传弹窗菜单选择组件):

import picker from '@ohos.file.picker';
import { checkPermissions, applyPermission, copyFileToCache } from '../../utils/index'
import { request } from '@kit.BasicServicesKit';
import { Permissions } from '@ohos.abilityAccessCtrl';
import camera from '@ohos.multimedia.camera';
import camerapicker from '@ohos.multimedia.cameraPicker';
import { BusinessError } from '@ohos.base';
import { common } from '@kit.AbilityKit';@Extend(Text)
function custText() {.width('100%').height('48')    .fontColor('#39364D').textAlign(TextAlign.Center)
}@CustomDialog
export default struct ImageUploadDialog {dialogController: CustomDialogController@Prop uploadURL:string='';//上传接口地址private context = getContext(this) as common.UIAbilityContext; //UIAbilityContextprivate success:(res: request.TaskState[])=>void=()=>{}//上传成功回调private fail:(res: request.TaskState[])=>void=()=>{} //上传失败回调//检查权限async checkAppPermission(): Promise<boolean> {try {const READ_MEDIA_PERMISSION: Permissions = 'ohos.permission.READ_MEDIA' //媒体读取权限const WRITE_MEDIA_PERMISSION: Permissions = 'ohos.permission.WRITE_MEDIA' //媒体写入权限let permissionList: Permissions[] = []; //需要申请选项列表let readPermission = await checkPermissions(READ_MEDIA_PERMISSION)//检查是否有媒体读取权限!readPermission && permissionList.push(READ_MEDIA_PERMISSION)let writePermission = await checkPermissions(WRITE_MEDIA_PERMISSION)//检查是否有媒体写入权限!writePermission && permissionList.push(READ_MEDIA_PERMISSION)if (permissionList.length) {//申请权限let res: boolean = await applyPermission(this.context, permissionList)if (!res) {//用户未同意授权AlertDialog.show({title: "提示",message: "无权限读写用户外部存储中的媒体文件信息,请前往系统设置开启",alignment: DialogAlignment.Center,secondaryButton: {value: '关闭',action: () => {}}})}return res}return true}catch (e) {return Promise.reject(e)}}//开始上传图片 path:图片路径后缀(图片名称)async uploadImage(path: string) {console.log(path, 'path')let uri=`internal://cache/${path}` //上传图片全路径let uploadConfig: request.UploadConfig = {url:this.uploadURL,header:{},method: "POST",files: [{ filename: path, name: "file", uri, type: path.split('.')[path.split('.').length-1] }],data: [],};try {let uploadTask:request.UploadTask=await request.uploadFile(this.context, uploadConfig)//上传中回调uploadTask.on('progress', (size,total) => {console.log(size.toString(),total.toString(),'上传进度')})//上传完成回调uploadTask.on('complete', (taskStates: request.TaskState[]) => {console.info("upOnComplete complete taskState:" + JSON.stringify(taskStates));if(taskStates&&taskStates.length&& taskStates[0].responseCode===0){this.success&&this.success(taskStates)}})//上传失败回调uploadTask.on('fail', (taskStates: request.TaskState[]) => {console.info("upOnComplete fail taskState:" + JSON.stringify(taskStates));this.fail&&this.fail(taskStates)})}catch (e){console.log( JSON.stringify(e),'e')}}build() {Column() {//拍照Text('拍照').custText().onClick(async()=>{//检查是否有读写外部媒体权限let res: boolean = await this.checkAppPermission()//无权限返回if (!res) returntry {let pickerProfile: camerapicker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK};let pickerResult: camerapicker.PickerResult = await camerapicker.pick(this.context,[camerapicker.PickerMediaType.PHOTO, camerapicker.PickerMediaType.PHOTO], pickerProfile);if(pickerResult?.resultUri){//关闭弹窗this.dialogController.close()//复制图片到缓存目录(缓存目录才有读写权限)let filePath = await copyFileToCache(pickerResult.resultUri, this.context)if (filePath) {//上传头像并设置this.uploadImage(filePath)}}} catch (error) {let err = error as BusinessError;console.error(`the pick call failed. error code: ${err.code}`);}})Divider().color('#F7F9FA').width('100%').strokeWidth(1)//从手机相册选择Text('从手机相册选择').custText().onClick(async () => {//检查是否有读写外部媒体权限let res: boolean = await this.checkAppPermission()//无权限返回if (!res) return//关闭弹窗this.dialogController.close()//从相册选择let PhotoSelectOptions = new picker.PhotoSelectOptions();PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;PhotoSelectOptions.maxSelectNumber = 1;let photoPicker = new picker.PhotoViewPicker();photoPicker.select(PhotoSelectOptions).then(async (PhotoSelectResult) => {if (PhotoSelectResult.photoUris.length) {//复制图片到缓存目录(缓存目录才有读写权限)let filePath = await copyFileToCache(PhotoSelectResult.photoUris[0],this.context)if (filePath) {this.uploadImage(filePath)}}})})Button('取消', { type: ButtonType.Capsule }).backgroundColor('#F7F7F7').fontSize('16fp').fontColor('#333333').width('100%').margin({ top: '30' }).onClick(() => {this.dialogController.close()})}.width('100%').padding({ left: '16', top: '11', right: '16', bottom: '16' }).backgroundColor(Color.White).borderRadius({topLeft: '24',topRight: '24'})}
}

组件入参 说明:

uploadURL:上传接口url
success:(res: request.TaskState[])=>void 上传成功回调函数
fail:(res: request.TaskState[])=>void=()=>{} //上传失败回调

成功或失败回调参数说明

 request.TaskState[]: {path:string //图片在本地路径message:string //上传结果信息responseCode //上传结果状态码 0:成功,其他值失败}[]

从 request.TaskState字段描述可以看出request.uploadFile无法返回接口返回的数据,这也是最大的坑,期待官方解决,如果需要获取上传成功后返回的url,可以在设计个接口上传完再调用该接口获取图片url,如果像头像设置这种功能也可以把图片上传和头像设置整合成一个接口,上传完也即设置完成。

页面调用:

pages/Index

import ImageUploadDialog from '../components/ImageUploadDialog/ImageUploadDialog'
import { promptAction } from '@kit.ArkUI'@Entry
@Component
struct Index {@State dialogController: CustomDialogController | null = null //选择上传类型弹窗控制器aboutToAppear(): void {this.dialogController= new CustomDialogController({builder: ImageUploadDialog({uploadURL: 'http://xxxxxxxxx',//上传地址success:e=>{//上传成功回调console.log(JSON.stringify(e))promptAction.showToast({message:'上传成功'})},fail:e=>{//上传失败回调console.log(JSON.stringify(e))promptAction.showToast({message:'上传失败'})}}),alignment: DialogAlignment.Bottom,//弹窗居于底部customStyle: true,//自定义样式})}build() {Column(){Button('上传').onClick(()=>{this.dialogController?.open()})}.width('100%')}
}

最后不要忘记添加权限
三个:

  "ohos.permission.INTERNET":网访问权限"ohos.permission.READ_MEDIA":外部存储设备媒体读取权限"ohos.permission.WRITE_MEDIA":外部存储设备媒体写入权限

module.json5:

 //权限requestPermissions: [{"name": "ohos.permission.INTERNET",},{"name": "ohos.permission.READ_MEDIA","reason": "$string:reasonReadWriteMedia",//使用权限原因"usedScene": {"abilities": [//使用的该权限的EntryAbility名称数组"EntryAbility"],"when": "inuse"}},{"name": "ohos.permission.WRITE_MEDIA","reason": "$string:reasonReadWriteMedia","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]

entry\src\main\resources\base\element\string.json

{"string": [,{"name":"reasonReadWriteMedia","value": "上传头像"}]
}

效果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

http://www.yayakq.cn/news/560351/

相关文章:

  • 网站建设云创做网站买什么书
  • 网站 手机站开发 cms360的网站排名怎么做
  • 网站被百度降权了怎么办中信建设公司董事长
  • 自己做网站美工自适用网站的建设
  • 提高网站性能电子工程职业学院官网
  • 建立网站项目计划书模板雷神代刷网站推广快速
  • 建设一个网站的具体流程做动漫网站
  • 建设网站代理网站内容授权书
  • 百度上找不到网站个人网站制作流程图片
  • 汽车网站cms大连住房保障网官网
  • 南宁网络营销网站wordpress中文破解主题
  • 怎么做网站识图验证码网络优化工程师发展前景
  • 网站建设所需要软件网站开发资料
  • 企业网站一定要花钱吗技术优化seo
  • 西安模板网站建设套餐莱芜信息港网页
  • 学校网站的建设费用吗仿木鱼网络网站
  • 厦门同安区建设局网站wordpress 全局字段
  • 手机创建网站免费注册wordpress获取当前分类文章数
  • 佛山网站建设电话网站制作模板软件
  • 中核西北建设集团网站小红书3000粉丝推广报价多少
  • 朔州seo网站建设网站设计图尺寸
  • 百度网站与推广装饰设计乙级资质
  • 用什么程序做网站上线了怎么建网站
  • 微信商城小程序怎么做应用宝aso优化
  • 网站中信息更新怎么做的大渡口网站建设
  • 网站建设佰金手指科杰十三wordpress 便利贴
  • 阳泉网站建设Python仿wordpress
  • 爱美刻在线制作网站wordpress 聊天室
  • 做宠物网站导航应该写什么字wordpress随机推
  • 沈阳做网站昌平装修公司哪家好