index.uts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
  2. import { Permissions, PermissionRequestResult as AtManagerPermissionResult } from '@ohos.abilityAccessCtrl'
  3. import { BusinessError } from '@ohos.base'
  4. import common from '@ohos.app.ability.common'
  5. import Want from '@ohos.app.ability.Want'
  6. import access from '@ohos.bluetooth.access'
  7. import bundleManager from '@ohos.bundle.bundleManager'
  8. import {
  9. BluetoothDemoInfo,
  10. CheckPermission,
  11. CheckPermissionOptions,
  12. CheckPermissions,
  13. CheckPermissionsOptions,
  14. CheckPermissionsResult,
  15. CheckPermissionsSync,
  16. CheckPermissionSync,
  17. GetSupportedPermissionsResult,
  18. GetSupportedPermissionsSync,
  19. GetBluetoothDemoInfoSync,
  20. OpenAppSettings,
  21. OpenAppSettingsOptions,
  22. PermissionCheckResult,
  23. PermissionGrantResult,
  24. PermissionKey,
  25. PermissionStatus,
  26. RequestPermission,
  27. RequestPermissionOptions,
  28. RequestPermissions,
  29. RequestPermissionsOptions,
  30. RequestPermissionsResult,
  31. } from '../interface.uts'
  32. import { PermissionFailImpl } from '../unierror'
  33. const SUPPORTED_PERMISSIONS : PermissionKey[] = [
  34. 'camera',
  35. 'photoLibrary',
  36. 'storage',
  37. 'readStorage',
  38. 'location',
  39. 'coarseLocation',
  40. 'microphone',
  41. 'contacts',
  42. 'writeContacts',
  43. 'bluetooth',
  44. ]
  45. /** 鸿蒙无对应系统能力的权限(Android 专属等) */
  46. const HARMONY_UNSUPPORTED : PermissionKey[] = [
  47. 'phone',
  48. 'phoneState',
  49. 'sms',
  50. 'readSms',
  51. 'receiveSms',
  52. 'overlay',
  53. 'writeSettings',
  54. ]
  55. function createCheckResult(permission : PermissionKey, status : PermissionStatus) : PermissionCheckResult {
  56. return {
  57. permission: permission,
  58. status: status,
  59. granted: status == 'granted',
  60. }
  61. }
  62. function createGrantResult(permission : PermissionKey, status : PermissionStatus) : PermissionGrantResult {
  63. return {
  64. permission: permission,
  65. status: status,
  66. granted: status == 'granted',
  67. }
  68. }
  69. /** 需在 module.json5 声明且 ACL 签名的权限 */
  70. const HARMONY_ACL_PERMISSION_KEYS : PermissionKey[] = [
  71. 'photoLibrary',
  72. 'readStorage',
  73. 'storage',
  74. 'contacts',
  75. 'writeContacts',
  76. ]
  77. function isHarmonyAclPermission(permission : PermissionKey) : boolean {
  78. for (let i = 0; i < HARMONY_ACL_PERMISSION_KEYS.length; i++) {
  79. if (HARMONY_ACL_PERMISSION_KEYS[i] == permission) {
  80. return true
  81. }
  82. }
  83. return false
  84. }
  85. function isHarmonyPermissionDeclared(harmonyPermission : Permissions) : boolean {
  86. try {
  87. const bundleInfo = bundleManager.getBundleInfoForSelfSync(
  88. bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION,
  89. )
  90. const declared = bundleInfo.reqPermissionDetails
  91. for (let i = 0; i < declared.length; i++) {
  92. const item = declared[i]
  93. if (item.name == harmonyPermission) {
  94. return true
  95. }
  96. }
  97. return false
  98. } catch (ignored) {
  99. return false
  100. }
  101. }
  102. function createAclUndeclaredMessage(permission : PermissionKey) : string {
  103. if (permission == 'photoLibrary' || permission == 'readStorage' || permission == 'storage') {
  104. return '当前包未声明相册/媒体权限,系统设置无对应开关。选图请用系统相册选择器;完整权限需 module.full.json5 + ACL'
  105. }
  106. return '当前包未声明该权限,系统设置无对应开关。请使用 module.full.json5 并配置 ACL 后重签安装'
  107. }
  108. function isHarmonyAclUndeclared(permission : PermissionKey) : boolean {
  109. if (!isHarmonyAclPermission(permission)) {
  110. return false
  111. }
  112. const harmonyPermission = resolveHarmonyPermission(permission)
  113. if (harmonyPermission == null) {
  114. return false
  115. }
  116. return !isHarmonyPermissionDeclared(harmonyPermission)
  117. }
  118. function isHarmonyUnsupported(permission : PermissionKey) : boolean {
  119. for (let i = 0; i < HARMONY_UNSUPPORTED.length; i++) {
  120. if (HARMONY_UNSUPPORTED[i] == permission) {
  121. return true
  122. }
  123. }
  124. return false
  125. }
  126. function resolveHarmonyPermission(permission : PermissionKey) : Permissions | null {
  127. switch (permission) {
  128. case 'camera':
  129. return 'ohos.permission.CAMERA'
  130. case 'photoLibrary':
  131. case 'readStorage':
  132. return 'ohos.permission.READ_IMAGEVIDEO'
  133. case 'storage':
  134. return 'ohos.permission.WRITE_IMAGEVIDEO'
  135. case 'location':
  136. return 'ohos.permission.LOCATION'
  137. case 'coarseLocation':
  138. return 'ohos.permission.APPROXIMATELY_LOCATION'
  139. case 'microphone':
  140. return 'ohos.permission.MICROPHONE'
  141. case 'contacts':
  142. return 'ohos.permission.READ_CONTACTS'
  143. case 'writeContacts':
  144. return 'ohos.permission.WRITE_CONTACTS'
  145. case 'bluetooth':
  146. return 'ohos.permission.ACCESS_BLUETOOTH'
  147. default:
  148. return null
  149. }
  150. }
  151. function getAbilityContext() : common.UIAbilityContext | null {
  152. try {
  153. return getContext() as common.UIAbilityContext
  154. } catch (ignored) {
  155. return null
  156. }
  157. }
  158. function checkHarmonyPermissionStatus(permission : PermissionKey) : PermissionStatus {
  159. if (isHarmonyUnsupported(permission)) {
  160. return 'unsupported'
  161. }
  162. const harmonyPermission = resolveHarmonyPermission(permission)
  163. if (harmonyPermission == null) {
  164. return 'unsupported'
  165. }
  166. if (isHarmonyAclUndeclared(permission)) {
  167. return 'restricted'
  168. }
  169. const context = getAbilityContext()
  170. if (context == null) {
  171. return 'denied'
  172. }
  173. const atManager = abilityAccessCtrl.createAtManager()
  174. const tokenId = context.applicationInfo.accessTokenId
  175. const status = atManager.checkAccessTokenSync(tokenId, harmonyPermission)
  176. if (status == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
  177. return 'granted'
  178. }
  179. return 'notDetermined'
  180. }
  181. function succeedCheckPermission(options : CheckPermissionOptions, res : PermissionCheckResult) {
  182. const successCallback = options.success
  183. if (successCallback != null) {
  184. successCallback(res)
  185. }
  186. const completeCallback = options.complete
  187. if (completeCallback != null) {
  188. completeCallback(res)
  189. }
  190. }
  191. function succeedCheckPermissions(options : CheckPermissionsOptions, res : CheckPermissionsResult) {
  192. const successCallback = options.success
  193. if (successCallback != null) {
  194. successCallback(res)
  195. }
  196. const completeCallback = options.complete
  197. if (completeCallback != null) {
  198. completeCallback(res)
  199. }
  200. }
  201. function succeedRequestPermission(options : RequestPermissionOptions, res : PermissionGrantResult) {
  202. const successCallback = options.success
  203. if (successCallback != null) {
  204. successCallback(res)
  205. }
  206. const completeCallback = options.complete
  207. if (completeCallback != null) {
  208. completeCallback(res)
  209. }
  210. }
  211. function succeedRequestPermissions(options : RequestPermissionsOptions, res : RequestPermissionsResult) {
  212. const successCallback = options.success
  213. if (successCallback != null) {
  214. successCallback(res)
  215. }
  216. const completeCallback = options.complete
  217. if (completeCallback != null) {
  218. completeCallback(res)
  219. }
  220. }
  221. function failRequestPermission(options : RequestPermissionOptions, err : PermissionFailImpl) {
  222. const failCallback = options.fail
  223. if (failCallback != null) {
  224. failCallback(err)
  225. }
  226. const completeCallback = options.complete
  227. if (completeCallback != null) {
  228. completeCallback(err)
  229. }
  230. }
  231. function failRequestPermissions(options : RequestPermissionsOptions, err : PermissionFailImpl) {
  232. const failCallback = options.fail
  233. if (failCallback != null) {
  234. failCallback(err)
  235. }
  236. const completeCallback = options.complete
  237. if (completeCallback != null) {
  238. completeCallback(err)
  239. }
  240. }
  241. function failOpenAppSettings(options : OpenAppSettingsOptions, err : PermissionFailImpl) {
  242. const failCallback = options.fail
  243. if (failCallback != null) {
  244. failCallback(err)
  245. }
  246. const completeCallback = options.complete
  247. if (completeCallback != null) {
  248. completeCallback(err)
  249. }
  250. }
  251. function succeedOpenAppSettings(options : OpenAppSettingsOptions, res : PermissionCheckResult) {
  252. const successCallback = options.success
  253. if (successCallback != null) {
  254. successCallback(res)
  255. }
  256. const completeCallback = options.complete
  257. if (completeCallback != null) {
  258. completeCallback(res)
  259. }
  260. }
  261. export const checkPermissionSync : CheckPermissionSync = function (permission : PermissionKey) : PermissionCheckResult {
  262. return createCheckResult(permission, checkHarmonyPermissionStatus(permission))
  263. }
  264. export const checkPermissionsSync : CheckPermissionsSync = function (permissions : PermissionKey[]) : CheckPermissionsResult {
  265. const results : PermissionCheckResult[] = []
  266. let allGranted = true
  267. for (let i = 0; i < permissions.length; i++) {
  268. const item = checkPermissionSync(permissions[i])
  269. results.push(item)
  270. if (!item.granted) {
  271. allGranted = false
  272. }
  273. }
  274. return {
  275. results: results,
  276. allGranted: allGranted,
  277. }
  278. }
  279. export const checkPermission : CheckPermission = function (options : CheckPermissionOptions) {
  280. succeedCheckPermission(options, checkPermissionSync(options.permission))
  281. }
  282. export const checkPermissions : CheckPermissions = function (options : CheckPermissionsOptions) {
  283. succeedCheckPermissions(options, checkPermissionsSync(options.permissions))
  284. }
  285. export const requestPermission : RequestPermission = function (options : RequestPermissionOptions) {
  286. if (isHarmonyUnsupported(options.permission)) {
  287. failRequestPermission(options, new PermissionFailImpl(9020003))
  288. return
  289. }
  290. if (isHarmonyAclUndeclared(options.permission)) {
  291. failRequestPermission(options, new PermissionFailImpl(9020003, createAclUndeclaredMessage(options.permission)))
  292. return
  293. }
  294. const currentStatus = checkHarmonyPermissionStatus(options.permission)
  295. if (currentStatus == 'granted') {
  296. succeedRequestPermission(options, createGrantResult(options.permission, 'granted'))
  297. return
  298. }
  299. const harmonyPermission = resolveHarmonyPermission(options.permission)
  300. if (harmonyPermission == null) {
  301. failRequestPermission(options, new PermissionFailImpl(9020003))
  302. return
  303. }
  304. const context = getAbilityContext()
  305. if (context == null) {
  306. failRequestPermission(options, new PermissionFailImpl(9020006, 'UIAbilityContext 不可用'))
  307. return
  308. }
  309. const atManager = abilityAccessCtrl.createAtManager()
  310. const permissionList : Array<Permissions> = [harmonyPermission]
  311. atManager.requestPermissionsFromUser(context, permissionList,
  312. (err : BusinessError, result : AtManagerPermissionResult) => {
  313. if (err != null) {
  314. succeedRequestPermission(options, createGrantResult(options.permission, 'denied'))
  315. return
  316. }
  317. if (result.authResults.length > 0
  318. && result.authResults[0] == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
  319. succeedRequestPermission(options, createGrantResult(options.permission, 'granted'))
  320. return
  321. }
  322. succeedRequestPermission(options, createGrantResult(options.permission, 'denied'))
  323. })
  324. }
  325. export const requestPermissions : RequestPermissions = function (options : RequestPermissionsOptions) {
  326. const permissions = options.permissions
  327. if (permissions.length == 0) {
  328. const emptyResult : RequestPermissionsResult = {
  329. results: [],
  330. allGranted: true,
  331. }
  332. succeedRequestPermissions(options, emptyResult)
  333. return
  334. }
  335. const context = getAbilityContext()
  336. if (context == null) {
  337. failRequestPermissions(options, new PermissionFailImpl(9020006, 'UIAbilityContext 不可用'))
  338. return
  339. }
  340. const harmonyPermissions : Array<Permissions> = []
  341. const permissionKeys : PermissionKey[] = []
  342. for (let i = 0; i < permissions.length; i++) {
  343. const key = permissions[i]
  344. if (isHarmonyUnsupported(key)) {
  345. continue
  346. }
  347. const harmonyPermission = resolveHarmonyPermission(key)
  348. if (harmonyPermission != null) {
  349. harmonyPermissions.push(harmonyPermission)
  350. permissionKeys.push(key)
  351. }
  352. }
  353. if (harmonyPermissions.length == 0) {
  354. failRequestPermissions(options, new PermissionFailImpl(9020003))
  355. return
  356. }
  357. const atManager = abilityAccessCtrl.createAtManager()
  358. atManager.requestPermissionsFromUser(context, harmonyPermissions,
  359. (err : BusinessError, result : AtManagerPermissionResult) => {
  360. const collectedResults : PermissionGrantResult[] = []
  361. let allGranted = true
  362. if (err != null) {
  363. for (let i = 0; i < permissionKeys.length; i++) {
  364. collectedResults.push(createGrantResult(permissionKeys[i], 'denied'))
  365. }
  366. allGranted = false
  367. } else {
  368. for (let i = 0; i < permissionKeys.length; i++) {
  369. const granted = i < result.authResults.length
  370. && result.authResults[i] == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED
  371. const status : PermissionStatus = granted ? 'granted' : 'denied'
  372. collectedResults.push(createGrantResult(permissionKeys[i], status))
  373. if (!granted) {
  374. allGranted = false
  375. }
  376. }
  377. }
  378. const finalResult : RequestPermissionsResult = {
  379. results: collectedResults,
  380. allGranted: allGranted,
  381. }
  382. succeedRequestPermissions(options, finalResult)
  383. })
  384. }
  385. export const openAppSettings : OpenAppSettings = function (options : OpenAppSettingsOptions) {
  386. const context = getAbilityContext()
  387. if (context == null) {
  388. failOpenAppSettings(options, new PermissionFailImpl(9020004, 'UIAbilityContext 不可用'))
  389. return
  390. }
  391. const wantInfo : Want = {
  392. bundleName: 'com.huawei.hmos.settings',
  393. abilityName: 'com.huawei.hmos.settings.MainAbility',
  394. uri: 'application_info_entry',
  395. parameters: {
  396. pushParams: context.abilityInfo.bundleName,
  397. },
  398. }
  399. context.startAbility(wantInfo).then(() => {
  400. const resultPermission = options.permission != null ? options.permission! : 'camera'
  401. succeedOpenAppSettings(options, createCheckResult(resultPermission, 'granted'))
  402. }).catch((_err : BusinessError) => {
  403. failOpenAppSettings(options, new PermissionFailImpl(9020004))
  404. })
  405. }
  406. export const getSupportedPermissionsSync : GetSupportedPermissionsSync = function () : GetSupportedPermissionsResult {
  407. return {
  408. permissions: SUPPORTED_PERMISSIONS,
  409. }
  410. }
  411. function mapHarmonyBluetoothState(state : access.BluetoothState) : string {
  412. switch (state) {
  413. case access.BluetoothState.STATE_OFF:
  414. return '已关闭'
  415. case access.BluetoothState.STATE_TURNING_ON:
  416. return '正在打开'
  417. case access.BluetoothState.STATE_ON:
  418. return '已开启'
  419. case access.BluetoothState.STATE_TURNING_OFF:
  420. return '正在关闭'
  421. case access.BluetoothState.STATE_BLE_TURNING_ON:
  422. return 'BLE 正在打开'
  423. case access.BluetoothState.STATE_BLE_ON:
  424. return 'BLE 已开启'
  425. case access.BluetoothState.STATE_BLE_TURNING_OFF:
  426. return 'BLE 正在关闭'
  427. default:
  428. return '未知'
  429. }
  430. }
  431. function isHarmonyBluetoothEnabled(state : access.BluetoothState) : boolean {
  432. return state == access.BluetoothState.STATE_ON
  433. || state == access.BluetoothState.STATE_BLE_ON
  434. }
  435. export const getBluetoothDemoInfoSync : GetBluetoothDemoInfoSync = function () : BluetoothDemoInfo {
  436. try {
  437. const state = access.getState()
  438. return {
  439. available: true,
  440. enabled: isHarmonyBluetoothEnabled(state),
  441. stateText: mapHarmonyBluetoothState(state),
  442. stateCode: state as number,
  443. }
  444. } catch (err) {
  445. let message = '读取蓝牙状态失败'
  446. if (err != null && typeof err === 'object') {
  447. const errObj = err as BusinessError
  448. if (errObj.message != null && errObj.message.length > 0) {
  449. message = errObj.message
  450. }
  451. }
  452. return {
  453. available: false,
  454. enabled: false,
  455. stateText: message,
  456. stateCode: -1,
  457. }
  458. }
  459. }