Helpex - Trao đổi & giúp đỡ Đăng nhập
44

Lý lịch

Tôi đang cố gắng lấy số liệu thống kê do ứng dụng khởi chạy và trên Lollipop, điều đó có thể thực hiện được bằng cách sử dụng lớp UsageStatsManager , chẳng hạn như (bài đăng gốc tại đây ):

rõ ràng:

<uses-permission
    android:name="android.permission.PACKAGE_USAGE_STATS"
    tools:ignore="ProtectedPermissions"/>

mở hoạt động sẽ cho phép người dùng xác nhận cấp cho bạn quyền này:

startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));

nhận số liệu thống kê, tổng hợp:

 private static final String USAGE_STATS_SERVICE ="usagestats"; // Context.USAGE_STATS_SERVICE);
 ...
 final UsageStatsManager usageStatsManager=(UsageStatsManager)context.getSystemService(USAGE_STATS_SERVICE);
 final Map<String,UsageStats> queryUsageStats=usageStatsManager.queryAndAggregateUsageStats(fromTime,toTime);

Vấn đề

Tôi dường như không thể kiểm tra xem bạn có quyền cần ("android.permission.PACKAGE_USAGE_STATS") hay không. Tất cả những gì tôi đã cố gắng cho đến nay luôn trả lại rằng nó bị từ chối.

Mã hoạt động, nhưng kiểm tra quyền không hoạt động tốt.

Những gì tôi đã thử

bạn có thể kiểm tra quyền được cấp bằng cách sử dụng:

String permission = "android.permission.PACKAGE_USAGE_STATS";
boolean granted=getContext().checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;   

hoặc cái này:

String permission = "android.permission.PACKAGE_USAGE_STATS";
boolean granted=getPackageManager().checkPermission(permission,getPackageName())== PackageManager.PERMISSION_GRANTED;   

Cả hai luôn trả lại rằng nó đã bị từ chối (ngay cả khi tôi đã cấp quyền với tư cách là người dùng).

Nhìn vào mã của UsageStatsManager, tôi đã cố gắng đưa ra giải pháp này:

      UsageStatsManager usm=(UsageStatsManager)getSystemService("usagestats");
      Calendar calendar=Calendar.getInstance();
      long toTime=calendar.getTimeInMillis();
      calendar.add(Calendar.YEAR,-1);
      long fromTime=calendar.getTimeInMillis();
      final List<UsageStats> queryUsageStats=usm.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY,fromTime,toTime);
      boolean granted=queryUsageStats!=null&&queryUsageStats!=Collections.EMPTY_LIST;

Nó đã hoạt động, nhưng nó vẫn là một cách giải quyết.

Câu hỏi

Tại sao tôi không nhận được kết quả chính xác của việc kiểm tra quyền?

Nên làm gì để kiểm tra nó tốt hơn?

44 hữu ích 2 bình luận 27k xem chia sẻ
19

Theo điều tra của chúng tôi: nếu MODE là mặc định (MODE_DEFAULT), thì cần kiểm tra thêm quyền. Cảm ơn nỗ lực kiểm tra của Weien.

boolean granted = false;
AppOpsManager appOps = (AppOpsManager) context
        .getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, 
        android.os.Process.myUid(), context.getPackageName());

if (mode == AppOpsManager.MODE_DEFAULT) {
    granted = (context.checkCallingOrSelfPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED);
} else {
    granted = (mode == AppOpsManager.MODE_ALLOWED);
}
19 hữu ích 5 bình luận chia sẻ
31

Các quyền đặc biệt do người dùng cấp trong cài đặt hệ thống (truy cập số liệu thống kê sử dụng, truy cập thông báo,…) được xử lý bởi AppOpsManager , được thêm vào Android 4.4.

Lưu ý rằng bên cạnh việc người dùng cấp cho bạn quyền truy cập trong cài đặt hệ thống, bạn thường cần có quyền trong tệp kê khai Android (hoặc một số thành phần), nếu không, ứng dụng của bạn thậm chí không hiển thị trong cài đặt hệ thống. Đối với số liệu thống kê sử dụng, bạn cần có android.permission.PACKAGE_USAGE_STATSquyền.

Không có nhiều tài liệu về điều đó nhưng bạn luôn có thể kiểm tra các nguồn Android để tìm nó. Giải pháp này có vẻ hơi khó hiểu vì một số hằng số đã được thêm vào sau đó AppOpsManagervà một số hằng số (ví dụ: để kiểm tra các quyền khác nhau) vẫn bị ẩn trong các API riêng tư.

AppOpsManager appOps = (AppOpsManager) context
        .getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow("android:get_usage_stats", 
        android.os.Process.myUid(), context.getPackageName());
boolean granted = mode == AppOpsManager.MODE_ALLOWED;

Điều này cho bạn biết nếu người dùng cấp quyền. Lưu ý rằng vì API cấp 21 nên không đổi AppOpsManager.OPSTR_GET_USAGE_STATS = "android:get_usage_stats".

Tôi đã thử nghiệm kiểm tra này trên Lollipop (bao gồm 5.1.1) và nó hoạt động như mong đợi. Nó cho tôi biết liệu người dùng có cấp quyền rõ ràng mà không gặp bất kỳ sự cố nào hay không. Ngoài ra còn có phương pháp appOps.checkOp()có thể ném một SecurityException.

31 hữu ích 5 bình luận chia sẻ
4

Đối số thứ hai checkOpNoThrowuid, không phải pid.

Thay đổi mã để phản ánh có vẻ như sẽ khắc phục được các vấn đề mà những người khác đang gặp phải:

AppOpsManager appOps = (AppOpsManager) context
    .getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow("android:get_usage_stats", 
    android.os.Process.myUid(), context.getPackageName());
boolean granted = mode == AppOpsManager.MODE_ALLOWED;
4 hữu ích 3 bình luận chia sẻ
1

Việc kiểm tra thêm trong câu trả lời của Chris Li là không cần thiết trừ khi bạn đang phát triển một ứng dụng hệ thống .

Khi một ứng dụng được cài đặt lần đầu tiên và người dùng chưa chạm vào quyền truy cập sử dụng của ứng dụng, sau đó checkOpNoThrow()quay lại MODE_DEFAULT.

Chris cho biết sau đó chúng tôi cần kiểm tra xem ứng dụng có PACKAGE_USAGE_STATSquyền kê khai hay không:

if (mode == AppOpsManager.MODE_DEFAULT) {
    granted = (context.checkCallingOrSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS) == PackageManager.PERMISSION_GRANTED);
} else {
    granted = (mode == AppOpsManager.MODE_ALLOWED);
}

Tuy nhiên, trừ khi ứng dụng của bạn là ứng dụng hệ thống, việc kiểm tra quyền này luôn trả về PERMISSION_DENIEDđó là quyền có chữ ký . Vì vậy, bạn có thể đơn giản hóa mã xuống như sau:

if (mode == AppOpsManager.MODE_DEFAULT) {
    granted = false;
} else {
    granted = (mode == AppOpsManager.MODE_ALLOWED);
}

Sau đó, bạn có thể đơn giản hóa điều này:

granted = (mode == AppOpsManager.MODE_ALLOWED);

Điều này đưa chúng ta trở lại giải pháp ban đầu, đơn giản hơn:

AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, Process.myUid(), context.getPackageName());
boolean granted = (mode == AppOpsManager.MODE_ALLOWED);

Đã kiểm tra và xác minh trong Android 5, 8.1 và 9.

1 hữu ích 2 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ android permissions usage statistics android-recents usagestatsmanager , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading