流量统计需要申请权限。实现步骤如下:
清单文件中申请权限:
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="ProtectedPermissions" />
MainActivity中有一个按钮,点击后开始申请权限,代码如下:
class MainActivity : AppCompatActivity() {
private lateinit var launcher: ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
val isOk = it.resultCode == Activity.RESULT_OK
Log.i("ABCD", "isOk = $isOk")
if (!hasQueryTrafficStatsPermission(this)) {
Log.i("ABCD", "用户拒绝了权限")
launcher.launch(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
} else {
Log.i("ABCD", "用户给权限了")
}
}
findViewById<Button>(R.id.button).setOnClickListener {
if (hasQueryTrafficStatsPermission(this)) {
Log.i("ABCD", "已经有流量统计权限了")
} else {
Log.i("ABCD", "开始申请流量统计权限")
launcher.launch(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
}
}
}
}
/** 判断是否有流量统计权限 */
fun hasQueryTrafficStatsPermission(activity: FragmentActivity): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true // 小于API 23版本的则默认就有流量统计权限了
}
val appOps = activity.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
val mode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
appOps.unsafeCheckOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), activity.packageName)
} else {
@Suppress("DEPRECATION")
appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), activity.packageName)
}
return mode == AppOpsManager.MODE_ALLOWED
}
注:不要使用it.resultCode == Activity.RESULT_OK来判断请求权限的结果,因为它永远为false。
为了使Activity更简洁,我们把请求权限相关代码封装到工具类中,如下:
object TrafficStatsPermissionUtil {
private lateinit var launcher: ActivityResultLauncher<Intent>
private lateinit var resultCallback: () -> Unit
fun registerForActivityResult(activity: FragmentActivity) {
launcher = activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (!hasQueryTrafficStatsPermission(activity)) {
Log.i("ABCD", "用户拒绝了权限")
showDialog(activity, """本应用需要获取"使用情况访问权限"权限,请给予此权限,否则无法使用本应用""") {
launcher.launch(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
}
} else {
Log.i("ABCD", "用户给权限了")
resultCallback()
}
}
}
fun requestTrafficStatsPermission(activity: FragmentActivity, resultCallback: () -> Unit) {
this.resultCallback = resultCallback
if (hasQueryTrafficStatsPermission(activity)) {
Log.i("ABCD", "已经有流量统计权限了")
resultCallback()
} else {
Log.i("ABCD", "开始申请流量统计权限")
launcher.launch(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS))
}
}
private fun showDialog(activity: FragmentActivity, message: String, okClick: () -> Unit) {
AlertDialog.Builder(activity)
.setTitle("提示")
.setMessage(message)
.setPositiveButton("确定") { _, _ -> okClick() }
.setCancelable(false)
.show()
}
/** 判断是否有流量统计权限 */
private fun hasQueryTrafficStatsPermission(activity: FragmentActivity): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true // 小于API 23版本的则默认就有流量统计权限了
}
val appOps = activity.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
val mode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
appOps.unsafeCheckOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), activity.packageName)
} else {
@Suppress("DEPRECATION")
appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), activity.packageName)
}
return mode == AppOpsManager.MODE_ALLOWED
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
TrafficStatsPermissionUtil.registerForActivityResult(this)
findViewById<Button>(R.id.button).setOnClickListener {
TrafficStatsPermissionUtil.requestTrafficStatsPermission(this) {
Log.i("ABCD", "哈哈哈,拿到流量统计权限了^_^")
}
}
}
}