Android 4.1: Làm thế nào để kiểm tra thông báo đã tắt cho ứng dụng?


98

Android 4.1 cung cấp cho người dùng một hộp kiểm để tắt thông báo cho một ứng dụng cụ thể.

Tuy nhiên, là một nhà phát triển, chúng tôi không có cách nào để biết liệu một cuộc gọi để thông báo có hiệu quả hay không.

Tôi thực sự cần kiểm tra xem thông báo có bị tắt cho ứng dụng hiện tại hay không nhưng tôi không thể tìm thấy bất kỳ cài đặt nào cho điều đó trong API.

Có cách nào để kiểm tra cài đặt này trong mã không?


1
Bạn thực sự không nên quan tâm đến nó. Chỉ cần giả sử thông báo của bạn đã thành công. Nếu người dùng đã tắt thông báo của bạn một cách rõ ràng, thì có lẽ họ có lý do chính đáng để làm như vậy và ứng dụng của bạn không nên quan tâm đến việc thông báo có được hiển thị hay không.
Kevin Coppock

Tôi đã giải thích lý do trong phần bình luận của nhà báo đầu tiên.
Guillaume Perrot

1
Đây là vấn đề cần gắn dấu sao / track code.google.com/p/android/issues/detail?id=38482 Thực sự cần cái này ....
brandall

Câu trả lời:


147

Bạn không thể 100% không thể.

Nó được yêu cầu trong video Google I / O 2012 này và Trưởng nhóm dự án về các thông báo mới tuyên bố rằng bạn không thể.


Biên tập

Bản cập nhật 2016: Bây giờ bạn có thể kiểm tra nó, như đã nói trong video Google I / O 2016 này .

Sử dụng NotificationManagerCompat.areNotificationsEnabled(), từ thư viện hỗ trợ, để kiểm tra xem các thông báo bị chặn trên API 19+. Các phiên bản bên dưới API 19 sẽ trả về true (đã bật thông báo).

nhập mô tả hình ảnh ở đây


2
Không có gì trong video cho thấy chúng tôi không thể đọc cài đặt này. Chỉ cần nói rõ: Tôi chỉ muốn có thể đọc trạng thái hiện tại của hộp kiểm, không thay đổi nó. Tôi sợ bạn không hiểu câu hỏi của tôi.
Guillaume Perrot,

2
Chúng tôi cần điều này vì chúng tôi hiển thị 1 thông báo tại một thời điểm (có thể trong ứng dụng hoặc trong thanh hệ thống). Nếu thông báo hệ thống được hiển thị, chúng tôi sẽ không hiển thị biểu ngữ trong ứng dụng và ngược lại. Nếu chúng ta không thể biết liệu một thông báo có được hiển thị hay không, chúng ta không thể quản lý vòng đời của nó nữa. Tôi đoán chúng ta phải hoàn toàn thay đổi cách chúng ta quản lý các thông báo bây giờ ...
Guillaume Perrot

9
FYI, câu hỏi được hỏi (và trả lời) lúc 48:05 trong video (trong phần hỏi đáp) với một từ ngắn ... Không. youtube.com/…
Devunwired

2
@Stavros_S đã cập nhật câu trả lời với liên kết đầy đủ. NotificationManagerCompat.areNotificationsEnabled () .
Sufian

16
@Stavros_S Bạn cần sử dụngNotificationManagerCompat.from(ctx).areNotificationsEnabled()
AlexAndro

38

Trên thực tế, điều này khá dễ thực hiện:

/**
 * Created by desgraci on 5/7/15.
*/
public class NotificationsUtils {

    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    public static boolean isNotificationEnabled(Context context) {

        AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

        ApplicationInfo appInfo = context.getApplicationInfo();

        String pkg = context.getApplicationContext().getPackageName();

        int uid = appInfo.uid;

        Class appOpsClass = null; /* Context.APP_OPS_MANAGER */

        try {

            appOpsClass = Class.forName(AppOpsManager.class.getName());

            Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);

            Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
            int value = (int)opPostNotificationValue.get(Integer.class);

            return ((int)checkOpNoThrowMethod.invoke(mAppOps,value, uid, pkg) == AppOpsManager.MODE_ALLOWED);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }
}

3
Tại thời điểm câu hỏi được đăng, Android 4.1 là phiên bản hiện tại, chỉ dành cho Android 4.4+ và có vẻ như sử dụng phản ánh và tài liệu không khuyên bạn nên sử dụng nó cho ứng dụng không phải hệ thống.
Guillaume Perrot

@GuillaumePerrot thực ra, bạn nói đúng về sự phản ánh, nhưng một lần nữa, tài liệu và tuyên bố chính thức từ android nói rằng bạn không thể làm điều đó, bạn cũng có thể bám vào điều đó. Xin lỗi về vấn đề phiên bản, tôi không thể giúp bạn điều đó. Nếu khách hàng / giải pháp của bạn yêu cầu nó, thì bạn có thể muốn xem xét nâng cao một chút phiên bản bắt buộc vì SDK đang hạn chế bạn tại thời điểm đó. Hãy cho tôi biết nếu bạn tìm thấy một cách thay thế.
desgraci,

1
Đủ công bằng nhưng bạn nên cho rằng trả về true nếu bạn không thể lấy được thông tin. Ít nhất trong trường hợp sử dụng của tôi, nó có ý nghĩa hơn. Hoặc có giá trị mặc định như một tham số trong hàm tĩnh để làm cho nó có thể tái sử dụng nhiều hơn.
Guillaume Perrot,

1
@Rahul Matte, GlobalContext chỉ là một lớp tiện ích mà tôi sử dụng để giữ tham chiếu đến một Context, bạn có thể chuyển một Context thông qua phương thức nếu bạn không sử dụng / hoặc sẵn sàng sử dụng cấu trúc đó. Hi vọng điêu nay co ich!
desgraci,

1
Tôi hy vọng chúng không phải: p mà đến từ google XD, vì điều này sử dụng phản chiếu, OP_POST_NOTIFICATION đã đọc qua mã trên grep sau khi thấy mình đang vật lộn với vấn đề tương tự.
desgraci

37

Câu trả lời từ @blundell là đúng nhưng có một thay đổi nhỏ trong các phiên bản mới hơn.

NotificationManagerCompat.from(context).areNotificationsEnabled()

5

Nếu bạn đang sử dụng Xamarin và bạn cần câu trả lời này, bạn có thể sử dụng mã này:

//return true if this option is not supported.
public class NotificationsUtils 
{
    private const String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private const String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";

    public static bool IsNotificationEnabled(global::Android.Content.Context context) {

        AppOpsManager mAppOps = (AppOpsManager) context.GetSystemService(global::Android.Content.Context.AppOpsService);

        ApplicationInfo appInfo = context.ApplicationInfo;

        String pkg = context.ApplicationContext.PackageName;

        int uid = appInfo.Uid;

        try {

            var appOpsClass = Java.Lang.Class.ForName("android.app.AppOpsManager");
            var checkOpNoThrowMethod = appOpsClass.GetMethod(CHECK_OP_NO_THROW,Java.Lang.Integer.Type,Java.Lang.Integer.Type,new Java.Lang.String().Class);//need to add String.Type

            var opPostNotificationValue = appOpsClass.GetDeclaredField (OP_POST_NOTIFICATION);
            var value = (int)opPostNotificationValue.GetInt(Java.Lang.Integer.Type);
            var mode = (int)checkOpNoThrowMethod.Invoke(mAppOps,value, uid, pkg);
            return (mode == (int)AppOpsManagerMode.Allowed);

        } catch (Exception) 
        {
            System.Diagnostics.Debug.WriteLine  ("Notification services is off or not supported");
        } 
        return true;
    }
}

@AdamPedley AreNotificationsEnabled () đã được thêm vào API 24 developer.android.com/reference/android/app/…
Sune Kjærgård

Bạn là chính xác, chắc chắn đã đọc sai nó trước đây. Tôi đã xóa bình luận ban đầu của mình, để không gây nhầm lẫn cho bất kỳ ai.
Adam Pedley

5

Có vẻ như không có cách nào để truy vấn trạng thái thông báo.

Tôi khuyên bạn điều này:

  • Thiết kế ứng dụng của bạn với các thông báo.
  • Cho phép người dùng tắt thông báo từ cài đặt của ứng dụng.
  • Kiểm tra xem thông báo có được nhấp vào hay không. Nếu người dùng nhấp vào thông báo, hãy lưu thông báo này vào tùy chọn.
  • Trong ứng dụng của bạn, nếu cài đặt thông báo được bật và nếu người dùng là Android 4.1+ (API 16), nhưng nếu người dùng không nhấp vào thông báo trong một số ngày / tuần, hãy giả sử rằng người dùng đã tắt thông báo.

Không đúng 100%. Nhưng điều này đưa ra một ý kiến.
Ví dụ: nếu người dùng không nhấp vào bất kỳ thông báo ứng dụng nào trong 10-15 ngày, có thể họ đã vô hiệu hóa thông báo đó


1
Đây là một cách tiếp cận rất rộng và trừu tượng.
IgorGanapolsky

Đây là cách tiếp cận tốt nhất! Chúng tôi đang thực hiện việc này trong ứng dụng của mình và bạn có thể nói chính xác, nếu thông báo bị tắt. Đang chờ xử lý cho MỌI hành động và lưu vào tùy chọn. Đừng quên đặt lại nếu điện thoại thông minh được khởi động lại.
JacksOnF1re

1

Tôi sử dụng phương pháp này để kiểm tra xem thông báo đã được bật hay chưa, các phương pháp nêu trên sẽ hoạt động để kiểm tra xem thông báo đã được bật hay chưa. Nhưng từ Android 8 trở đi để tạo thông báo, chúng tôi phải tạo kênh trước , vì vậy từ Oreo, chúng tôi phải kiểm tra xem kênh thông báo của bạn có được bật hay không .

    /**
     * Checking Whether notifications are enabled or not
     * @return true if notifications are enabled otherwise false
     */
    public static final String CHANNEL_ID = your_channel_id";

    private boolean isNotificationChannelEnabled(){
        if(NotificationManagerCompat.from(this).areNotificationsEnabled()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                NotificationChannel channel = manager.getNotificationChannel(CHANNEL_ID);
                if (channel == null)
                    return true; //channel is not yet created so return boolean
                // by only checking whether notifications enabled or not
                return channel.getImportance() != NotificationManager.IMPORTANCE_NONE;
            }
            return true;
        }
        return false;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.