permission.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /**
  2. * Android / iOS 权限与能力检测
  3. * Android 6+ 扫描 BLE 需要位置权限 + 位置服务开启
  4. * Android 12+ 需要 BLUETOOTH_SCAN / BLUETOOTH_CONNECT
  5. * iOS 需要 NSBluetoothAlwaysUsageDescription (在 manifest.json 中配置)
  6. *
  7. * 仅在 APP-PLUS 环境下调用 plus API, H5 / 小程序环境跳过
  8. */
  9. export function getPlatform() {
  10. try { return uni.getSystemInfoSync().platform } catch (_) { return '' }
  11. }
  12. /** 是否 App 环境 (plus 存在) */
  13. export function isAppPlus() {
  14. // #ifdef APP-PLUS
  15. return typeof plus !== 'undefined'
  16. // #endif
  17. // #ifndef APP-PLUS
  18. return false
  19. // #endif
  20. }
  21. /** 检查位置服务是否已开启 (Android) */
  22. export function isLocationEnabled() {
  23. return new Promise(resolve => {
  24. if (!isAppPlus() || getPlatform() !== 'android') return resolve(true)
  25. // #ifdef APP-PLUS
  26. try {
  27. const main = plus.android.runtimeMainActivity()
  28. const LocationManager = plus.android.importClass('android.location.LocationManager')
  29. const context = plus.android.importClass('android.content.Context')
  30. const lm = main.getSystemService(context.LOCATION_SERVICE)
  31. const gps = lm.isProviderEnabled(LocationManager.GPS_PROVIDER)
  32. const net = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
  33. resolve(gps || net)
  34. } catch (e) { resolve(true) }
  35. // #endif
  36. })
  37. }
  38. /** 跳转到系统位置服务设置 */
  39. export function openLocationSettings() {
  40. // #ifdef APP-PLUS
  41. if (!isAppPlus() || getPlatform() !== 'android') return
  42. try {
  43. const main = plus.android.runtimeMainActivity()
  44. const Intent = plus.android.importClass('android.content.Intent')
  45. const Settings = plus.android.importClass('android.provider.Settings')
  46. const intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
  47. main.startActivity(intent)
  48. } catch (e) { console.error(e) }
  49. // #endif
  50. }
  51. /** 请求 Android 运行时权限(定位/蓝牙扫描/连接). 返回 true/false */
  52. export function requestAndroidPermissions() {
  53. return new Promise(resolve => {
  54. if (!isAppPlus() || getPlatform() !== 'android') return resolve(true)
  55. // #ifdef APP-PLUS
  56. try {
  57. const main = plus.android.runtimeMainActivity()
  58. const Build = plus.android.importClass('android.os.Build')
  59. const sdkInt = Build.VERSION.SDK_INT
  60. const perms = ['android.permission.ACCESS_FINE_LOCATION']
  61. if (sdkInt >= 31) {
  62. perms.push('android.permission.BLUETOOTH_SCAN')
  63. perms.push('android.permission.BLUETOOTH_CONNECT')
  64. }
  65. const PackageManager = plus.android.importClass('android.content.pm.PackageManager')
  66. const need = perms.filter(p => main.checkSelfPermission(p) !== PackageManager.PERMISSION_GRANTED)
  67. if (!need.length) return resolve(true)
  68. const ActivityCompat = plus.android.importClass('androidx.core.app.ActivityCompat')
  69. // 注册结果回调
  70. const onReq = (activity, requestCode, permsArr, grantResults) => {
  71. plus.android.clearRequestPermissions && plus.android.clearRequestPermissions()
  72. const granted = grantResults && Array.from(grantResults).every(r => r === 0)
  73. resolve(!!granted)
  74. }
  75. if (plus.android.requestPermissions) {
  76. plus.android.requestPermissions(need, res => {
  77. resolve(res && res.granted && res.granted.length === need.length)
  78. }, () => resolve(false))
  79. } else {
  80. ActivityCompat.requestPermissions(main, need, 1001)
  81. // 无结果回调能力时, 乐观等待 2s 后查询
  82. setTimeout(() => {
  83. const still = need.filter(p => main.checkSelfPermission(p) !== PackageManager.PERMISSION_GRANTED)
  84. resolve(!still.length)
  85. }, 2000)
  86. }
  87. } catch (e) {
  88. console.error(e); resolve(false)
  89. }
  90. // #endif
  91. })
  92. }
  93. /** 一键: 申请权限 + 校验定位服务. 失败抛异常 */
  94. export async function ensureBlePrerequisite() {
  95. if (getPlatform() === 'android') {
  96. const ok = await requestAndroidPermissions()
  97. if (!ok) throw new Error('BLE_PERMISSION_DENIED')
  98. const loc = await isLocationEnabled()
  99. if (!loc) throw new Error('BLE_LOCATION_OFF')
  100. }
  101. return true
  102. }