Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
basic-uniapp-v3
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-uniapp-v3
Commits
edbd7400
提交
edbd7400
authored
10月 22, 2024
作者:
方治民
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 添加 usePermissions hook 组件用来实现通用的 Android 权限监听
上级
a0b9d9b2
显示空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
382 行增加
和
96 行删除
+382
-96
package.json
package.json
+2
-1
App.vue
src/App.vue
+17
-1
usePermissions.ts
src/hooks/app/usePermissions.ts
+258
-0
manifest.json
src/manifest.json
+97
-92
app.d.ts
types/app.d.ts
+7
-2
vite.config.ts
vite.config.ts
+1
-0
没有找到文件。
package.json
浏览文件 @
edbd7400
...
...
@@ -161,5 +161,6 @@
"engines"
:
{
"node"
:
">=18"
,
"pnpm"
:
">=9.0.0"
}
},
"appName"
:
"基础工程"
}
src/App.vue
浏览文件 @
edbd7400
<
script
setup
lang=
"ts"
>
// import * as Push from '@/utils/push
'
import
{
onExit
}
from
'@dcloudio/uni-app
'
import
{
isDevMode
}
from
'@/utils/env'
import
{
usePermissions
}
from
'@/hooks/app/usePermissions'
// import * as Push from '@/utils/push'
// 监听权限获取
const
{
listen
,
stop
}
=
usePermissions
()
onLaunch
(()
=>
{
console
.
log
(
'App Launch'
)
// #ifdef APP-PLUS
// 监听权限获取
listen
()
// #endif
// 清除消息角标
// Push.setBadge(0)
...
...
@@ -21,6 +32,11 @@
// #endif
})
onExit
(()
=>
{
// 停用监听权限
stop
()
})
onShow
(()
=>
{
console
.
log
(
'App Show'
)
})
...
...
src/hooks/app/usePermissions.ts
0 → 100644
浏览文件 @
edbd7400
import
{
debounce
}
from
'lodash-es'
import
{
Storage
}
from
'@/utils/storage'
export
interface
Permissions
{
listen
:
()
=>
void
stop
:
()
=>
void
gotoAppPermissionSetting
:
()
=>
void
}
export
interface
RequestPermissionListener
{
onRequest
:
(
e
:
any
)
=>
void
onConfirm
:
(
e
:
any
)
=>
void
onComplete
:
(
e
:
any
)
=>
void
stop
:
()
=>
void
}
/**
* 权限申请说明(注:仅适用于 Android)
* @link https://uniapp.dcloud.net.cn/tutorial/app-nativeresource-android.html#permissions
*/
export
function
getRequestPermissionTipMessage
(
id
:
string
)
{
switch
(
id
)
{
case
'android.permission.INTERNET'
:
return
{
name
:
'网络权限'
,
message
:
'允许访问网络,便于使用应用相关功能。'
}
case
'android.permission.CAMERA'
:
return
{
name
:
'相机权限'
,
message
:
'允许访问摄像头,便于拍照上传照片/图片用于意见反馈、保存相册、缓存数据提升访问速度等场景中拍摄照片。'
,
}
case
'android.permission.READ_MEDIA_IMAGES'
:
case
'android.permission.READ_EXTERNAL_STORAGE'
:
case
'android.permission.WRITE_EXTERNAL_STORAGE'
:
return
{
name
:
'存储权限'
,
message
:
'允许访问存储,便于上传照片/图片用于意见反馈、保存相册、缓存数据提升访问速度等场景中读取和写入相册和文件内容。'
,
}
case
'android.permission.READ_PHONE_STATE'
:
case
'android.permission.ACCESS_NETWORK_STATE'
:
case
'android.permission.ACCESS_WIFI_STATE'
:
return
{
name
:
'设备状态权限'
,
message
:
'允许访问设备状态,便于收集应用异常信息。'
,
}
case
'android.permission.ACCESS_COARSE_LOCATION'
:
case
'android.permission.ACCESS_FINE_LOCATION'
:
case
'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS'
:
case
'android.permission.ACCESS_MOCK_LOCATION'
:
return
{
name
:
'位置权限'
,
message
:
'允许访问位置信息,便于确认上传随手拍问题时的所在位置。'
,
}
case
'android.permission.INSTALL_PACKAGES'
:
case
'android.permission.REQUEST_INSTALL_PACKAGES'
:
return
{
name
:
'安装应用权限'
,
message
:
'允许访问安装应用,便于应用更新包的安装。'
,
}
}
}
export
function
usePermissions
():
Permissions
{
const
system
=
uni
.
getSystemInfoSync
()
const
listener
=
ref
<
RequestPermissionListener
>
()
const
requestPermissionId
=
ref
<
string
>
()
const
show
=
ref
(
false
)
const
debounceShow
=
debounce
((
value
)
=>
{
show
.
value
=
value
},
200
)
watch
(
()
=>
show
.
value
,
(
value
)
=>
{
const
id
=
requestPermissionId
.
value
if
(
value
)
{
const
statusBarHeight
=
system
.
statusBarHeight
const
navigationBarHeight
=
system
.
platform
===
'android'
?
48
:
44
const
totalHeight
=
statusBarHeight
+
navigationBarHeight
let
view
=
new
plus
.
nativeObj
.
View
(
id
,
{
top
:
'0px'
,
left
:
'0px'
,
width
:
'100%'
,
backgroundColor
:
'rgba(0,0,0,0.3)'
,
})
view
.
drawRect
(
{
color
:
'#fff'
,
radius
:
'5px'
,
},
{
top
:
`
${
totalHeight
}
px`
,
left
:
'5%'
,
width
:
'90%'
,
height
:
'100px'
,
},
)
view
.
drawText
(
'权限使用说明'
,
{
top
:
`
${
totalHeight
+
5
}
px`
,
left
:
'8%'
,
height
:
'30px'
,
},
{
align
:
'left'
,
color
:
'#000'
,
size
:
'20px'
,
},
)
view
.
drawText
(
getRequestPermissionTipMessage
(
id
)?.
message
,
{
top
:
`
${
totalHeight
+
35
}
px`
,
height
:
'60px'
,
left
:
'8%'
,
width
:
'84%'
,
},
{
whiteSpace
:
'normal'
,
size
:
'14px'
,
align
:
'left'
,
color
:
'#656563'
,
},
)
view
.
show
()
view
=
null
}
else
{
// @ts-expect-error
let
view
=
plus
.
nativeObj
.
View
.
getViewById
(
id
)
view
&&
view
.
close
()
view
=
null
requestPermissionId
.
value
=
null
}
},
)
function
listen
()
{
// #ifdef APP-PLUS
// FIXED: 由于 iOS 下无问题,此处仅处理安卓平台的权限申请问题
if
(
system
.
platform
===
'android'
)
{
// @ts-expect-error
listener
.
value
=
uni
.
createRequestPermissionListener
()
listener
.
value
.
onConfirm
((
e
:
string
[])
=>
{
console
.
log
(
'onConfirm'
,
e
)
// 创建弹窗视图
requestPermissionId
.
value
=
e
[
0
]
debounceShow
(
true
)
})
listener
.
value
.
onComplete
((
e
:
string
[])
=>
{
console
.
log
(
'onComplete'
,
e
)
// 关闭弹窗视图
const
id
=
e
[
0
]
// 判断是否触发了对应的权限显示
if
(
requestPermissionId
.
value
!==
id
&&
Storage
.
get
(
id
)
!==
'granted'
)
{
if
(
Storage
.
get
(
id
)
===
'denied'
)
{
handlerPermissionModal
(
id
)
}
else
{
plus
.
android
.
requestPermissions
(
e
,
(
v
)
=>
{
console
.
log
(
'requestPermissions'
,
e
,
v
)
if
(
v
.
granted
.
includes
(
id
))
{
Storage
.
set
(
id
,
'granted'
)
}
if
(
v
.
deniedAlways
.
includes
(
id
))
{
Storage
.
set
(
id
,
'denied'
)
handlerPermissionModal
(
id
)
}
})
}
}
else
{
requestPermissionId
.
value
=
id
debounceShow
(
false
)
}
})
console
.
log
(
'[usePermissions] start listen...'
)
}
// #endif
}
function
stop
()
{
// #ifdef APP-PLUS
listener
.
value
?.
stop
()
// 清除权限标记,防止用户主动设置了权限允许重新打开仍然无法使用的问题
Storage
.
keys
().
forEach
((
key
)
=>
{
if
(
key
.
startsWith
(
'android.permission.'
))
{
Storage
.
remove
(
key
)
}
})
console
.
log
(
'[usePermissions] stop listen'
)
// #endif
}
// 权限设置弹窗
const
settingConfirmVisible
=
ref
(
false
)
function
handlerPermissionModal
(
id
:
string
)
{
if
(
settingConfirmVisible
.
value
)
{
return
}
settingConfirmVisible
.
value
=
true
Message
.
confirm
(
`缺少
${
getRequestPermissionTipMessage
(
id
).
name
}
,立即去设置开启?`
,
'温馨提示'
,
'去设置'
).
then
(
(
confirm
)
=>
{
settingConfirmVisible
.
value
=
false
if
(
confirm
)
{
try
{
Storage
.
remove
(
id
)
gotoAppPermissionSetting
()
}
catch
(
e
)
{
console
.
error
(
'[Permissions] gotoAppPermissionSetting fail!'
,
e
)
}
}
},
)
}
// 跳转到 APP 权限设置
function
gotoAppPermissionSetting
()
{
// #ifdef APP-PLUS
if
(
system
.
platform
===
'ios'
)
{
const
UIApplication
=
plus
.
ios
.
importClass
(
'UIApplication'
)
const
application
=
UIApplication
.
sharedApplication
()
const
NSURL
=
plus
.
ios
.
importClass
(
'NSURL'
)
const
setting
=
NSURL
.
URLWithString
(
'app-settings:'
)
application
.
openURL
(
setting
)
plus
.
ios
.
deleteObject
(
setting
)
plus
.
ios
.
deleteObject
(
NSURL
)
plus
.
ios
.
deleteObject
(
application
)
}
else
{
// console.log(plus.device.vendor);
const
Intent
=
plus
.
android
.
importClass
(
'android.content.Intent'
)
const
Settings
=
plus
.
android
.
importClass
(
'android.provider.Settings'
)
const
Uri
=
plus
.
android
.
importClass
(
'android.net.Uri'
)
const
mainActivity
=
plus
.
android
.
runtimeMainActivity
()
// @ts-expect-error
const
intent
=
new
Intent
()
// @ts-expect-error
intent
.
setAction
(
Settings
.
ACTION_APPLICATION_DETAILS_SETTINGS
)
// @ts-expect-error
const
uri
=
Uri
.
fromParts
(
'package'
,
mainActivity
.
getPackageName
(),
null
)
intent
.
setData
(
uri
)
// @ts-expect-error
mainActivity
.
startActivity
(
intent
)
}
// #endif
}
return
{
listen
,
stop
,
gotoAppPermissionSetting
,
}
}
src/manifest.json
浏览文件 @
edbd7400
{
"name"
:
"Beta App"
,
"appid"
:
"__UNI__2E9441A"
,
"description"
:
"APP 基础工程"
,
"versionName"
:
"1.0.1"
,
"versionCode"
:
10001
,
"transformPx"
:
false
,
"locale"
:
"zh-Hans"
,
"vueVersion"
:
"3"
,
"name"
:
"Beta App"
,
"appid"
:
"__UNI__2E9441A"
,
"description"
:
"APP 基础工程"
,
"versionName"
:
"1.0.1"
,
"versionCode"
:
10001
,
"transformPx"
:
false
,
"locale"
:
"zh-Hans"
,
"vueVersion"
:
"3"
,
/*
5
+App特有相关
*///
配置文件详细说明
//
https
:
//uniapp.dcloud.net.cn/collocation/manifest-app.html#full-manifest
"app-plus"
:
{
"usingComponents"
:
true
,
"nvueStyleCompiler"
:
"uni-app"
,
"compilerVersion"
:
3
,
"splashscreen"
:
{
"alwaysShowBeforeRender"
:
false
,
"autoclose"
:
false
,
"waiting"
:
true
},
"screenOrientation"
:
[
"portrait-primary"
,
"landscape-primary"
],
"compatible"
:
{
"app-plus"
:
{
"usingComponents"
:
true
,
"nvueCompiler"
:
"uni-app"
,
"nvueStyleCompiler"
:
"uni-app"
,
"nvueLaunchMode"
:
"fast"
,
"compilerVersion"
:
3
,
"splashscreen"
:
{
"alwaysShowBeforeRender"
:
false
,
"autoclose"
:
false
,
"waiting"
:
true
},
"screenOrientation"
:
[
"portrait-primary"
,
"landscape-primary"
],
"compatible"
:
{
//
忽略版本提示
"ignoreVersion"
:
true
"ignoreVersion"
:
true
},
/*
模块配置
*/
"modules"
:
{
"Geolocation"
:
{},
"Camera"
:
{}
"modules"
:
{
"Geolocation"
:
{},
"Camera"
:
{}
},
/*
应用发布信息
*/
"distribute"
:
{
"distribute"
:
{
/*
android打包配置
*/
"android"
:
{
"permissions"
:
[
"android"
:
{
"permissions"
:
[
"<uses-permission android:name=
\"
android.permission.CHANGE_NETWORK_STATE
\"
/>"
,
"<uses-permission android:name=
\"
android.permission.MOUNT_UNMOUNT_FILESYSTEMS
\"
/>"
,
"<uses-permission android:name=
\"
android.permission.VIBRATE
\"
/>"
,
...
...
@@ -49,94 +51,97 @@
"<uses-feature android:name=
\"
android.hardware.camera
\"
/>"
,
"<uses-permission android:name=
\"
android.permission.WRITE_SETTINGS
\"
/>"
],
"permissionPhoneState"
:
{
"permissionPhoneState"
:
{
//
app首次启动关闭权限申请
"request"
:
"none"
}
"request"
:
"none"
},
"minSdkVersion"
:
23
,
"targetSdkVersion"
:
30
,
"abiFilters"
:
[
"armeabi-v7a"
,
"arm64-v8a"
]
},
/*
ios打包配置
*/
"ios"
:
{
"dSYMs"
:
false
,
"privacyDescription"
:
{
"NSUserTrackingUsageDescription"
:
"请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验"
,
"NSLocationAlwaysAndWhenInUseUsageDescription"
:
"该应用需要你的地理位置,以便检查你当前位置信息"
,
"NSLocationAlwaysUsageDescription"
:
"该应用需要你的地理位置,以便检查你当前位置信息"
,
"NSLocationWhenInUseUsageDescription"
:
"该应用需要你的地理位置,以便检查你当前位置信息"
,
"NSPhotoLibraryUsageDescription"
:
"请允许访问您的照片图库,以便能够上传应用异常问题的截图"
"ios"
:
{
"dSYMs"
:
false
,
"privacyDescription"
:
{
"NSUserTrackingUsageDescription"
:
"请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验"
,
"NSLocationAlwaysAndWhenInUseUsageDescription"
:
"该应用需要你的地理位置,以便检查你当前位置信息"
,
"NSLocationAlwaysUsageDescription"
:
"该应用需要你的地理位置,以便检查你当前位置信息"
,
"NSLocationWhenInUseUsageDescription"
:
"该应用需要你的地理位置,以便检查你当前位置信息"
,
"NSPhotoLibraryUsageDescription"
:
"请允许访问您的照片图库,以便能够上传应用异常问题的截图"
}
},
/*
SDK配置
*/
"sdkConfigs"
:
{
"ad"
:
{},
"statics"
:
{},
"geolocation"
:
{
"system"
:
{
"__platform__"
:
[
"ios"
,
"android"
]
"sdkConfigs"
:
{
"ad"
:
{},
"statics"
:
{},
"geolocation"
:
{
"system"
:
{
"__platform__"
:
[
"ios"
,
"android"
]
}
}
},
"icons"
:
{
"android"
:
{
"hdpi"
:
"unpackage/res/icons/72x72.png"
,
"xhdpi"
:
"unpackage/res/icons/96x96.png"
,
"xxhdpi"
:
"unpackage/res/icons/144x144.png"
,
"xxxhdpi"
:
"unpackage/res/icons/192x192.png"
},
"ios"
:
{
"appstore"
:
"unpackage/res/icons/1024x1024.png"
,
"ipad"
:
{
"app"
:
"unpackage/res/icons/76x76.png"
,
"app@2x"
:
"unpackage/res/icons/152x152.png"
,
"notification"
:
"unpackage/res/icons/20x20.png"
,
"notification@2x"
:
"unpackage/res/icons/40x40.png"
,
"proapp@2x"
:
"unpackage/res/icons/167x167.png"
,
"settings"
:
"unpackage/res/icons/29x29.png"
,
"settings@2x"
:
"unpackage/res/icons/58x58.png"
,
"spotlight"
:
"unpackage/res/icons/40x40.png"
,
"spotlight@2x"
:
"unpackage/res/icons/80x80.png"
},
"iphone"
:
{
"app@2x"
:
"unpackage/res/icons/120x120.png"
,
"app@3x"
:
"unpackage/res/icons/180x180.png"
,
"notification@2x"
:
"unpackage/res/icons/40x40.png"
,
"notification@3x"
:
"unpackage/res/icons/60x60.png"
,
"settings@2x"
:
"unpackage/res/icons/58x58.png"
,
"settings@3x"
:
"unpackage/res/icons/87x87.png"
,
"spotlight@2x"
:
"unpackage/res/icons/80x80.png"
,
"spotlight@3x"
:
"unpackage/res/icons/120x120.png"
"icons"
:
{
"android"
:
{
"hdpi"
:
"unpackage/res/icons/72x72.png"
,
"xhdpi"
:
"unpackage/res/icons/96x96.png"
,
"xxhdpi"
:
"unpackage/res/icons/144x144.png"
,
"xxxhdpi"
:
"unpackage/res/icons/192x192.png"
},
"ios"
:
{
"appstore"
:
"unpackage/res/icons/1024x1024.png"
,
"ipad"
:
{
"app"
:
"unpackage/res/icons/76x76.png"
,
"app@2x"
:
"unpackage/res/icons/152x152.png"
,
"notification"
:
"unpackage/res/icons/20x20.png"
,
"notification@2x"
:
"unpackage/res/icons/40x40.png"
,
"proapp@2x"
:
"unpackage/res/icons/167x167.png"
,
"settings"
:
"unpackage/res/icons/29x29.png"
,
"settings@2x"
:
"unpackage/res/icons/58x58.png"
,
"spotlight"
:
"unpackage/res/icons/40x40.png"
,
"spotlight@2x"
:
"unpackage/res/icons/80x80.png"
},
"iphone"
:
{
"app@2x"
:
"unpackage/res/icons/120x120.png"
,
"app@3x"
:
"unpackage/res/icons/180x180.png"
,
"notification@2x"
:
"unpackage/res/icons/40x40.png"
,
"notification@3x"
:
"unpackage/res/icons/60x60.png"
,
"settings@2x"
:
"unpackage/res/icons/58x58.png"
,
"settings@3x"
:
"unpackage/res/icons/87x87.png"
,
"spotlight@2x"
:
"unpackage/res/icons/80x80.png"
,
"spotlight@3x"
:
"unpackage/res/icons/120x120.png"
}
}
},
"splashscreen"
:
{
"useOriginalMsgbox"
:
true
"splashscreen"
:
{
"useOriginalMsgbox"
:
true
}
},
"uniStatistics"
:
{
"enable"
:
true
"uniStatistics"
:
{
"enable"
:
true
}
},
"uniStatistics"
:
{
"enable"
:
true
,
"version"
:
"2"
,
"debug"
:
true
"uniStatistics"
:
{
"enable"
:
true
,
"version"
:
"2"
,
"debug"
:
true
},
/*
快应用特有相关
*/
"quickapp"
:
{},
"quickapp"
:
{},
/*
小程序特有相关
*/
"mp-weixin"
:
{
"appid"
:
""
,
"setting"
:
{
"urlCheck"
:
false
"mp-weixin"
:
{
"appid"
:
""
,
"setting"
:
{
"urlCheck"
:
false
},
"usingComponents"
:
true
"usingComponents"
:
true
},
"mp-alipay"
:
{
"usingComponents"
:
true
"mp-alipay"
:
{
"usingComponents"
:
true
},
"mp-baidu"
:
{
"usingComponents"
:
true
"mp-baidu"
:
{
"usingComponents"
:
true
},
"mp-toutiao"
:
{
"usingComponents"
:
true
"mp-toutiao"
:
{
"usingComponents"
:
true
}
}
types/app.d.ts
浏览文件 @
edbd7400
/**
* App 信息
*/
type
Application
=
{
interface
Application
{
/**
* 应用名称
*/
appName
:
string
/**
* 项目名称
*/
...
...
@@ -31,7 +36,7 @@ type Application = {
/**
* App 作者信息
*/
type
Author
=
{
interface
Author
{
/**
* 作者名称
*/
...
...
vite.config.ts
浏览文件 @
edbd7400
...
...
@@ -45,6 +45,7 @@ export default ({ mode }: ConfigEnv): UserConfig => {
},
define
:
{
__APP__
:
{
appName
:
pkg
.
appName
||
pkg
.
description
,
name
:
pkg
.
name
,
version
:
pkg
.
version
,
description
:
pkg
.
description
,
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论