api

  1. checkPermission :检测权限是否授予
  2. isOpenGPS :是否打开gps
  3. isNotifyEnabled :获取是否有通知权限
  4. isNotifyEnabled2 :获取是否有通知权限
  5. startSetting :跳转设置(应用信息),会开启一个新的进程(点回退会回到桌面),使用startActivityForResult不可靠,跳转就会触发onActivityResult
  6. startSettingActivity:打开设置页面(应用信息),和App在同一个进程
  7. startNotifySetting :跳转到通知设置界面

utils

  1. package com.kiwilss.lutils.utils.permission
  2. import android.annotation.SuppressLint
  3. import android.app.Activity
  4. import android.app.AppOpsManager
  5. import android.app.NotificationManager
  6. import android.content.Context
  7. import android.content.Intent
  8. import android.content.pm.ApplicationInfo
  9. import android.content.pm.PackageManager
  10. import android.location.LocationManager
  11. import android.net.Uri
  12. import android.os.Build
  13. import android.provider.Settings
  14. import androidx.core.app.NotificationManagerCompat
  15. import androidx.core.content.ContextCompat
  16. import androidx.fragment.app.Fragment
  17. import java.lang.reflect.Field
  18. import java.lang.reflect.Method
  19. /**
  20. *@author kiwilss
  21. * @email kiwilss@163.com
  22. * @time 2022/7/1
  23. * @desc {权限相关工具类}
  24. */
  25. object PermissionUtils {
  26. const val SETTING_REQUESTCODE = 6666
  27. private const val CHECK_OP_NO_THROW = "checkOpNoThrow"
  28. private const val OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION"
  29. /**
  30. * 检测是否有权限
  31. * @param context
  32. * @param permissions
  33. * @return
  34. */
  35. fun checkPermission(context: Context?, vararg permissions: String?): Boolean {
  36. if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
  37. return true
  38. } else {
  39. if (context == null || permissions.isEmpty()) return false
  40. for (permisson in permissions) {
  41. permisson?.run {
  42. if (ContextCompat.checkSelfPermission(
  43. context,
  44. this
  45. ) != PackageManager.PERMISSION_GRANTED
  46. ) {
  47. return false
  48. }
  49. }
  50. }
  51. }
  52. return true
  53. }
  54. /**
  55. * 判断GPS是否开启,GPS或者AGPS开启一个就认为是开启的
  56. *
  57. * @param context
  58. * @return true 表示开启
  59. */
  60. fun isOpenGPS(context: Context?): Boolean {
  61. if (context == null) return false
  62. val locationManager: LocationManager =
  63. context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
  64. // 通过GPS卫星定位,定位级别可以精确到街(通过24颗卫星定位,在室外和空旷的地方定位准确、速度快)
  65. var gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
  66. // 通过WLAN或移动网络(3G/2G)确定的位置(也称作AGPS,辅助GPS定位。主要用于在室内或遮盖物(建筑群或茂密的深林等)密集的地方定位)
  67. // boolean network = false;
  68. // if (locationManager != null) {
  69. // network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
  70. // }
  71. return gps
  72. }
  73. /**
  74. * 跳转设置(应用信息),会开启一个新的进程(点回退会回到桌面),使用startActivityForResult不可靠,跳转就会触发onActivityResult
  75. *
  76. * @param context
  77. */
  78. fun startSetting(context: Context?) {
  79. context?.run {
  80. try {
  81. val intent = Intent()
  82. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
  83. intent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"
  84. intent.data = Uri.fromParts("package", packageName, null)
  85. startActivity(intent)
  86. } catch (e: Exception) {
  87. e.printStackTrace()
  88. }
  89. }
  90. }
  91. /**
  92. * 打开设置页面(应用信息),和App在同一个进程
  93. *
  94. * @param context
  95. */
  96. fun startSettingActivity(context: Activity?, requestCode: Int = SETTING_REQUESTCODE) {
  97. if (context == null) return
  98. try {
  99. val intent = Intent(
  100. Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse(
  101. "package:" +
  102. context.packageName
  103. )
  104. )
  105. intent.addCategory(Intent.CATEGORY_DEFAULT)
  106. context.startActivityForResult(
  107. intent,
  108. requestCode
  109. ) //这里的requestCode和onActivityResult中requestCode要一致
  110. } catch (e: Exception) {
  111. e.printStackTrace()
  112. }
  113. }
  114. /**
  115. * 打开设置页面(应用信息),和App在同一个进程
  116. *
  117. * @param context
  118. */
  119. fun startSettingActivity(fragment: Fragment?, requestCode: Int = SETTING_REQUESTCODE) {
  120. if (fragment == null) return
  121. val context = fragment.context ?: return
  122. try {
  123. val intent = Intent(
  124. Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse(
  125. "package:" +
  126. context.packageName
  127. )
  128. )
  129. intent.addCategory(Intent.CATEGORY_DEFAULT)
  130. fragment.startActivityForResult(
  131. intent,
  132. requestCode
  133. ) //这里的requestCode和onActivityResult中requestCode要一致
  134. } catch (e: Exception) {
  135. e.printStackTrace()
  136. }
  137. }
  138. /**
  139. * 跳转到通知设置界面
  140. */
  141. @SuppressLint("ObsoleteSdkInt")
  142. fun startNotifySetting(context: Context?) {
  143. if (context == null) return
  144. // vivo 点击设置图标>加速白名单>我的app
  145. // 点击软件管理>软件管理权限>软件>我的app>信任该软件
  146. var appIntent = context.packageManager.getLaunchIntentForPackage("com.iqoo.secure")
  147. if (appIntent != null) {
  148. context.startActivity(appIntent)
  149. return
  150. }
  151. // oppo 点击设置图标>应用权限管理>按应用程序管理>我的app>我信任该应用
  152. // 点击权限隐私>自启动管理>我的app
  153. appIntent = context.packageManager.getLaunchIntentForPackage("com.oppo.safe")
  154. if (appIntent != null) {
  155. context.startActivity(appIntent)
  156. return
  157. }
  158. val intent = Intent()
  159. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  160. intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
  161. intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
  162. } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  163. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  164. intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
  165. }
  166. intent.putExtra("app_package", context.packageName)
  167. intent.putExtra("app_uid", context.applicationInfo.uid)
  168. } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
  169. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
  170. intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
  171. intent.data = Uri.fromParts("package", context.packageName, null)
  172. } else {
  173. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
  174. intent.action = Intent.ACTION_VIEW
  175. intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails")
  176. intent.putExtra("com.android.settings.ApplicationPkgName", context.packageName)
  177. }
  178. context.startActivity(intent)
  179. }
  180. /**
  181. * 获取是否有通知权限
  182. *
  183. * @param context
  184. * @return
  185. */
  186. fun isNotifyEnabled(context: Context?): Boolean {
  187. if (context == null) return false
  188. return NotificationManagerCompat.from(context).areNotificationsEnabled()
  189. }
  190. /**
  191. * 获取是否有通知权限
  192. *
  193. * @param context
  194. * @return
  195. */
  196. fun isNotifyEnabled2(context: Context): Boolean {
  197. return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  198. isEnableV26(context)
  199. } else {
  200. isEnabledV19(context)
  201. }
  202. }
  203. /**
  204. * 8.0以下判断
  205. *
  206. * @param context api19 4.4及以上判断
  207. * @return
  208. */
  209. private fun isEnabledV19(context: Context): Boolean {
  210. val mAppOps: AppOpsManager =
  211. context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
  212. val appInfo: ApplicationInfo = context.applicationInfo
  213. val pkg = context.applicationContext.packageName
  214. val uid: Int = appInfo.uid
  215. var appOpsClass: Class<*>? = null
  216. try {
  217. appOpsClass = Class.forName(AppOpsManager::class.java.name)
  218. val checkOpNoThrowMethod: Method = appOpsClass.getMethod(
  219. CHECK_OP_NO_THROW,
  220. Integer.TYPE, Integer.TYPE, String::class.java
  221. )
  222. val opPostNotificationValue: Field = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION)
  223. val value = opPostNotificationValue.get(Int::class.java) as Int
  224. return checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) as Int ===
  225. AppOpsManager.MODE_ALLOWED
  226. } catch (e: java.lang.Exception) {
  227. e.printStackTrace()
  228. }
  229. return false
  230. }
  231. /**
  232. * 8.0及以上通知权限判断
  233. *
  234. * @param context
  235. * @return
  236. */
  237. private fun isEnableV26(context: Context): Boolean {
  238. val appInfo: ApplicationInfo = context.applicationInfo
  239. val pkg = context.applicationContext.packageName
  240. val uid: Int = appInfo.uid
  241. return try {
  242. val notificationManager: NotificationManager =
  243. context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
  244. val sServiceField: Method =
  245. notificationManager.javaClass.getDeclaredMethod("getService")
  246. sServiceField.setAccessible(true)
  247. val sService: Any = sServiceField.invoke(notificationManager)
  248. val method: Method = sService.javaClass.getDeclaredMethod(
  249. "areNotificationsEnabledForPackage",
  250. String::class.java,
  251. Integer.TYPE
  252. )
  253. method.setAccessible(true)
  254. method.invoke(sService, pkg, uid) as Boolean
  255. } catch (e: java.lang.Exception) {
  256. true
  257. }
  258. }
  259. }

ktx

  1. package com.kiwilss.lutils.utils.permission
  2. import android.app.Activity
  3. import android.content.Context
  4. import androidx.fragment.app.Fragment
  5. /**
  6. *@author kiwilss
  7. * @email kiwilss@163.com
  8. * @time 2022/7/1
  9. * @desc {权限扩展工具类}
  10. */
  11. /**
  12. * 检测是否有权限
  13. *
  14. * @param permission
  15. * @return
  16. */
  17. fun Context?.checkPermission(vararg permission: String?) = PermissionUtils.checkPermission(
  18. this,
  19. *permission
  20. )
  21. /**
  22. * 是否打开gps
  23. *
  24. * @return
  25. */
  26. fun Context?.isOpenGPS() = PermissionUtils.isOpenGPS(this)
  27. /**
  28. *跳转设置(应用信息),会开启一个新的进程(点回退会回到桌面),使用startActivityForResult不可靠,跳转就会触发onActivityResult
  29. */
  30. fun Context?.startSetting() = PermissionUtils.startSetting(this)
  31. /**
  32. * 打开设置页面(应用信息),和App在同一个进程
  33. *
  34. * @param requestCode
  35. */
  36. fun Activity?.startSettingActivity(requestCode: Int = PermissionUtils.SETTING_REQUESTCODE) =
  37. PermissionUtils.startSettingActivity(this, requestCode)
  38. /**
  39. * 打开设置页面(应用信息),和App在同一个进程
  40. *
  41. * @param requestCode
  42. */
  43. fun Fragment?.startSettingActivity(requestCode: Int = PermissionUtils.SETTING_REQUESTCODE) =
  44. PermissionUtils.startSettingActivity(this, requestCode)
  45. /**
  46. *打开通知设置界面
  47. */
  48. fun Context?.startNotifySetting() = PermissionUtils.startNotifySetting(this)
  49. /**
  50. *获取通知权限是否打开
  51. */
  52. fun Context?.isNotifyEnabled() = PermissionUtils.isNotifyEnabled(this)

申请权限

  1. 申请单个权限

    1. PermissionsHelper.init(this)
    2. .requestEachPermissions(ACCESS_FINE_LOCATION, new IPermissionListenerWrap.IEachPermissionListener() {
    3. @Override
    4. public void onAccepted(Permission permission) {
    5. if (permission.granted){
    6. //同意
    7. ALog.i(LUtils.tag(this),"grant");
    8. }else if (permission.shouldShowRequestPermissionRationale){
    9. //拒绝
    10. ALog.i(LUtils.tag(this),"reject");
    11. }else {
    12. //拒绝并不再显示
    13. ALog.i(LUtils.tag(this),"reject and not show");
    14. }
    15. }
    16. });
  2. 申请多个权限

  1. PermissionsHelper.init(this)
  2. .requestPermissions(new String[]{ACCESS_FINE_LOCATION, RECORD_AUDIO}, new IPermissionListenerWrap.IPermissionListener() {
  3. @Override
  4. public void onAccepted(boolean isGranted, boolean allShould, List<String> rejects, List<String> shoulds) {
  5. if (isGranted){
  6. //全部同意
  7. ALog.i(LUtils.tag(this),"grant");
  8. }else if (allShould){
  9. //有权限不同意
  10. ALog.i(LUtils.tag(this),"reject:" + rejects);
  11. }else {
  12. //有权限不同意,并且设置了不再显示
  13. ALog.i(LUtils.tag(this),"reject and not show : " + shoulds);
  14. }
  15. }
  16. });