作者:Hugo
鏈接:https://www.zhihu.com/question/33540416/answer/113706620
來源:知乎
著作權歸作者所有,轉載請聯系作者獲得授權。
鏈接:https://www.zhihu.com/question/33540416/answer/113706620
來源:知乎
著作權歸作者所有,轉載請聯系作者獲得授權。
背景知識:
----坑------
應用進程被殺后再次啟動時,服務不生效(沒有bindService)(在下圖所示的藍色列表名單中,不在紅色的存活名單中)。
調查思路:
一、第三方應用主動注冊
二、觸發系統重新bind
思路一:第三方應用主動注冊
思路二:觸發系統重新bind
2、怎樣發起通知授權流程。
所屬:android.service.notification.NotificationListenerService
作用:監聽通知欄內容變化的服務
- extends Service,abstract class(意味着第三方可以實現去接收通知欄的通知數據)。
- Added in API level 18(Android 4.3)。
- 應用場景:智能手表(Google官方的Android Wear手機端App,通知消息同步到手表。如下圖)、紅包助手(監聽通知欄的微信紅包消息)等。
- Service bind時機:在系統的設置通知授權中勾選並授權時。
- 回調時機:有新通知或通知被移除或通知排序變化時系統回調。
----坑------
應用進程被殺后再次啟動時,服務不生效(沒有bindService)(在下圖所示的藍色列表名單中,不在紅色的存活名單中)。
影響:通知欄有內容變更,服務無法感知。
還原方法:重啟手機
必現手機(方便調試):小米Note Pro,清除后台應用后。
我們要做的:讓服務重生。
調試手段:查看存活的通知監聽服務。
方法:adb shell dumpsys notification

藍色:已授權的通知監聽Service列表。
紅色:當前存活的的通知監聽Service列表。
調查思路:
一、第三方應用主動注冊
二、觸發系統重新bind
思路一:第三方應用主動注冊
關鍵代碼路徑:
- android.service.notification.NotificationListenerService#registerAsSystemService
- android.app.INotificationManager.Stub#enforceSystemOrSystemUI
條件:
- 系統的uid或有android.permission.STATUS_BAR_SERVICE權限。
∴ 路不通。
思路二:觸發系統重新bind
關鍵代碼路徑:
- com.android.server.notification.ManagedServices#rebindServices
三種方式觸發:
- A && B(A:應用安裝卸載或更新等的廣播;B:上圖藍色列表中的服務有變化)。
- 系統的登錄用戶切換 。[pass]
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS的Settings值有變更。
第三方有權利觸發的方式(源碼分析得知 1B= 3):
- Service的disable,會有Intent.ACTION_PACKAGE_CHANGED廣播,並且從上圖藍色列表中移除。
利用這一特性,把應用的NotificationListenerService實現類disable再enable,即可觸發系統rebind操作。
private void toggleNotificationListenerService() { PackageManager pm = getPackageManager(); pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); pm.setComponentEnabledSetting(new ComponentName(this, com.xinghui.notificationlistenerservicedemo.NotificationListenerServiceImpl.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); }
問題解決。
補充:
1、怎樣在代碼中判斷自己的服務是否在上圖藍色列表(通知已授權)中?
private static boolean isNotificationListenerServiceEnabled(Context context) {
Set<String> packageNames = NotificationManagerCompat.getEnabledListenerPackages(context);
if (packageNames.contains(context.getPackageName())) {
return true;
}
return false;
}
2、怎樣發起通知授權流程。
startActivity(new Intent(NotificationConstants.ACTION_NOTIFICATION_LISTENER_SETTINGS));