對Android 8.0以上版本通知點擊無效的一次分析


版權聲明:本文為xing_star原創文章,轉載請注明出處!

本文同步自http://javaexception.com/archives/178

對Android 8.0以上版本通知點擊無效的一次分析

最近在重構聊天服務,有機會從新梳理下前人寫的通知相關的邏輯,隱藏着一個很深的bug,遺留了應該有8個多月了。直到今天才定位出原因,之前一直懷疑是自己設備的問題😂😂,經過寫demo,做實驗驗證,最終得出結論。
Android 8.0之后通知相關的Api又發生了很大的變化,接手項目的時候,沒怎么關注過這塊,一直以為沒有問題,到今天測試驗證,發現還是存在問題的😂,問題表象是,點擊App通知欄的通知消息,點擊之后通知欄還在,一直沒有反應(App業務中關於Click通知欄的邏輯沒有生效)。抱着對代碼懷疑的角度,自己創建了個demo工程,參考Notification的用法,自己做實驗觀察效果。

實驗過程

這里在回顧下自己做實驗的過程。

首先創建了個demo工程,添加通知相關的代碼,以及動態注冊了一個BroadcastReceiver。

private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
 
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent == null || context == null) {
            return;
        }
        mNotificationManager.cancel(NOTIFICATION_ID_LIVE);
        String type = intent.getStringExtra(PUSH_TYPE);
        if (PUSH_TYPE_LINK.equals(type)) {
            mNumLinkes = 0;
        } else if (PUSH_TYPE_LIVE.equals(type)) {
            mNumLives = 0;
        }
        //這里可以重新計數
    }
};
private void registerHeadsetPlugReceiver() {
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(NOTIFICATION_CLICK_ACTION);
    intentFilter.addAction(NOTIFICATION_DELETED_ACTION);
    registerReceiver(mBroadcastReceiver, intentFilter);
}
private void sendLiveNotification() {
    Intent intent = new Intent(NOTIFICATION_CLICK_ACTION);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
        channel.setBypassDnd(true);    //設置繞過免打擾模式
        channel.canBypassDnd();       //檢測是否繞過免打擾模式
        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);//設置在鎖屏界面上顯示這條通知
        channel.setDescription("測試通知消息內容");
        channel.setLightColor(Color.GREEN);
        channel.setName("測試通知消息名稱");
        channel.setShowBadge(true);
        channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
        channel.enableVibration(true);
        mNotificationManager.createNotificationChannel(channel);
    }
 
    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
    String title = "Push測試";
    mBuilder.setContentTitle(title);
    mBuilder.setTicker(title);
    mBuilder.setContentText("https://233.tv/over140");
    mBuilder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
    mBuilder.setSmallIcon(R.mipmap.ic_launcher);
    mBuilder.setDefaults(Notification.DEFAULT_ALL);
    mBuilder.setWhen(System.currentTimeMillis());
    mBuilder.setContentIntent(PendingIntent.getBroadcast(this, NOTIFICATION_ID_LIVE, intent, 0));
    mBuilder.setDeleteIntent(PendingIntent.getBroadcast(this, NOTIFICATION_ID_LIVE, new Intent(NOTIFICATION_DELETED_ACTION).putExtra(PUSH_TYPE, PUSH_TYPE_LIVE), 0));
    mNotificationManager.notify(NOTIFICATION_ID_LIVE, mBuilder.build());
}

第一步的測試代碼比較簡單,在MainActivity調用sendLiveNotification()方法,就會出現通知欄,之后呢,點擊通知欄會發送廣播,我們在MainActivity注冊了這個廣播事件,就能夠接收到,看起來沒問題。到這里把懷疑點放到了靜態注冊上,BroadcastReceiver在AndroidManifest.xml中的注冊。

接着就是修改代碼,把動態注冊的代碼調整為一個CustomBroadcastReceiver,然后在AndroidManifest.xml中進行注冊

<receiver
    android:name=".CustomBroadcastReceiver"
    android:enabled="true"
    android:exported="false">
    <intent-filter>
        <action android:name="me.star.notificationdemo2.click" />
        <action android:name="me.star.notificationdemo2.delete" />
    </intent-filter>
</receiver>
public class CustomBroadcastReceiver extends BroadcastReceiver {
    private int NOTIFICATION_ID_LIVE = 101;
    private String PUSH_TYPE_LIVE = "PUSH_TYPE_LIVE";
    private String PUSH_TYPE = "push_type";
    private String PUSH_TYPE_LINK = "PUSH_TYPE_LINK";
    private int mNumLinkes;
    private int mNumLives;
 
    @Override
    public void onReceive(Context context, Intent intent) {
        NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        if (intent == null || context == null) {
            return;
        }
        mNotificationManager.cancel(NOTIFICATION_ID_LIVE);
        String type = intent.getStringExtra(PUSH_TYPE);
        if (PUSH_TYPE_LINK.equals(type)) {
            mNumLinkes = 0;
        } else if (PUSH_TYPE_LIVE.equals(type)) {
            mNumLives = 0;
        }
    }
}

調整完后,繼續驗證自己的想法。

運行程序,開啟debug模式,發現點擊通知欄后,在CustomBroadcastReceiver中沒有攔截到,到這里就確定了問題肯定是出現在靜態注冊上面,但是之前的項目中,有些第三方的broadcastReceiver是靜態注冊,但最終是執行了onReceiver的方法,那肯定是我的使用姿勢有問題。於是google搜索了一番,關鍵詞就是android broadcastreceiver androidmanifest android 8.0 不運行,第一篇文章就是我想要找的。參考了一番,發現提到的幾個說法值得一試,目前只驗證了

intent.setPackage(getPackageName());

在查閱資料的過程也特意觀察了下log輸出

07-26 23:30:14.452 1637-1688/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=me.star.notificationdemo2.click flg=0x10 } to notification.star.me.notificationdemo2/.CustomBroadcastReceiver

說的是后台執行不被允許?反正搞不懂啥情況,沒仔細看相關的源碼。加上intent.setPackage(getPackageName());后重新編譯

之后重新debug,發現這次執行了onReceiver的代碼邏輯,終於找到了問題所在,就這一行代碼,花去了好幾個小時😂,但是值得的。

 

參考資料

https://blog.csdn.net/u011386173/article/details/82889275

Demo下載

鏈接:https://pan.baidu.com/s/1Ac97_0kFxKavpQi6-YxB2w 密碼:niun  (demo中包含Git版本控制,可以通過切換commit,查閱動態注冊,靜態注冊的代碼)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM