【Harmony】常用工具类封装

news2025/4/23 17:37:03

文章目录

  • 一,简介
  • 二,网络请求工具类
    • 2.1、鸿蒙原生http封装
    • 2.2、第三方axios封装(需提前下载依赖)
  • 三、录音笔相关工具类
    • 3.1、录音封装(录入)
    • 3.2、录音封装(放音/渲染)
    • 3.3、文件写入封装(针对录音/放音功能)
  • 四、RDB关系型数据库
    • 4.1、relationalStore简答的CRUD封装
    • 4.2、relationalStore单例模式封装(待更新)
  • 五、首选项
    • 5.1、preferences简单封装
    • 5.2、preferences单例模式封装
  • 六、权限管理
    • 6.1、权限管理封装
  • 七、其他工具类
    • 7.1、生成一个指定连续数值的数组
    • 7.2、生成随机颜色(RGB)
    • 7.3、生成随机颜色(16进制)
    • 7.4、格式化日期

一,简介

本文工具类更新至2025年4月22日,后续有新内容也会持续更新。并且本文工具类为本人在学习过程中自己总结和封装,可能有不足的地方,欢迎大佬指正。

二,网络请求工具类

2.1、鸿蒙原生http封装

//【鸿蒙http】
// -http只提供底层核心代码功能,没有任何功能的封装,需要自己开发。
// -适配应用,采用泛型进行封装
import { http } from "@kit.NetworkKit";
import { BASE_URL, TOKEN_KEY } from "../constants";
import { promptAction, router } from "@kit.ArkUI";
import { UserSettingClass } from ".";
import { ResponseData } from "../models";


//【网络请求过程】
// 当前模块私有方法,不导出,提供正式对外开放的功能使用
// 其中包括:请求拦截处理,头部处理,过程处理,响应结果处理
//  -url:请求的路径:必填项
//  -data:请求的参数对象:什么都可以,用object,可选的
//  -method:请求方式,可选,默认是GET请求
async function requestHttp<T> (
  url: string,
  data?: object,
  method:http.RequestMethod = http.RequestMethod.GET
): Promise<T> {

  //创建请求对象
  const httpRequest = http.createHttp()

  //设置请求参数对象
  const options: http.HttpRequestOptions = {
    method,
    readTimeout: 10000,
    header: {
      //与后台匹配,提交的是json对象
      'Content-Type': 'application/json',
      //用户登录后,应用级数据对象获取用户令牌,拿不到就是空的
      'Authorization': AppStorage.get<string>(TOKEN_KEY) || ''
    },
    //设置除get请求之外的请求参数(因为get请求提交的数据是组合在地址中的)
    extraData: method === http.RequestMethod.GET ? '' : data
  }

  //组合正式请求的完整网址
  let urlStr = BASE_URL + url

  //处理get请求情况
  if(method === http.RequestMethod.GET){
    //需要将请求对象中的属性提取出来,组合到请求地址中
    //判断:是否提交了请求数据对象
    if(data){
      //调用Object的方法,自动获取对象中所有的属性名,返回字符串数组
      const allKeys:string[] = Object.keys(data)
      //是否有请求的参数属性
      if(allKeys){
        //创建一个数组,字符串的,里面是请求内容[key=value]
        const arr:string[] = []
        //循环key的数组
        for(let key of allKeys){
          //在数据中,按照key获取值,然后组合成要的格式,加入数组
          arr.push(`${key}=${data[key]}`)
        }
        //组合到请求地址中:按照指定字符将数组所有元素组合成一个字符串
        urlStr += '?' + arr.join('&')
      }
    }
  }

  //正式发送请求
  //  -异常需要处理:这个数据代码错误了
  //  -http请求操作是一次性的(鸿蒙固定的),用完了要销毁的
  //  -需要对应好resolve和reject
  //   错误情况有多种,err是错误,服务器正常返回也有错误的
  //  -采用Promise特性,async自动封装了Promise,内部可以直接对应resolve和reject
  try{
    //发起请求,获取响应结果
    const res = await httpRequest.request(urlStr, options)
    //解析响应结果:
    if(res.responseCode === 401){
      //服务器验证用户身份Authorization失败
      promptAction.showToast({message: '未授权或令牌失效!'})
      //清空本地令牌
      AppStorage.setOrCreate(TOKEN_KEY, '')
      new UserSettingClass(getContext()).setUserToken('')
      //跳转登录
      router.replaceUrl({ url: 'pages/Login/Login' })
      //返回错误
      return Promise.reject(new Error('未授权或令牌失效!'))
    }
    else if(res.responseCode === 404){
      //访问的地址已失效
      promptAction.showToast({message: '请求的地址无效!'})
      return Promise.reject(new Error('请求的地址无效!'))
    }
    else if(res.responseCode === 200){
      //正确响应,提取响应结果
      // -先将响应结果统一类型string
      // -然后转成json对象,它是object
      // -然后对应好类型约束:ResponseData:参考所有接口返回的统一格式
      const result = JSON.parse(res.result as string) as ResponseData<T>

      //校验结果:回发的数据中的编码
      if(result.code === 200){
        //返回结果:适配泛型,默认返回自动对应resolve,不用写了
        return result.data as T
      }
      else{
        //请求对的,也响应了,但是代码中说失败
        //请找后端开发人员了解具体情况:需要告知:请求方式、头部、参数
        promptAction.showToast({message: '请求失败!'})
        return Promise.reject(new Error('请求失败!'))
      }
    }
    else{
      return Promise.reject(new Error('服务器接口调用失败!'))
    }
  }
  catch(err){
    //错误
    return Promise.reject(new Error(JSON.stringify(err)))
  }
  finally {
    //对和错都执行:销毁请求对象
    httpRequest.destroy()
  }
}



//【http接口请求工具类】
// -对外提供RestFul请求风格的四类请求:GET/POST/PUT/DELETE
// -采用静态方法,提供应用直接使用
export class Request {

  //方法格式统一,用方法名描述请求方式
  //参数只要路径和请求数据对象
  //响应结果是Promise<泛型>,你要什么返回什么
  static get<T>(url:string, data?:object):Promise<T> {
    return requestHttp<T>(url, data, http.RequestMethod.GET)
  }

  static post<T>(url:string, data?:object):Promise<T> {
    return requestHttp<T>(url, data, http.RequestMethod.POST)
  }

  static put<T>(url:string, data?:object):Promise<T> {
    return requestHttp<T>(url, data, http.RequestMethod.PUT)
  }

  static delete<T>(url:string, data?:object):Promise<T> {
    return requestHttp<T>(url, data, http.RequestMethod.DELETE)
  }
}

2.2、第三方axios封装(需提前下载依赖)

如果没有axios依赖,须在项目目录下,命令行执行如下命令

ohpm install @ohos/axios

出现绿色completed证明安装成功

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

//【第三方axios】
import axios,{InternalAxiosRequestConfig,AxiosError,AxiosResponse,AxiosRequestConfig,AxiosInstance} from "@ohos/axios"
import { UserSettingClass } from "."
import { BASE_URL, TOKEN_KEY } from "../constants"
import { router } from "@kit.ArkUI"

const instance = axios.create({
  baseURL:BASE_URL,//自动组合到请求路径
  readTimeout:10000
})


//请求拦截配置,发起请求时,先执行这里追加令牌
instance.interceptors.request.use((config:InternalAxiosRequestConfig)=>{
  //config就是配置,我们在头部追加用户令牌
  config.headers.Authorization = AppStorage.get(TOKEN_KEY) || ""
  return config

},(err:AxiosError)=>{
  return Promise.reject(err)
})


//响应拦截,接收到响应结果后,执行这里的操作
instance.interceptors.response.use((response:AxiosResponse)=>{
  //data:{code,meg,data}
  //判断结果:
  if(response.data && response.data.code ===200){
    return response.data.data
  }
  //TODO:如果response.data.code ===401等自行处理

  //默认返回响应,调用者处理
  return response
},(err:AxiosError)=>{
  //是否是401,身份验证不通过
  if(err.response?.status===401){
    //说明令牌无效
    AppStorage.setOrCreate(TOKEN_KEY,"")//删除应用中的token记录
    new UserSettingClass(getContext()).setUserToken("")//删除首选项中的token
    //跳转登录
    router.replaceUrl({ url: 'pages/Login/Login' })
  }
  return Promise.reject(err)
})


//提供执行操作对象,适配泛型
//R是返回类型,D是请求类型
//支持调用时,自定义配置
function request<R=null,D=null>(config:AxiosRequestConfig){
  //返回操作实例
  return instance<null,R,D>(config)
}


export class RequestAxios{
  static get<T>(url:string, data?:object):Promise<T> {
    return request<T,null>({url,params:data,method:"GET"})
  }

  static post<T>(url:string, data?:object):Promise<T> {
    return request<T,object>({url,data,method:"POST"})
  }

  static put<T>(url:string, data?:object):Promise<T> {
    return request<T,object>({url,data,method:"PUT"})
  }

  static delete<T>(url:string, data?:object):Promise<T> {
    return request<T,object>({url,data,method:"DELETE"})
  }
}

三、录音笔相关工具类

3.1、录音封装(录入)

//音频工具
//官方称之为录音笔
//需要集成audio和fileIo
import { audio } from "@kit.AudioKit";
import { fileIo } from "@kit.CoreFileKit";
import { emitter } from "@kit.BasicServicesKit";

export class AudioCapturer{

  //录音笔对象
  static audioCapture:audio.AudioCapturer

  //音频流配置
  static audioStreamInfo:audio.AudioStreamInfo = {
    samplingRate:audio.AudioSamplingRate.SAMPLE_RATE_16000,//音频的采样率:帧数
    sampleFormat:audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,//音频文件的转码格式--音频播放解析
    encodingType:audio.AudioEncodingType.ENCODING_TYPE_RAW,//文件编码格式--读写文件
    channels:audio.AudioChannel.CHANNEL_1 //等级
  } as audio.AudioStreamInfo

  //录音笔配置
  static  audioCapturerInfo:audio.AudioCapturerInfo = {
    source:audio.SourceType.SOURCE_TYPE_MIC,//资源的来源:麦克风
    capturerFlags:0//功能启动标识
  }

  //控制变量:是否进行录制
  static recordIng:boolean =false

  //初始化
  static async  init(){
    //创建录音笔实例
    AudioCapturer.audioCapture = await audio.createAudioCapturer({
      streamInfo:AudioCapturer.audioStreamInfo,
      capturerInfo:AudioCapturer.audioCapturerInfo
    })
  }

  //开始录制
  static async start(filePath:string){
    try {
      //打开目标文件,得到文件对象,只写,读不在这块
      const file=fileIo.openSync(filePath,fileIo.OpenMode.READ_WRITE|fileIo.OpenMode.CREATE)
      //文件大小:字节
      const fd = file.fd
      let bufferSize = fileIo.statSync(fd).size
      //开始采集,状态转换
      AudioCapturer.recordIng = true
      //开启录音笔能力
      await AudioCapturer.audioCapture.start()
      //采集音频:循环执行,由状态变量AudioCapturer.recordIng决定是否录制
      while (AudioCapturer.recordIng){
        //获取采集音频已经录下的在缓冲区内容的大小,他是一段一段读的
        const size = AudioCapturer.audioCapture.getBufferSizeSync()
        //从缓冲区中读取一段
        const  buffer = await AudioCapturer.audioCapture.read(size,true)
        //如果可以读到
        if(buffer){
          //追加写入
          fileIo.writeSync(fd,buffer,{
            offset:bufferSize,
            length:buffer.byteLength
          })
          //通知页面
          emitter.emit("caleVoice",{data:{buffer}})
          //下一段
          bufferSize+=buffer.byteLength
        }
      }

    }catch (err) {
      console.log(JSON.stringify(err));
      AlertDialog.show({message:"当前设备不支持录音"})
    }
  }


  //结束录制
  static async stop(){
    //只有在录制才可以结束根据状态变量判断
    if(AudioCapturer.recordIng && AudioCapturer.audioCapture){
      //结束音频录制
      AudioCapturer.recordIng = false
      //关闭录音功能
      await AudioCapturer.audioCapture.stop()
    }
  }



  //释放资源
  static async close(){
    //只要对象存在都可以执行
    if(AudioCapturer.audioCapture){
      //释放缓冲区
      await AudioCapturer.audioCapture.release()
    }
  }

}

3.2、录音封装(放音/渲染)

//音频渲染/播放工具
//主要集中于本地文件,先下载
import { audio } from "@kit.AudioKit";
import { fileIo } from "@kit.CoreFileKit";

export  class AudioRender {

  //播放器对象
  static audioRenderer:audio.AudioRenderer

  //音频流的配置
  static audioStreamInfo:audio.AudioStreamInfo = {
    samplingRate:audio.AudioSamplingRate.SAMPLE_RATE_16000,
    sampleFormat:audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
    channels:audio.AudioChannel.CHANNEL_1,
    encodingType:audio.AudioEncodingType.ENCODING_TYPE_RAW
  } as audio.AudioStreamInfo

  //渲染器的配置
  static audioRenderInfo:audio.AudioRendererInfo = {
    rendererFlags:0,//标记
    usage:audio.StreamUsage.STREAM_USAGE_VOICE_ASSISTANT //语音助手的
  } as audio.AudioRendererInfo

  //渲染器的配置对象,将上面两个配置合在一起
  static  audioRenderOptions:audio.AudioRendererOptions = {
    streamInfo:AudioRender.audioStreamInfo,
    rendererInfo:AudioRender.audioRenderInfo
  }


  //文件
  static renderFile:fileIo.File

  //文件大小
  static maxSize:number = 0

  //已经播放的字节数
  static renderSize:number = 0

  //播放完的回调
  static callBack=()=>{}


  //初始化
  static async init(){
    //创建渲染器实例
    AudioRender.audioRenderer = await audio.createAudioRenderer(AudioRender.audioRenderOptions)
    //注册(监听)数据写入事件操作
    AudioRender.audioRenderer.on("writeData",//当有数据写入时
      (buffer:ArrayBuffer)=>{
        //是否有文件
        if(AudioRender.renderFile){
          //有,从文件中读取,文件大小必须保持一致
          fileIo.readSync(AudioRender.renderFile.fd,buffer,{
            offset:AudioRender.renderSize,
            length:buffer.byteLength
          })
          //更新字节数
          AudioRender.renderSize += buffer.byteLength
        }
        //前面的内容是否播放完毕
        if(AudioRender.renderSize>=AudioRender.maxSize){
          //关闭文件
          fileIo.closeSync(AudioRender.renderFile.fd)
          //停止播放
          //TODO:
          AudioRender.stop()
        }
      }
    )
  }

  //播放
  static async start(filePath:string,callBack1?:()=>void,callBack2?:()=>void){
    //播放之前,停止之前播放,确保同时只播放一个
    await AudioRender.stop()
    //打开需要播放的文件
    AudioRender.renderFile= fileIo.openSync(filePath,fileIo.OpenMode.READ_WRITE)
    //获取文件大小
    AudioRender.maxSize= fileIo.statSync(AudioRender.renderFile.fd).size
    //文件有内容时
    if(AudioRender.maxSize>0){
      //如果有回调1:作为当前播放之前的方法调用
      callBack1 && callBack1()
      //如果有回调2:作为当前停止之后的方法调用,通过引用传递
      if(callBack2){
        AudioRender.callBack = callBack2
      }
      //正式播放
      AudioRender.audioRenderer.start()
    }else {
      AlertDialog.show({message:`文件为空`})
    }
  }


  //停止
  static async stop(){
    //必须播放状态下才可以停止
    if(AudioRender.audioRenderer && AudioRender.audioRenderer.state=== audio.AudioState.STATE_RUNNING){
      //停止
      await AudioRender.audioRenderer.stop()
      //重置信息
      AudioRender.maxSize = 0
      AudioRender.renderSize = 0
      //调用回调,告知外部
      AudioRender.callBack && AudioRender.callBack()
    }
  }

}

3.3、文件写入封装(针对录音/放音功能)

//文件处理工具
//用于处理物理文件,针对files/目录
//针对录音功能,音频文件后缀.wav
import {fileIo} from  "@kit.CoreFileKit"

export  class  FileOperate{

  //创建空文件,返回路径
  static  createAudioFile(userId:string){
    //判断有没有路径,没有就创建
    const dirPath = getContext().filesDir+"/"+userId
    if(!fileIo.accessSync(dirPath)){
      fileIo.mkdirSync(dirPath)
    }
    //文件不能重名,利用时间戳作为文件名
    const  filePath = dirPath+"/"+Date.now()+".wav"
    //打开并创建文件
    const file = fileIo.openSync(filePath,fileIo.OpenMode.CREATE)
    //关闭文件,防止挂起
    fileIo.closeSync(file)
    return filePath
  }
  
  //删除指定文件
  static deleteFile(path:string){
    fileIo.unlinkSync(path)
  }

  //删除整个个人目录
  static deleteUser(userId:string){
    const dirPath = getContext().filesDir+"/"+userId
    if(fileIo.accessSync(dirPath)){
      fileIo.rmdirSync(dirPath)
    }
  }

}

四、RDB关系型数据库

4.1、relationalStore简答的CRUD封装

补充:

​ 1.这个工具类关闭数据库那里有点问题,我加了延时器关闭。因为store.close()是异步操作,如果不加,查询操作可能会出现数据库连接关闭了,返回的结果为空这种情况。所以手动延迟2秒关闭,造成这种情况原因还没完全搞明白,后续搞懂了再更新。

​ 2.resultSet结果集需要在调用处自行关闭释放。

import { relationalStore } from "@kit.ArkData"

export  class  DBHelper{
  //TODO:这里数据库名需要替换为自己的,注意不要忘了.db后缀
  private DB_NAME:string = "Test.db"
  //TODO:这里数据库安全等级需要替换为自己的
  private DB_SECURITY_LEVEL = relationalStore.SecurityLevel.S1
  private store:relationalStore.RdbStore = {} as relationalStore.RdbStore
  private config:relationalStore.StoreConfig = {
    name:this.DB_NAME,
    securityLevel:this.DB_SECURITY_LEVEL
  }


  //创建链接,需要传入上下文对象
  private async createDB(context:Context){
    try {
        this.store = await relationalStore.getRdbStore(context,this.config)
    }catch (e){
        console.log("createDB执行异常",e);
    }
  }


  //增删改操作,由调用处决定上下文对象
  async  execDML(context:Context,sql:string,params?:Array<relationalStore.ValueType>){
    try {
      await this.createDB(context)

      await this.store.executeSql(sql,params)
    } catch (e) {
      console.log("execDML执行异常",e)
    } finally {
      if(this.store){
        setTimeout(async ()=>{
         await this.store.close()
        },2000)
      }
    }
  }
  
  //查询操作,由调用处决定上下文对象
  async  execDQL(context:Context,sql:string,params?:Array<relationalStore.ValueType>){
    try {
      await this.createDB(context)
      let res =  await this.store.querySql(sql,params)
      return res
    }catch (e){
        console.log("execDQL执行异常",e);
        return {} as relationalStore.ResultSet
    } finally {
      if(this.store){
        setTimeout(async ()=>{
          await this.store.close()
        },2000)
      }
    }
  }
}

4.2、relationalStore单例模式封装(待更新)

五、首选项

5.1、preferences简单封装

import { preferences } from "@kit.ArkData"



export class UserSettingClass{
  private  context:Context

  constructor(context:Context) {
    this.context=context
  }

  //获取首选项仓库
  private getStore():Promise<preferences.Preferences>{
    //TODO:这里USER_SETTING需要替换为你的首选项文件存储时的名字
    return preferences.getPreferences(this.context,USER_SETTING)
  }

  //TODO:通过getStore()获取首选项仓库,然后定义对应方法
  //TODO:以下是两个案例:1.广告数据的存取,用户令牌的存取
  
  // //广告的数据存取
  // async setUserAd(ad:AdvertClass):Promise<void>{
  //   const store = await this.getStore()
  //   await store.put(USER_SETTING_AD,JSON.stringify(ad))
  //   await store.flush()
  // }
  //
  // async getUserAd():Promise<AdvertClass>{
  //   const store = await this.getStore()
  //   const result =  await store.get(USER_SETTING_AD,JSON.stringify(defaultAd))
  //   return JSON.parse(result as string) as AdvertClass
  // }
  //
  // //用户的令牌存取
  // async setUserToken(token:string):Promise<void>{
  //   const store = await this.getStore()
  //   await store.put(TOKEN_KEY,token)
  //   await store.flush()
  // }
  //
  // async getUserToken():Promise<string>{
  //   const store = await this.getStore()
  //   const result =  await store.get(TOKEN_KEY,"")
  //   return result as string
  // }

}

5.2、preferences单例模式封装

//首选项功能类
import { preferences } from "@kit.ArkData"
import { MessageInfoModel } from "../models/message"
import { emitter } from "@kit.BasicServicesKit"
import { DefaultUserList } from "../models/users"


export class StoreClass{
  static context:Context //上下文
  static KEY:string = "Ding" //标识

  //初始化方法,固定好上下文对象,全局都用这一个
  //TODO:这里推荐在entryAbility中进行初始化,固定上下文
  static init(context:Context){
    StoreClass.context = context
  }

  //每一个聊天用户一个文件,而不是所有人都存在一个地方
  //通过用户id获取指定用户的首选项仓库
  //TODO:核心就是这个方法,如果不想所有东西保存在一个位置,那么就用参数+key(随便什么字符串)拼接
  private  static  getUserStoreById(userId:string):preferences.Preferences{
    return preferences.getPreferencesSync(StoreClass.context,{name:`${StoreClass.KEY}_${userId}`})
  }

  //TODO:下面的方法是一些案例,可以参考。不需要就删掉自行定义相关方法


  // //给指定用户添加一条消息
  // static async addChatMessage(userId:string,message:MessageInfoModel){
  //   //获取用户仓库
  //   const store =  StoreClass.getUserStoreById(userId)
  //   //添加(按照消息id,转字符串)
  //   store.putSync(message.id,JSON.stringify(message))
  //   //更新
  //   store.flushSync()
  //   //【发布通知,告知消息放好了】给对方说有新内容,你可以读了,不然对方不知道有新的消息需要更新
  //   //利用线程通讯,告知应用,消息发送好了
  //   emitter.emit(StoreClass.KEY)
  //
  // }
  //
  // //删除指定用户的消息
  // static async removeChatMessage(userId:string,messageId:string){
  //   //获取用户仓库
  //   const store =  StoreClass.getUserStoreById(userId)
  //   //删除
  //   store.deleteSync(messageId)
  //   //更新
  //   store.flushSync()
  //   //【发布通知】
  //   emitter.emit(StoreClass.KEY)
  // }
  //
  // //删除指定用户的所有信息
  // static async removeChatAllMessage(userId:string){
  //   //删除用户仓库
  //   preferences.deletePreferences(StoreClass.context,{name:`${StoreClass.KEY}_${userId}`})
  //   //【发布通知】
  //   emitter.emit(StoreClass.KEY)
  // }
  //
  // //获取指定用户的所有信息
  // static getChatAllMessage(userId:string):MessageInfoModel[]{
  //   //获取用户仓库
  //   const store =  StoreClass.getUserStoreById(userId)
  //   //获取所有
  //   const  all = store.getAllSync() as object
  //   //有吗?
  //   if(all){
  //     //系统方法,通过字符串内容实现数据集合
  //     const list: MessageInfoModel[] = Object.values(all).map((item:string)=>{
  //       return JSON.parse(item) as MessageInfoModel
  //     })
  //     //按照时间进行数据排序
  //     list.sort((a,b)=>{return a.sendTime-b.sendTime})
  //     return list
  //   }else {
  //     return []
  //   }
  //
  // }
  //
  // //获取所有用户最后一条消息【不需要参数】
  // //针对接收到新消息,只要有发布,我就获取所有
  // static async getAllChatLastMessage(){
  //   const  lastList:MessageInfoModel[] = []
  //   //从默认用户列表,提取所有用户信息
  //   DefaultUserList.forEach((user)=>{
  //     //按照用户id提取他所有的消息
  //     const  chatList = StoreClass.getChatAllMessage(user.user_id)
  //     //是否存在
  //     if(chatList.length>0){
  //       //最后一个消息,放入数组
  //       lastList.push(chatList[chatList.length-1])
  //     }
  //     //按照时间进行数据排序
  //     lastList.sort((a,b)=>{return a.sendTime-b.sendTime})
  //   })
  //   return lastList
  // }

}

六、权限管理

6.1、权限管理封装

此工具类包含:检查权限\拉起权限弹窗\跳转系统权限设置

//之前需要授权管理,每次都要重新写代码
//所以我们先封装一个工具,后续可以一直使用
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';

 class PermissionManager{

  /**
   * 检查有没有指定的权限
   * @param permissions 指定的权限的列表
   */
  checkPermissions(permissions:Permissions[]){
    //权限管理器
    let manager = abilityAccessCtrl.createAtManager();

    //获取应用信息(通过系统方法获取)
    let appInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)

    //获取应用唯一标识
    let tokenId = appInfo.appInfo.accessTokenId

    //校验这个token是否拥有权限
    let authResults = permissions.map((permission:Permissions)=>{
      return manager.checkAccessTokenSync(tokenId,permission)
    })

    //返回是否拥有权限
    return authResults.every((authResult:abilityAccessCtrl.GrantStatus)=>{
      return authResult === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
    })
  }

  /**
   * 动态弹窗申请权限
   * @param permissions
   * @returns
   */
  async requestPermissions(permissions:Permissions[]):Promise<boolean>{
    let mangager =  abilityAccessCtrl.createAtManager();
    let res = await mangager.requestPermissionsFromUser(getContext(),permissions)

    //选择结果
    let isAuth = res.authResults.every((authResult:abilityAccessCtrl.GrantStatus)=>{
      return authResult === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
    })

    return isAuth
  }

  //如果出问题需要打开系统设置手动给权限
  //打开系统设置:权限管理页面
  openPermissionSettingPage() {
    //获取UIAbility上下文对象
    const context = getContext() as common.UIAbilityContext
    //应用信息(通过系统方法设置为当前本地应用对象)
    const appInfo = bundleManager.getBundleInfoForSelfSync(
      bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
    )
    //打开系统设置窗口,进行配置
    context.startAbility({
      bundleName: 'com.huawei.hmos.settings',
      abilityName: 'com.huawei.hmos.settings.MainAbility',
      uri: 'application_info_entry',
      parameters: {
        pushParams: appInfo.name
      }
    })
  }
}

export let permissionManager = new PermissionManager()

七、其他工具类

7.1、生成一个指定连续数值的数组

/*生成一个指定连续数值的数组
 * startNum:number 开始参数
 * endNum:number 结束参数
 * step:number=1 步长参数(默认为1)
 * */
export  function range(startNum:number,endNum:number,step:number=1){
  let arr:number[]=[];
  for(let i=startNum;i<=endNum;i+=step){
    arr.push(i)
  }
  return arr;
}

7.2、生成随机颜色(RGB)

export function getRandColorRGB(){
  const  red = Math.floor(Math.random()*256) //0~255的随机数
  const  green = Math.floor(Math.random()*256) //0~255的随机数
  const  blue = Math.floor(Math.random()*256) //0~255的随机数
  return `rgb(${red},${green},${blue})`
}

7.3、生成随机颜色(16进制)

export function getRandColorHEX(){
  const  result = Math.floor(Math.random()*16777216).toString(16) //16777216=256*256*256
  return "#"+result
}

7.4、格式化日期

export function formatDate(date:Date):string{
  let year= date.getFullYear()
  let month= date.getMonth()+1
  let day= date.getDate()
  let hour= date.getHours()
  let minter= date.getMinutes()
  let seconds= date.getSeconds()

  let monthStr = month<10?"0"+month:month.toString()
  let dayStr = day<10?"0"+day:day.toString()
  let hourStr = hour<10?"0"+hour:hour.toString()
  let minterStr = minter<10?"0"+minter:minter.toString()
  let secondsStr = seconds<10?"0"+seconds:seconds.toString()

  return `${year}-${monthStr}-${dayStr} ${hourStr}:${minterStr}:${secondsStr}`
  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2340941.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DCDC芯片,boost升压电路设计,MT3608 芯片深度解析:从架构到设计的全维度技术手册

一、硬件架构解析:电流模式升压 converter 的核心设计 (一)电路拓扑与核心组件 MT3608 采用恒定频率峰值电流模式升压(Boost)转换器架构,核心由以下模块构成: 集成功率 MOSFET 内置 80mΩ 导通电阻的 N 沟道 MOSFET,漏极(Drain)对应引脚 SW,源极(Source)内部接…

Cline 之Plan和Act模式

Cline 提供了 "Plan & Act"双模式开发框架。适用在不同的场景。 一、核心模式理念 通过结构化开发流程提升AI编程效率&#xff0c;采用"先规划后执行"的核心理念。 该框架旨在帮助开发者构建更易维护、准确性更高的代码&#xff0c;同时显著缩短开发…

【中级软件设计师】程序设计语言基础成分

【中级软件设计师】程序设计语言基础成分 目录 【中级软件设计师】程序设计语言基础成分一、历年真题二、考点&#xff1a;程序设计语言基础成分1、基本成分2、数据成分3、控制成分 三、真题的答案与解析答案解析 复习技巧&#xff1a; 若已掌握【程序设计语言基础成分】相关知…

C++项目 —— 基于多设计模式下的同步异步日志系统(3)(日志器类)

C项目 —— 基于多设计模式下的同步&异步日志系统&#xff08;3&#xff09;&#xff08;日志器类&#xff09; 整体思想设计日志消息的构造C语言式的不定参函数的作用函数的具体实现逻辑1. 日志等级检查2. 初始化可变参数列表3. 格式化日志消息4. 释放参数列表5. 序列化和…

【数学建模】随机森林算法详解:原理、优缺点及应用

随机森林算法详解&#xff1a;原理、优缺点及应用 文章目录 随机森林算法详解&#xff1a;原理、优缺点及应用引言随机森林的基本原理随机森林算法步骤随机森林的优点随机森林的缺点随机森林的应用场景Python实现示例超参数调优结论参考文献 引言 随机森林是机器学习领域中一种…

蓝桥杯 19.合根植物

合根植物 原题目链接 题目描述 W 星球的一个种植园被分成 m n 个小格子&#xff08;东西方向 m 行&#xff0c;南北方向 n 列&#xff09;。每个格子里种了一株合根植物。 这种植物有个特点&#xff0c;它的根可能会沿着南北或东西方向伸展&#xff0c;从而与另一个格子的…

Linux环境MySQL出现无法启动的问题解决 [InnoDB] InnoDB initialization has started.

目录 起因 强制启用恢复模式 备份数据 起因 服务器重启了&#xff0c;然后服务器启动完成之后我发现MySQL程序没有启动&#xff0c;错误信息如下&#xff1a; 2025-04-19T12:46:47.648559Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started. 2025-04-1…

高性能服务器配置经验指南1——刚配置好服务器应该做哪些事

文章目录 安装ubuntu安装必要软件设置用户远程连接安全问题ClamAV安装教程步骤 1&#xff1a;更新系统软件源步骤 2&#xff1a;升级系统&#xff08;可选但推荐&#xff09;步骤 3&#xff1a;安装 ClamAV步骤 4&#xff1a;更新病毒库步骤 5&#xff1a;验证安装ClamAV 常用命…

Centos7安装Jenkins(图文教程)

本章教程,主要记录在centos7安装部署Jenkins 的详细过程。 [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) 一、基础环境安装 内存大小要求:256 MB 内存以上 硬盘大小要求:10 GB 及以上 安装基础java环境:Java 17 ( JRE 或者 JDK 都可…

【JAVA】十三、基础知识“接口”精细讲解!(二)(新手友好版~)

哈喽大家好呀qvq&#xff0c;这里是乎里陈&#xff0c;接口这一知识点博主分为三篇博客为大家进行讲解&#xff0c;今天为大家讲解第二篇java中实现多个接口&#xff0c;接口间的继承&#xff0c;抽象类和接口的区别知识点&#xff0c;更适合新手宝宝们阅读~更多内容持续更新中…

边缘计算盒子是什么?

边缘计算盒子是一种小型的硬件设备&#xff0c;通常集成了处理器、存储器和网络接口等关键组件&#xff0c;具备一定的计算能力和存储资源&#xff0c;并能够连接到网络。它与传统的云计算不同&#xff0c;数据处理和分析直接在设备本地完成&#xff0c;而不是上传到云端&#…

大数据系列 | 详解基于Zookeeper或ClickHouse Keeper的ClickHouse集群部署--完结

大数据系列 | 详解基于Zookeeper或ClickHouse Keeper的ClickHouse集群部署 1. ClickHouse与MySQL的区别2. 在群集的所有机器上安装ClickHouse服务端2.1. 在线安装clickhouse2.2. 离线安装clickhouse 3. ClickHouse Keeper/Zookeeper集群安装4. 在配置文件中设置集群配置5. 在每…

19Linux自带按键驱动程序的使用_csdn

1、自带按键驱动程序源码简析 2、自带按键驱动程序的使用 设备节点信息&#xff1a; gpio-keys {compatible "gpio-keys";pinctrl-names "default";pinctrl-0 <&key_pins_a>;autorepeat;key0 {label "GPIO Key L";linux,code &l…

用银河麒麟 LiveCD 快速查看原系统 IP 和打印机配置

原文链接&#xff1a;用银河麒麟 LiveCD 快速查看原系统 IP 和打印机配置 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在银河麒麟操作系统的 LiveCD 或系统试用镜像环境下&#xff0c;如何查看原系统中电脑的 IP 地址与网络打印机 IP 地址的实用教程。在系统损坏…

.net core 项目快速接入Coze智能体-开箱即用-第2节

目录 一、Coze智能体的核心价值 二、开箱即用-效果如下 三 流程与交互设计 本节内容调用自有或第三方的服务 实现语音转文字 四&#xff1a;代码实现----自行实现 STT 【语音转文字】 五&#xff1a;代码实现--调用字节API实现语音转文字 .net core 项目快速接入Coze智能…

win10中打开python的交互模式

不是输入python3&#xff0c;输入python&#xff0c;不知道和安装python版本有没有关系。做个简单记录&#xff0c;不想记笔记了

时序逻辑电路——序列检测器

文章目录 一、序列检测二、牛客真题1. 输入序列连续的序列检测&#xff08;输入连续、重叠、不含无关项、串行输入&#xff09;写法一&#xff1a;移位寄存器写法二&#xff1a;Moore状态机写法三&#xff1a;Mealy状态机 一、序列检测 序列检测器指的就是将一个指定的序列&…

TikTok X-Gnarly纯算分享

TK核心签名校验&#xff1a;X-Bougs 比较简单 X-Gnarly已经替代了_signature参数&#xff08;不好校验数据&#xff09; 主要围绕query body ua进行加密验证 伴随着时间戳 浏览器指纹 随机值 特征值 秘钥转换 自写算法 魔改base64编码 与X-bougs 长a-Bougs流程一致。 视频…

LPDDR5协议新增特性

文章目录 一、BL/n_min参数含义二、RDQS_t/RDQS_c引脚的功能三、DMI引脚的功能3.1、Write操作时的Data Mask数据掩码操作3.2、Write/Read操作时的Data Bus Inversion操作四、CAS命令针对WR/RD/Mask WR命令的低功耗组合配置4.1、Write/Read操作前的WCK2CK同步操作4.2、Write/Rea…

【深度学习】#8 循环神经网络

主要参考学习资料&#xff1a; 《动手学深度学习》阿斯顿张 等 著 【动手学深度学习 PyTorch版】哔哩哔哩跟李牧学AI 为了进一步提高长线学习的效率&#xff0c;该系列从本章开始将舍弃原始教材的代码部分&#xff0c;专注于理论和思维的提炼&#xff0c;系列名也改为“深度学习…