Android 4.1: จะตรวจสอบการแจ้งเตือนสำหรับแอปพลิเคชันได้อย่างไร?


98

Android 4.1 ให้ผู้ใช้มีช่องทำเครื่องหมายเพื่อปิดใช้งานการแจ้งเตือนสำหรับแอปพลิเคชันเฉพาะ

อย่างไรก็ตามในฐานะนักพัฒนาเราไม่มีทางรู้ได้ว่าการโทรเพื่อแจ้งเตือนนั้นมีผลหรือไม่

ฉันต้องการตรวจสอบจริงๆว่าการแจ้งเตือนถูกปิดใช้งานสำหรับแอปพลิเคชันปัจจุบันหรือไม่ แต่ฉันไม่พบการตั้งค่าใด ๆ สำหรับสิ่งนั้นใน API

เคยมีวิธีตรวจสอบการตั้งค่านี้ในรหัสหรือไม่?


1
คุณไม่ควรกังวลกับตัวเองจริงๆ เพียงแค่ถือว่าการแจ้งเตือนของคุณประสบความสำเร็จ หากผู้ใช้ปิดการใช้งานการแจ้งเตือนของคุณอย่างชัดเจนเขา / เธออาจมีเหตุผลที่ดีที่จะทำเช่นนั้นและแอปพลิเคชันของคุณไม่ควรสนใจว่าการแจ้งเตือนนั้นจะแสดงหรือไม่
Kevin Coppock

ฉันอธิบายเหตุผลในความคิดเห็นแรกของ anwser
Guillaume Perrot

1
นี่คือปัญหาในการติดดาว / ติดตามcode.google.com/p/android/issues/detail?id=38482ต้องการสิ่งนี้จริงๆ ....
brandall

คำตอบ:


147

คุณไม่สามารถทำได้ 100%

มีการถามในวิดีโอ Google I / O 2012 นี้และหัวหน้าโครงการสำหรับการแจ้งเตือนใหม่แจ้งว่าคุณทำไม่ได้


แก้ไข

ปรับปรุง 2016ตอนนี้คุณสามารถตรวจสอบได้ตามที่กล่าวในการนี้ Google I / O 2016 วิดีโอ

ใช้NotificationManagerCompat.areNotificationsEnabled()จากไลบรารีการสนับสนุนเพื่อตรวจสอบว่าการแจ้งเตือนถูกบล็อกบน API 19+ หรือไม่ เวอร์ชันด้านล่าง API 19 จะคืนค่าจริง (เปิดใช้งานการแจ้งเตือน)

ป้อนคำอธิบายภาพที่นี่


2
ไม่มีอะไรในวิดีโอที่แสดงว่าเราอ่านการตั้งค่านี้ไม่ได้ เพื่อความชัดเจน: ฉันแค่ต้องการที่จะสามารถอ่านสถานะปัจจุบันของกล่องกาเครื่องหมายไม่ใช่แก้ไข ฉันกลัวว่าคุณไม่เข้าใจคำถามของฉัน
Guillaume Perrot

2
เราต้องการสิ่งนี้เนื่องจากเราแสดงการแจ้งเตือนครั้งละ 1 รายการ (ซึ่งอาจเป็นในแอปหรือในแถบระบบ) หากระบบแสดงการแจ้งเตือนเราจะไม่แสดงแบนเนอร์ในแอปและในทางกลับกัน หากเราไม่สามารถทราบได้ว่ามีการแจ้งเตือนปรากฏขึ้นหรือไม่เราจะไม่สามารถจัดการวงจรชีวิตได้อีกต่อไป ฉันเดาว่าเราต้องเปลี่ยนวิธีจัดการการแจ้งเตือนทั้งหมดตอนนี้ ...
Guillaume Perrot

9
FYI คำถามถูกถาม (และตอบ) เวลา 48:05 ในวิดีโอ (ระหว่างถาม - ตอบ) ด้วยคำสั้น ๆ คำเดียว ... ไม่ youtube.com/…
devunwired

2
@Stavros_S อัปเดตคำตอบพร้อมลิงก์แบบเต็ม NotificationManagerCompat.areNotificationsEnabled ()
Sufian

17
@Stavros_S คุณต้องใช้NotificationManagerCompat.from(ctx).areNotificationsEnabled()
AlexAndro

39

คำตอบจาก @blundell ถูกต้อง แต่มีการเปลี่ยนแปลงเล็กน้อยในเวอร์ชันที่ใหม่กว่า

NotificationManagerCompat.from(context).areNotificationsEnabled()

38

จริงๆแล้วมันค่อนข้างง่ายที่จะทำ:

/**
 * 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
ในขณะที่โพสต์คำถาม Android 4.1 เป็นเวอร์ชันปัจจุบันสำหรับ Android 4.4+ เท่านั้นและดูเหมือนว่าจะใช้การสะท้อนกลับและเอกสารประกอบไม่แนะนำให้ใช้กับแอปที่ไม่ใช่ระบบ
Guillaume Perrot

@GuillaumePerrot จริงๆแล้วคุณพูดถูกเกี่ยวกับการไตร่ตรอง แต่อีกครั้งเอกสารและแถลงการณ์อย่างเป็นทางการจาก Android บอกว่าคุณไม่สามารถทำได้คุณยังสามารถยึดติดกับสิ่งนั้นได้ ขออภัยเกี่ยวกับปัญหาเกี่ยวกับเวอร์ชันฉันไม่สามารถช่วยคุณได้ หากลูกค้า / โซลูชันของคุณต้องการคุณอาจต้องพิจารณาเพิ่มเวอร์ชันที่จำเป็นเล็กน้อยเนื่องจากเป็น SDK ที่ จำกัด คุณ ณ จุดนั้น โปรดแจ้งให้เราทราบหากคุณพบวิธีอื่น
desgraci

1
ยุติธรรมเพียงพอ แต่คุณควรถือว่าเป็นจริงหากคุณไม่สามารถรับข้อมูลได้ อย่างน้อยในกรณีการใช้งานของฉันมันก็สมเหตุสมผลกว่า หรือมีค่าเริ่มต้นเป็นพารามิเตอร์ในฟังก์ชันคงที่เพื่อให้สามารถใช้ซ้ำได้มากขึ้น
Guillaume Perrot

1
@Rahul Matte, GlobalContext เป็นเพียงคลาสยูทิลิตี้ที่ฉันใช้เพื่ออ้างอิงถึงบริบทคุณสามารถส่งบริบทผ่านวิธีการนี้หากคุณไม่ได้ใช้ / หรือเต็มใจที่จะใช้โครงสร้างนั้น หวังว่านี่จะช่วยได้!
desgraci

1
ฉันหวังว่าพวกเขาจะไม่: p แต่มาจาก google XD เนื่องจากสิ่งนี้ใช้การสะท้อน OP_POST_NOTIFICATION กำลังอ่านโค้ดบน grep หลังจากพบว่าตัวเองกำลังดิ้นรนกับปัญหาเดียวกัน
desgraci

5

หากคุณใช้ Xamarin และต้องการคำตอบคุณสามารถใช้รหัสนี้:

//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 () ถูกเพิ่มใน API 24 developer.android.com/reference/android/app/…
Sune Kjærgård

คุณถูกต้องต้องอ่านผิดก่อนหน้านี้ ฉันลบความคิดเห็นเดิมของฉันเพื่อไม่ให้ใครสับสน
Adam

5

ดูเหมือนว่าไม่มีวิธีใดในการสอบถามสถานะการแจ้งเตือน

ฉันแนะนำสิ่งนี้:

  • ออกแบบแอปพลิเคชันของคุณด้วยการแจ้งเตือน
  • ให้ผู้ใช้ปิดการแจ้งเตือนจากการตั้งค่าของแอปพลิเคชัน
  • ตรวจสอบว่ามีการคลิกการแจ้งเตือนหรือไม่ หากผู้ใช้คลิกการแจ้งเตือนให้บันทึกเป็นค่ากำหนด
  • ในแอปของคุณหากเปิดการตั้งค่าการแจ้งเตือนและหากผู้ใช้เป็น Android 4.1+ (API 16) แต่หากผู้ใช้ไม่คลิกการแจ้งเตือนเป็นเวลาหลายวัน / สัปดาห์ให้ถือว่าผู้ใช้ปิดการแจ้งเตือน

ไม่ถูกต้อง 100% แต่สิ่งนี้ให้ความเห็น
ตัวอย่างเช่นหากผู้ใช้ไม่คลิกการแจ้งเตือนแอปใด ๆ เป็นเวลา 10-15 วันแสดงว่าเขาปิดการใช้งาน


1
นี่เป็นแนวทางที่กว้างและเป็นนามธรรม
IgorGanapolsky

นี่คือแนวทางที่ดีที่สุด! เรากำลังทำสิ่งนี้ในแอปพลิเคชันของเราและคุณสามารถพูดได้อย่างแม่นยำหากปิดใช้งานการแจ้งเตือน PendingIndent สำหรับทุกการกระทำและบันทึกลงในค่ากำหนด อย่าลืมรีเซ็ตหากสมาร์ทโฟนรีสตาร์ท
JacksOnF1re

2

ฉันใช้วิธีนี้เพื่อตรวจสอบว่ามีการเปิดใช้งานการแจ้งเตือนหรือไม่วิธีการที่กล่าวถึงข้างต้นจะใช้ได้ผลในการตรวจสอบว่าเปิดใช้งานการแจ้งเตือนหรือไม่ แต่จาก Android 8เป็นต้นไปสำหรับการสร้างการแจ้งเตือนเราจะต้องสร้างช่องแรกดังนั้นจากโอรีโอ, เรามีการตรวจสอบช่องการแจ้งเตือนของคุณเปิดใช้งานหรือไม่

    /**
     * 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;
    }

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.