鸿蒙权限申请、网络请求
前言
前两篇鸿蒙文章说实话还是挺水的,没什么干货,主要我也是边学边做,后面会慢慢提高的,代码也会慢慢优化。这篇文章就来讲讲鸿蒙的网络请求和动态权限申请。
权限申请
和安卓一样,鸿蒙的敏感权限也要动态申请,具体的看文档吧,这里我这就以文件权限来写个例子。
声明权限
和安卓在AndroidManifest.xml里面声明权限类似,鸿蒙需要在module.json5文件中声明权限:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.READ_MEDIA",
"reason": "$string:app_name",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "always"
}
}
]
}
}
这里声明了网络权限和读取文件权限,对安卓开发来说应该很熟悉了,就不多说了。需要注意的是,和安卓中申请权限自己做权限说明不一样,鸿蒙这里要在喷子的地方写清申请理由,还要限定权限使用范围,这点确实比安卓好。
动态申请
声明好权限了,就可以在用到的地方动态申请了,先检查权限授予情况:
/**
* 校验当前权限是否已经授权
*
* @param permission
* @returns
*/
async checkAccessToken(permission: Permissions) {
let atManager = abilityAccessCtrl.createAtManager();
let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
// 获取应用程序的accessTokenID
let 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) {
LogUtil.e(`getBundleInfoForSelf failed, error: ${err}`);
}
// 校验应用是否被授予权限
try {
grantStatus = await atManager.checkAccessToken(tokenID, permission);
} catch (err) {
LogUtil.e(`checkAccessToken failed, error: ${err}`);
}
return grantStatus;
}
基本就是官方demo了,就是挺迷,检查个权限不能封装下吗?直接context检查不好吗?
下面看下申请的代码:
/**
* 请求单个权限
*
* @param permission
* @param context
*/
requestPermission(
permission: Permissions,
context: Context,
onSuccess: (message: string)=> void,
onFailed: (error: string) => void
): void {
this.requestPermissions([ permission ], context, onSuccess, onFailed);
}
/**
* 请求多个权限
*
* @param permissions
* @param context
*/
requestPermissions(
permissions: Array<Permissions>,
context: Context,
onSuccess: (message: string)=> void,
onFailed: (error: string) => void
): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
onSuccess("success: " + permissions[i]);
} else {
// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
onFailed("denied: " + permissions[i]);
}
}
}).catch((err: BusinessError) => {
onFailed("error: " + err.message)
LogUtil.d(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
})
}
这里对官方demo改动了些,理解还是挺好理解的,下面再看下整合在一起使用:
/**
* 传入权限数组Array<Permissions>
*
* @param permission
* @returns
*/
async checkAndRequestPermissions(
permissions: Array<Permissions>,
context: Context,
onSuccess: (message: string)=> void,
onFailed: (error: string) => void
): Promise<string> {
return new Promise(async (_resolve, _reject) => {
for (let i = 0; i < permissions.length; i++) {
let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permissions[i]);
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
// 已经授权,可以继续访问目标操作
onSuccess("success: " + permissions[i]);
} else {
// 申请权限
this.requestPermissions([ permissions[i] ], context, onSuccess, onFailed);
}
}
});
}
/**
* 传入权限数组Array<Permissions>
*
* @param permission
* @returns
*/
async checkAndRequestPermissionsForAll(
permissions: Array<Permissions>,
context: Context
): Promise<Boolean> {
return new Promise(async (resolve, reject) => {
try {
let isAllGranted = true;
for (let i = 0; i < permissions.length; i++) {
let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permissions[i]);
if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
if (isAllGranted) {
resolve(true);
}else {
resolve(false);
// 申请权限
this.requestPermissions( permissions , context, ()=>{}, ()=>{});
}
} catch (e) {
LogUtil.e(e);
reject(e);
}
});
}
这里写了两种使用方式,一种是一个一个接受申请结果,一个是得到同意全部的回调,我也不知道这样写好不好,感觉就是有点怪怪的,凑合用吧。
网络请求
首先说明啊,这里我没用鸿蒙三方库的axios,有兴趣的朋友可以选择使用它,我是用的鸿蒙API做的,学习下,主要鸿蒙化的APP功能还不多,后面再看了。
网络请求里面用的比较多的就get和post请求,这里简单封装了下,先来看get请求:
/**
* 发送网络请求
*
* @param url 请求链接
* @param header 自定义请求头
* @param onSuccess 成功回调
* @param onFailed 失败回调
*/
request(
url: string,
header: Record<string,string | number>,
onSuccess: (message: string)=> void,
onFailed: (error: string) => void
) {
// http请求对象
let httpRequest = http.createHttp();
let opt: http.HttpRequestOptions = {
method: http.RequestMethod.GET,
header: header
}
// 发送上传请求
httpRequest.request(url, opt)
.then((resp) => {
if (resp.responseCode == 200) {
onSuccess(JSON.stringify(resp.result))
}else {
onFailed("responseCode:" + resp.responseCode)
}
})
.catch((e: BusinessError) => {
onFailed("error:" + (e as BusinessError).message)
})
}
下面看下用法:
let url = hostUrl + “xxx”;
let header: Record<string, string | number> = {
'Authorization': this.token,
}
httpUtil.request(url, header, (res) => {
// 拿到body数据
}, (err) => {
// 处理失败
});
这里的header是一个Record类型,真的卡了我好久不知道怎么通过方法传递过来,而且Record使用set好像不生效,需要用方括号来设置值。
下面再看下post请求,比get复杂了一丢丢:
/**
* 发送form请求
*
* @param url 请求链接
* @param header 自定义请求头
* @param param form数据
* @param onSuccess 成功回调
* @param onFailed 失败回调
*/
postForm(
url: string,
header: Record<string,string | number>,
param: Map<string, string>,
onSuccess: (message: string)=> void,
onFailed: (error: string) => void
) {
// 增加form的header
header['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
// http请求对象
let httpRequest = http.createHttp();
let opt: http.HttpRequestOptions = {
method: http.RequestMethod.POST,
header: header,
extraData: this.buildQueryString(param)
}
// 发送上传请求
httpRequest.request(url, opt)
.then((resp) => {
onSuccess(JSON.stringify(resp.result))
})
.catch((e: BusinessError) => {
onFailed("uploadFile error:" + (e as BusinessError).message)
})
}
private buildQueryString(params: Map<string, string>) {
let result = ""
params.forEach((value, key)=> {
result += `${key}=${value}&`
})
result = result.slice(0, -1)
return result
}
post请求要发送form数据,需要设置content-type,然后在body里面把form数据通过"&"符号拼接起来,用法如下:
let url = hostUrl + “xxx”;
let header: Record<string, string | number> = {
'Authorization': this.token,
}
// 参数
let param: Map<string, string> = new Map()
param.set('xxx', xxx)
// 异步请求
httpUtil.postForm(url, header, param, (result) => {
resolve(result);
}, (error) => {
reject(error);
})
其实嘛,HTTP协议就是这样,用什么框架都万变不离其中,下面是一个form请求的例子:
POST / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
sex=man&name=Professional
第一行说明了请求方法、路径、协议版本,第二行开始是header,第三个部分是用空行隔开的body,更多的应用我们上传文件再说,这里就算抛砖引玉了。
小结
这篇文章简单介绍了下鸿蒙权限申请和网络请求两个部分的内容,还是以官方API为主,稍微修改和封装了下,希望对读者有所帮助。