天天看點

使用Xposed攔截應用通知的一直簡單實作

當我們不希望某一應用的通知在通知欄上提示時,我們可以通過xposed來實作攔截它的操作。以支付寶為例,當支付寶切換到背景時,資訊會以通知欄的形式顯示。若要攔截它,大緻有兩個思路來實作:1、反編譯支付寶代碼,将相關代碼hook掉。然而這個工程對我等小碼仔來說,太難實作。2、攔截系統所有的通知資訊,對其進行過濾,當資訊是來自我們想要攔截的應用時,hook掉它。本文記錄一下對第二種方法的簡單實作。

基于面向google(baidu)程式設計,這裡決定hook NotificationManager中notify方法,源碼如下:

/**  
 * Post a notification to be shown in the status bar. If a notification with  
 * the same tag and id has already been posted by your application and has not yet been   
 * canceled, it will be replaced by the updated information.  
 *  
 * @param tag A string identifier for this notification.  May be {@code null}.  
 * @param id An identifier for this notification.  The pair (tag, id) must be unique  
 *        within your application.  
 * @param notification A {@link Notification} object describing what to  
 *        show the user. Must not be null.  
 */  
public void notify(String tag, int id, Notification notification)
{   
    notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));  
}
           

notify方法的三個入參,其中notification就是要在通知欄上顯示的資訊。代碼如下(測試時使用QQ來測試,是以注釋中有QQ的包名):

public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
    if (!lpparam.packageName.equals("com.eg.android.AlipayGphone")
            && !lpparam.processName.equals("com.eg.android.AlipayGphone"))
        return;
    if (lpparam.packageName.equals("com.eg.android.AlipayGphone")) {
        //        if (!lpparam.packageName.equals("com.tencent.mobileqq")
        //                && !lpparam.processName.equals("com.tencent.mobileqq"))
        //            return;
        //        if (lpparam.packageName.equals("com.tencent.mobileqq")) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            XposedHelpers.findAndHookMethod("android.app.NotificationManager"
                    , lpparam.classLoader, "notify"
                    , String.class, int.class, Notification.class
                    , new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            XposedBridge.log("methodHookParam.args:  " + Arrays.toString(param.args));
                            //通過param拿到第三個入參notification對象
                            Notification notification = (Notification) param.args[2];
                            //獲得包名
                            String aPackage = notification.contentView.getPackage();
                            String title = "--";
                            String text = "--";
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                                Bundle bundle = notification.extras;
                                title = (String) bundle.get("android.title");
                                text = (String) bundle.get("android.text");
                            }
                            //    if ("com.tencent.mobileqq".equals(aPackage)) {
                            if ("com.eg.android.AlipayGphone".equals(aPackage)
                                    && title.equals("支付寶消息") &&
                                    text.endsWith("已成功向你轉了1筆錢")) {
                                param.setResult(null);
                                return;
                            }
                            super.beforeHookedMethod(param);
                        }
                    });
        }
}
           

上面代碼實作的是攔截支付寶的到賬通知(支付寶還會正常到賬,打開支付寶後也會有到賬消息,隻是攔截了通知欄的提示不影響正常功能),通過notification.extra可以獲得要顯示在通知欄的資訊内容。

Bundle[{android.title=leon, android.subText=null,   android.showChronometer=false,   android.icon=2130837513, 
    android.text=leon:九分風好  大, android.progress=0,     android.progressMax=0,
    android.rebuild.contentViewActionCount=41,   android.showWhen=true,
    android.rebuild.applicationInfo=ApplicationInfo {1a3b2b0 com.eg.android.AlipayGphone},
    [email protected], android.infoText=null, android.originatingUserId=0,
    android.progressIndeterminate=false}]  
           

可以看到這是一個bundle對象,其中android.title是通知欄顯示的标題,android.text是通知欄顯示的内容。這條是支付寶接收到使用者發送消息時的内容,下面看一下接收到轉賬提示時的内容。

Bundle[{android.title=支付寶消息, android.subText=null, android.showChronometer=false, android.icon=2130837513,
    android.text=leon已成功向你轉了1筆錢, android.progress=0, android.progressMax=0,
    android.rebuild.contentViewActionCount=41, android.showWhen=true,
    android.rebuild.applicationInfo=ApplicationInfo{1a3b2b0 com.eg.android.AlipayGphone},
    android.larg[email protected], android.infoText=null,
    android.originatingUserId=0,android.progressIndeterminate=false}]  
           

可以看到當資訊來自支付寶轉賬時,android.title的内容固定為支付寶消息,android.text的内容為XXX已成功想你轉了1筆錢,其餘内容全部相同。我們就可以考慮判斷這兩個字段的值,來對到賬消息進行攔截的同時不影響正常功能的使用。代碼在上面,很簡單的實作了對支付寶到賬資訊的攔截,若有需要對到賬資訊統計的話,可以在統計到賬的次數與轉賬人,但是無法統計到賬金額,畢竟隻是對系統方法進行hook,支付寶也不會把金額資訊給顯示在通知欄中。