利用NotificationListenerService和Android Auto自动回复微信消息

    技术2022-07-29  82

    这里只讲技术和思路         这里只讲技术和思路              这里只讲技术和思路

    在之前的一片文章中描述了如何通过NotificationListenerService获取微信通知的消息,利用NotificationListenerService获取微信通知消息的头像和内容

    1.通过虚拟点击回复消息:

    1.1当通过NotificationListenerService可以获取一个PendingIntent ,这个PendingIntent封装了数据,可以直接跳转到对应发送消息的会话列表。然后执行虚拟点击找控件,填写回复的内容,点击发送,就完成了一次回复操作

    PendingIntent pendingIntent = sbn.getNotification().contentIntent; //获取通知的PendingIntent 跳转到要回复消息的收件人会话列表

    Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startIntentSender(pendingIntent.getIntentSender(), intent, Intent.FLAG_ACTIVITY_NEW_TASK,         Intent.FLAG_ACTIVITY_NEW_TASK, 0);

    2.通过auto回复消息:

           利用虚拟点击回复微信消息,有两个天然的弊端就是一是AccessibilityService可能会被系统kill,这样的话使用的时候必须检测且手动开启,非常麻烦。二是微信的控件id和布局会随着微信版本的升级不断地变化,适配的工作量会不断的增大,且重复id变多,代码越写越麻烦,不易维护。

           在Android 5.0以后Android推出了一个Android auto的功能,这里我们可以借鉴使用来实现回复的功能,这个功能使用起来更方便且易维护

            在微信生成一个Notification的时候,如果检测到手机上有安装Android auto apk,会在Notification中加入扩展的数据,我们就是要利用这块数据来做事情。

            Android auto是原声谷歌应用,国内手机基本上是没有的,也没有谁去会去专门安装这个apk(感兴趣的可以去下载一个体验下),那么我们又要使用,只有“欺骗”微信了,我们可以在手机端安装一个包名为“com.google.android.projection.gearhead” 的apk(可以自己创建一个同样包名的apk安装在手机上即可,没必要安装auto),当微信在创建Notification的时候会检测这个apk是否存在,如果存在就在Notification中扩展了数据字段。

    通过NotificationListenerService获取微信的通知,如果安装了auto,在回复微信的时候就可以使用如下代码直接回复

    sbn是StatusBarNotification的缩写,在NotificationListenerService中获取

        @Override     public void onNotificationPosted(StatusBarNotification sbn) {     ...         } catch (ClassCastException e) {         }     }  

    ​     public void Test() {         Notification notification = sbn.getNotification();//sbn可以看前面         if (notification != null) {             NotificationCompat.CarExtender mCarExtender = new NotificationCompat.CarExtender(notification);             if (mCarExtender != null) {                 NotificationCompat.CarExtender.UnreadConversation conversation = mCarExtender.getUnreadConversation();                 if (conversation != null) {                     PendingIntent pendingReply = conversation.getReplyPendingIntent();                     RemoteInput remoteInput = conversation.getRemoteInput();                     String key = remoteInput.getResultKey();                       if (pendingReply != null) {                         Intent localIntent = new Intent();                         Bundle resultBundle = new Bundle();                         resultBundle.putString(key, "回复的内容");                         RemoteInput.addResultsToIntent(new RemoteInput[]{new RemoteInput.Builder(key).build()}, localIntent, resultBundle);                         try {                             pendingReply.send(mContext, 0, localIntent);                         } catch (Exception e) {                         }                     }                 }             }         }     }   ​ 加一段demo代码,获取Notification的代码在上一篇文章中已经说明

      import android.app.Notification; import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.provider.Settings; import android.support.v4.app.NotificationCompat; import android.support.v4.app.RemoteInput; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast;   import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode;   public class MainActivity extends AppCompatActivity {       Button mtest;     ImageView mTestImg;//通知的头像       Notification mNotification;       @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         init();//初始化控件           toggleNotificationListenerService(this);           if (!isNotificationListenersEnabled()) {             gotoNotificationAccessSetting();         }         EventBus.getDefault().register(this);     }       private void toggleNotificationListenerService(Context context) {         PackageManager pm = context.getPackageManager();         pm.setComponentEnabledSetting(new ComponentName(context, MyNotificationListenerService .class),                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);           pm.setComponentEnabledSetting(new ComponentName(context, MyNotificationListenerService .class),                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);     }       protected boolean gotoNotificationAccessSetting() {         try {             Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);             startActivity(intent);             return true;         } catch (ActivityNotFoundException e) {//普通情况下找不到的时候需要再特殊处理找一次             try {                 Intent intent = new Intent();                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                 ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.Settings$NotificationAccessSettingsActivity");                 intent.setComponent(cn);                 intent.putExtra(":settings:show_fragment", "NotificationAccessSettings");                 startActivity(intent);                 return true;             } catch (Exception e1) {                 e1.printStackTrace();             }             Toast.makeText(this, "对不起,您的手机暂不支持", Toast.LENGTH_SHORT).show();             System.out.println("--------------对不起,您的手机暂不支持------------->>");             e.printStackTrace();             return false;         }     }       public boolean isNotificationListenersEnabled() {         String pkgName = getPackageName();         final String flat = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners");         System.out.println("-----flat-------->" + flat);         if (!TextUtils.isEmpty(flat)) {             final String[] names = flat.split(":");             for (int i = 0; i < names.length; i++) {                 final ComponentName cn = ComponentName.unflattenFromString(names[i]);                 if (cn != null) {                     if (TextUtils.equals(pkgName, cn.getPackageName())) {                         return true;                     }                 }             }         }         return false;     }         private void init() {         mtest = (Button) this.findViewById(R.id.test_btn);         mtest.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 test();             }         });           mTestImg = (ImageView) this.findViewById(R.id.test_img);     }       @Override     protected void onStart() {         super.onStart();         System.out.println("------onStart----");     }       @Override     protected void onResume() {         super.onResume();         System.out.println("------onResume----");     }       @Override     protected void onPause() {         super.onPause();         System.out.println("------onPause----");     }       @Subscribe(threadMode = ThreadMode.MAIN)     public void onMessageEvent(NoticesBean event) {           mTestImg.setImageBitmap(event.getLargeIcon());         mNotification = event.getNotification();     }       public void test() {         Notification notification = mNotification;         if (notification != null) {             NotificationCompat.CarExtender mCarExtender = new NotificationCompat.CarExtender(notification);             if (mCarExtender != null) {                 NotificationCompat.CarExtender.UnreadConversation conversation = mCarExtender.getUnreadConversation();                 if (conversation != null) {                     PendingIntent pendingReply = conversation.getReplyPendingIntent();                     RemoteInput remoteInput = conversation.getRemoteInput();                     String key = remoteInput.getResultKey();                       if (pendingReply != null) {                         Intent localIntent = new Intent();                         Bundle resultBundle = new Bundle();                         resultBundle.putString(key, "回复的内容");                         RemoteInput.addResultsToIntent(new RemoteInput[]{new RemoteInput.Builder(key).build()}, localIntent, resultBundle);                         try {                             pendingReply.send(MainActivity.this, 0, localIntent);                         } catch (Exception e) {                         }                     }                 }             }         }     }

    }

    Processed: 0.009, SQL: 10