HarmonyOS---权限和http/Axios网络请求

网络请求(http,axios)


一、应用权限管理

应用权限保护的对象分数据和功能的:

  • 数据:个人(照片,通讯录,日历,位置)、设备(标识码,相机,麦克风)

  • 功能:设备(摄像头/麦克风、电话、联网)、应用(悬浮窗、快捷方式、唤起第三方应用、后台运行)

1.1权限的等级

system_core: 该等级提供应用服务操作系统的 - 核心能力
system_basic:该等级提供应用服务的 - 基础服务
normal: 普通的基本应用:默认

1.2授权方式

system_grant:系统授权
指的是系统类型的权限,应用被允许访问的数据不会涉及到用户或设备的敏感信息
安装应用是,应用会询问系统,系统会自动进行授权。
user_grant:用户授权
指的是涉及用户隐私或敏感数据的,如果出现问题,是不可控的。
应用安装后,运行时,会指定弹窗,询问用户是否允许获取权限。

授权申请

1.3声明权限的配置

entry/src/main/module.json5 配置文件中,声明权限:

例:当不需要用户确认和用户确认运行都需要在requestPermissions[]中进行配置:

1. 不需要用户确认:
	{
        "name": "ohos.permission.INTERNET"  //权限名称:网络
      },
2. 用户确认 (当需要用户确认时,填写配置信息会有提示,不填则报错)
例:在卡片Call机制中也用到了,保持后台应用:
格式:
	{
        "name": "ohos.permission.LOCATION", //定位
        "reason": "$string:reason_loc",      //描述申请的原因:user_grant时,必填项,因为需要国际化需要在语言文件中设置才可以
        "usedScene": {                       //描述权限使用的场景:user_grant时,必填项
          "abilities": [ "EntryAbility" ],   //标识需要使用该权限的 Ability
          "when": "always"                   //标识使用的时机:inuse:只允许前台, always:前后台都允许
        }

1.4如何向用户进行申请

:定位
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; //权限控制管理

onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    //唤醒用户授权窗口,只有在user_grant情况下有效
    try{
      //创建一个权限管理对象
      const manager = abilityAccessCtrl.createAtManager()
      //基于管理对象,申请用户授权
      manager.requestPermissionsFromUser( this.context, [
        "ohos.permission.LOCATION",
        "ohos.permission.APPROXIMATELY_LOCATION",
        ...
      ] )
    }
    catch(err){
      promptAction.showToast({message:'获取位置失败!'})
    }
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  }

1.5 处理完整流程:(根据实际调整)

当需要访问网络请求或者开启定位、麦克风、相机等功能时,系统级别直接可以加入权限,用户级别则需要用户授权后才可以进行访问。
当给予用户授权可以会遭遇拒绝,此时则需要进行二次申请授权,此时则需要拉起具体位置进行对app授权

解题思路:
	1.要加入权限
	2.校验权限是否开发,判断
	3.没有开启:则申请二次授权,跳转至系统设置位置
	4.开启:执行正常业务

例: 按照定位权限为例

1.要加入权限
	{
        "name": 'ohos.permission.APPROXIMATELY_LOCATION',
        "reason": "$string:reason1",
        "usedScene": {
          "abilities": [
            'EntryAbility'
          ],
          "when": "inuse" // 只在前台
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        "reason": '$string:reason2',
        "usedScene": {
          "abilities": [
            'EntryAbility'
          ],
          "when": "inuse"
        }
      }
2.校验权限是否开发,判断

let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

// 获取tokenId
    let bundleInfo: bundleManager.BundleInfo =
    await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); // 固定参数,可以查看官网
    let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
    
    const permissions: Array<Permissions> = ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION'];
    
    const grantStatus = await atManager.checkAccessToken(appInfo.accessTokenId, permissions[0]);
3.没有开启:则申请二次授权,跳转至系统设置位置
开启判断 // 其实值为0
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) 
未开启判断 // 其实值为-1
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED)

当没有开启时,二次授权:
// 若没有权限
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
	//1. 获取查看是否已经授权
	//2.拉起设置页面
3.1. 获取查看是否已经授权
	  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
      const data = await atManager.requestPermissionsFromUser(getContext(this), permissions)
      let grantStatus: Array<number> = data.authResults;
	// 再次校验是否开启
		if (grantStatus[0] ==abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
3.2 拉起设置页面
	        const context = getContext(this) as common.UIAbilityContext
	        const want: Want = {
	          bundleName: "com.huawei.hmos.settings",
	          abilityName: "com.huawei.hmos.settings.MainAbility", //设置贞的ability名称
	          uri: "application_info_entry",
	          parameters: {
	            pushParams: appInfo.name //因为要知道是哪个应用需要打开设置
	          }
	
	        }
	        await context.startAbility(want)
	}
} else{
	// 已经开启了 ,执行正常的业务
}

扩展:请求方式
GET:
短文本请求,是一种不安全的请求,所有的信息都暴露在地址栏中。
内容的上限是255个字节。
通常都是直接打开网址、超链接a它们使用。
POST:
长文本请求,是一种安全的请求,基于http超文本传输协议的。
数据信息是通过TCP/IP请求协议进行处理的,用户不可见。
数据上限:2MB
如今,我们有一个RestFul请求风格定义,它扩展了更多的请求方式:并不是所有后端服务器都支持

PUT:
    本质还是post请求。

DELETE:
    本质还是get请求。

二、内置http请求使用

可能会存在个版本不兼容问题:建议使用Axios

在这里插入图片描述

1.开启网络权限: 'ohos.permission.INTERNET'
2.导包: import http from '@ohos.net.http'
3.请求:
 		//创建网络请求对象
        const httpRequest:http.HttpRequest = http.createHttp()
		// 方式一:异步
        //异步方法:data就是响应回发的结果
        //httpRequest.request('url', {...}, (err,data)=>{})

		// 方式二: 同步
        //转同步操作
        try{
          const res:http.HttpResponse = await httpRequest.request(
            'https://jsonplaceholder.typicode.com/users',
            {method: http.RequestMethod.GET}   //get请求方式:默认
          )
          //处理请求结果:得到一个json对象
          console.info('http===', res.responseCode)           //状态码
          console.info('http===', JSON.stringify(res.header)) //头部信息
          console.info('http===', JSON.stringify(res.result)) //数据结果
        }
        catch(err){
          console.info('http===', err)
        }
        finally{
          //不管成功还是失败,最终,始终关闭请求对象
          httpRequest.destroy()
        }

2.1 工具包

使用方式:
export const tasksList = async (params: TaskModel) => {
  return await Request.get<taskResInfoModel>('/tasks/list', params)
}
//实现原生http|axios的封装
import { http } from '@kit.NetworkKit'
import { BASE_URL, TOKEN_KEY } from '../constants'
import { promptAction } from '@kit.ArkUI'
import { UserSettingClass } from './setting'
import { ResponseData } from '../models'
import { BusinessError } from '@kit.BasicServicesKit'

/**
 * 调用服务器接口的方法
 * @param url 接口地址 /account/login
 * @param method 请求方式
 * @param data 携带的数据
 * @returns
 */
export async function requestHttp<T>(
  url: string = "",
  method: http.RequestMethod = http.RequestMethod.GET,
  data?: object): Promise<T> {
  //1.创建请求
  const httpRequest = http.createHttp()

  let urlStr = BASE_URL + url
  //GET方式传递的参数:url?key1=value1&key2=value2
  if (method === http.RequestMethod.GET) {
    if (data && Object.keys(data).length) {
      urlStr += "?" + Object.keys(data).map(key => {
        if (data[key]) {
          return `${key}=${data[key]}`
        }
        return ""
      }).join("&")
    }
  }

  //设置请求头
  const config: http.HttpRequestOptions = {
    method: method, //思考:不同的请求方式,如何携带数据?
    extraData: method === http.RequestMethod.GET ? "" : data, //POST方式传递的数据
    header: {
      "Content-Type": "application/json",
      "Authorization": AppStorage.get(TOKEN_KEY) || ""//获取用户令牌
    }
  }
  try {
    //2.发送请求
    const res = await httpRequest.request(urlStr, config)
 	//处理请求结果:得到一个json对象
    // console.info('http===', res.responseCode)           //状态码
    // console.info('http===', JSON.stringify(res.header)) //头部信息
    // console.info('http===', JSON.stringify(res.result)) //数据结果
    
    // 3.解析结果
    if (res.responseCode === 401) {
      promptAction.showToast({ message: "未授权或Token超时!" })
      AppStorage.set(TOKEN_KEY, "") //删除token
      new UserSettingClass(getContext()).setUserToken("") //清空首选项
      return Promise.reject(new Error("未授权或Token超时!"))
    } else if (res.responseCode === 404) {
      promptAction.showToast({ message: "请求地址错误!" })
      return Promise.reject(new Error("请求地址错误!"))
    } else {
      const result = JSON.parse(res.result as string) as ResponseData<T>
      if (result.code === 200) {
        //执行成功
        return result.data as T //直接返回数据
      } else {
        promptAction.showToast({ message: result.msg })
        return Promise.reject(new Error(result.msg))
      }
    }
  } catch (error) {
    promptAction.showToast({ message: JSON.stringify(error) })
    return Promise.reject(error.message)
  } finally {
    //4.销毁
    httpRequest.destroy()
  }
}

export class Request {
  static get<T>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.GET, data)
  }

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

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

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

三、Axios请求使用(建议)

使用Axios需要安装ohpm中的 axios依赖或者在oh-package.json5 加入依赖
方式一:根据命令安装:ohpm install @ohos/axios
方式二:“@ohos/axios”:“^2.2.0”

3.1 使用方式一

直接调用get(),post(), 不建议使用,原因路径每次都是完整的,有重复性

:
开启网络权限: 'ohos.permission.INTERNET'
导包: import axios  from '@ohos/axios'
axios.get('完整url',{params:{}})
axios.post('完整url')

3.2 使用方式二(建议)

定义出来公用部分,若不相同可以在调用时进行覆盖

使用方式:
export const tasksList = async (params: TaskModel) => {
  return await Request.get<taskResInfoModel>('/tasks/list', params)
}
:
开启网络权限: 'ohos.permission.INTERNET'
导包: import axios  from '@ohos/axios'
// 1.公共部分
 const cont =  axios.create({
    baseURL:'https://atstudy-1253850831.cos.ap-shanghai.myqcloud.com', // 公用部分的url
    //transformRequest:()=>{}, // 发送请求前的操作函数 // 知道别用出错有点难找
    //transformResponse:()=>{}, // 接收结果  // 知道别用出错有点难找
    timeout:3*1000, // 请求超时时间
    headers:{} // 头部数据
  })
  // 格式: 2.调用 cont.get() /  cont.post()
  // 此处使用的异步,也可以转为async同步
  cont.get('/lab-d3/harmonyOS/meituan/shop.json',
		 {timeout:6*1000} // 重写超时时间
		 ).then((res: AxiosResponse) => {
	       if (res.status == 200) { // 状态码
	         res.data // 返回数据
	       }
	     })
	       .catch((err: BusinessError) => {
	         promptAction.showToast({ message: "get请求异常"})
	       })
	       .finally(() => {  })

3.3 工具包(建议)

Axios工具包:
import axios, { AxiosResponse } from '@ohos/axios'
import { BASE_URL, USER_TOKEN } from '../constants/setting'
import { ResponseData } from '../models'

export class AxiosUtil {
  public static async get<T>(url: string, extraData: string | Object | ArrayBuffer = ''): Promise<T> {
    const arr = Object.keys(extraData)
    let params = arr.map((item: string,index) => {
    if ( (extraData as object)[item]) {
        return arr[index] as string + '=' + (extraData as object)[item]
        // arr[0] key
        // (extraData as object)[item] // 值
      }
      return ''
    }).join('&')
    const response: AxiosResponse = await ReqAxios().get(url + '?' + params)
    const res = response.data as ResponseData<string>
    return res.data as T
  }

  public static async post<T>(url: string, extraData: string | Object | ArrayBuffer = ''): Promise<T> {
    const response: AxiosResponse = await ReqAxios().post(url, extraData)
    const res = response.data as ResponseData<string>
    return res.data as T
  }

  public static async put<T>(url: string, extraData: string | Object | ArrayBuffer = ''): Promise<T> {
    const response: AxiosResponse = await ReqAxios().put(url,extraData)
    const res = response?.data as ResponseData<string>
    return res.data as T
  }

  public static async delete<T>(url: string, extraData: string | Object | ArrayBuffer = ''): Promise<T> {
    const arr = Object.keys(extraData)
    let params = arr.map((item: string,index) => {
      return arr[index] as string + '=' + (extraData as object)[item]
    }).join('&')
    const response: AxiosResponse = await ReqAxios().delete(url + '?' + params)
    const res = response?.data as ResponseData<string>
    return res.data as T
  }
}

// 封装公用部分url
function ReqAxios() {
  return axios.create({
    baseURL: BASE_URL,
    timeout: 3 * 1000, // 请求超时时间
    headers: {
      'content-type': 'application/json',
      'Authorization': AppStorage.get(USER_TOKEN) as string || null
    }, // 头部数据
    timeoutErrorMessage: '连接超时'
  })
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大众筹码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值