2016.6.12更新
最最主要的源码其实就只有下面我提到的这些了,最核心的功能都在上面了,以及可能碰到的坑。
代码已经开源到github,地址:
https://github.com/zhuohui/AndMonitor
原文:
有段时间没写博了,想着还是要写点东西,免得生疏了,正好前段时间做了一个抓取通知栏的功能,期间也走了一些弯路,
通过网上查资料,看Android源码,最终总算解决了监控通知栏的功能。实现的效果如下:
不过在使用通知栏监控之前,首先要进行设置,要让手机允许你监控通知栏,毕竟这是很隐私的操作,不然如果没有这个允许动作,那么Android手机也太危险了,
包括聊天信息,短消息都有可能被监控。设置如下:
在辅助功能这里,开启NotificationMonitor服务。
接下来来讲一下实现方法:
首先写一个类继承AccessibilityService,AccessibilityService辅助服务,可以看官方介绍:
http://developer.android.com/reference/android/accessibilityservice/AccessibilityService.html
这个服务运行在后台,当有定义的的AccessibilityEvent被触发时,则会进行相应的回调函数,通知栏需要使用到的事件是:
AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED
也就是通知栏状态变化事件。
代码如下:
public class NeNotificationService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
//判断辅助服务触发的事件是否是通知栏改变事件
if (event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)
{
//获取Parcelable对象
Parcelable data = event.getParcelableData();
//判断是否是Notification对象
if (data instanceof Notification) {
Notification notification = (Notification) data;
Intent intent = new Intent();
intent.putExtra("NotifyData", notification);
intent.putExtra("packageName", event.getPackageName());
intent.setAction(".NeNotificationService");
//进行处理解析通知栏内容的函数
MainActivity.notifyReceive((String)event.getPackageName(), notification);
}else
{
}
}
/**
*Service被启动的时候会调用这个API
*/
@Override
protected void onServiceConnected() {
//设置关心的事件类型
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED |
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED |
AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.notificationTimeout = 100;//两个相同事件的超时时间间隔
setServiceInfo(info);
}
}
//在MainActivity.onCreate里初始化
Intent upservice = new Intent(this, NeNotificationService.class);
//按钮按下时更新或启动服务
accesscStartNo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateServiceStatus(true);
}
});
//这里防止多次启动服务,所以先判断服务是否在运行中
private void updateServiceStatus(boolean start)
{
boolean bRunning = util.isServiceRunning(this, "com.nis.bcreceiver.NeNotificationService");
//没有Running则启动
if (start && !bRunning) {
this.startService(upservice);
} else if(!start && bRunning) {
this.stopService(upservice);
}
}
//另外需要在AndroidManifest.xml文件中配置
界面上的View,我们只要解析它就可以获取展示的View的标题及文本内容,处理代码如下:
private void AnalyzeView(RemoteViews remoteView, String packName) { try { //把RemoteView apply后变成当前可以处理的View View v1 = remoteView.apply(this, rootLayout); //然后就是枚举处理这个View的内容 EnumGroupViews(v1); //展示出来 rootLayout.addView(v1); } catch (Exception e) { AppLog.e("addToUi excep",e); } } private void EnumGroupViews(View v1) { if(v1 instanceof ViewGroup) { ViewGroup lav = (ViewGroup)v1; int lcCnt = lav.getChildCount(); for(int i = 0; i < lcCnt; i++) { View c1 = lav.getChildAt(i); if(c1 instanceof ViewGroup) EnumGroupViews(c1);//递归处理GroupView else if(c1 instanceof TextView) { //TestView则解析里面文本内容 TextView txt = (TextView)c1; String str = txt.getText().toString().trim(); if(str.length() > 0) { //这里打印文本内容 } AppLog.i( "TextView id:"+ txt.getId() + ".text:" + str); }else { AppLog.w("2 other layout:" + c1.toString()); } } } else { AppLog.w("1 other layout:" + v1.toString()); } }
在查看其相应源码情况下自己琢磨出来的,而且测试了十几款有推送消息的应用,都可以正常解析其所有内容。