【问题标题】:Listen outgoing SMS or sent box in Android在 Android 中收听传出的短信或已发送的邮箱
【发布时间】:2011-08-14 02:15:51
【问题描述】:

我正在开发一个应用程序,它将所有传入和传出的短信存储在 SD 卡中的文本文件中。

我可以使用广播接收器收听传入的消息。我发现很难收听传出的短信。

我在某种程度上知道需要设置已发送箱或发件箱上的内容观察器,但我不知道该怎么做。

如何做到这一点?

【问题讨论】:

    标签: android sms


    【解决方案1】:

    基本上,你必须注册一个内容观察者......像这样:

    ContentResolver contentResolver = context.getContentResolver();
    contentResolver.registerContentObserver(Uri.parse("content://sms/out"),true, yourObserver);
    

    yourObserver 是一个可能如下所示的对象 (new YourObserver(new Handler())):

    class YourObserver extends ContentObserver {
    
        public YourObserver(Handler handler) {
            super(handler);
        }
    
        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            // save the message to the SD card here
        }
    }
    

    那么,您究竟是如何获得短信内容的呢?你必须使用Cursor:

    // save the message to the SD card here
    Uri uriSMSURI = Uri.parse("content://sms/out");
    Cursor cur = this.getContentResolver().query(uriSMSURI, null, null, null, null);
     // this will make it point to the first record, which is the last SMS sent
    cur.moveToNext();
    String content = cur.getString(cur.getColumnIndex("body"));
    // use cur.getColumnNames() to get a list of all available columns...
    // each field that compounds a SMS is represented by a column (phone number, status, etc.)
    // then just save all data you want to the SDcard :)
    

    【讨论】:

    • 我应该使用光标来获取邮件正文吗?
    • 是的... 案例中的光标是指向每条短信记录的指针。稍微了解一下游标,你就会完全理解上面代码中发生了什么。
    • 非常感谢您帮助克里斯蒂安。你为我节省了很多时间。
    • 字符串“content://sms/out”对我不起作用。我使用了没有输出的“content://sms/”并检查了“type”列==2 是否传出
    • 在哪里注册观察者?我希望它在不启动应用程序的情况下注册或让应用程序在前台运行...
    【解决方案2】:

    这是我解决这个问题的方法

    1. 创建从其他活动调用的服务
    2. 在其中创建一个内容观察者

       @Override
       public int onStartCommand(Intent intent, int flag, int startId) {
       MyObserver myObserver = new MyObserver(new Handler());
       ContentResolver contentResolver = this.getApplicationContext().getContentResolver();
       contentResolver.registerContentObserver(Uri.parse("content://sms/sent"), true, myObserver);
       return START_STICKY;
       }
      
    3. 创建观察者类

      class MyObserver extends ContentObserver {
      
      public MyObserver(Handler handler) {
          super(handler);
      }
      
      @Override
      public void onChange(boolean selfChange) {
          super.onChange(selfChange);
          Uri uriSMSURI = Uri.parse("content://sms/sent");
          Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);
          cur.moveToNext();
          String content = cur.getString(cur.getColumnIndex("body"));
          String smsNumber = cur.getString(cur.getColumnIndex("address"));
          if (smsNumber == null || smsNumber.length() <= 0) {
              smsNumber = "Unknown";
          }
          cur.close();
      
          if(smsChecker( "OutgoingSMS to " + smsNumber + ": " + content)) {
              //save data into database/sd card here
          }
      }
      }
      
    4. 我添加了一个方法 smsChecker() 来检查新消息是否与上一条消息相同

      public boolean smsChecker(String sms) {
      boolean flagSMS = true;
      
      if (sms.equals(lastSMS)) {
          flagSMS = false;
      }
      else {
          lastSMS = sms;
      }
      //if flagSMS = true, those 2 messages are different
      return flagSMS;
      }
      

    如果我没记错的话,如果我们只想检查所有发送的消息,我们使用“content://sms/sent”,如果我们只想检查发件箱内的所有消息,我们使用“content://sms/out”,如果我们想检查所有消息,则为“content://sms”。

    【讨论】:

    • 如果两条消息合法地相同,例如多次说“是”,这将忽略第二条消息。请参阅stackoverflow.com/a/43393907/461982 了解更有效的验证重复项的方法。
    【解决方案3】:

    这是我的版本,已在Android 6.0+中验证

    class smsObserver extends ContentObserver {
    
        private String lastSmsId;
    
        public smsObserver(Handler handler) {
            super(handler);
        }
    
        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            Uri uriSMSURI = Uri.parse("content://sms/sent");
            Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);
            cur.moveToNext();
            String id = cur.getString(cur.getColumnIndex("_id"));
            if (smsChecker(id)) {
                String address = cur.getString(cur.getColumnIndex("address"));
                // Optional: Check for a specific sender
                if (address.equals(phoneNumber)) {
                    String message = cur.getString(cur.getColumnIndex("body"));
                    // Use message content for desired functionality
                }
            }
        }
    
        // Prevent duplicate results without overlooking legitimate duplicates
        public boolean smsChecker(String smsId) {
            boolean flagSMS = true;
    
            if (smsId.equals(lastSmsId)) {
                flagSMS = false;
            }
            else {
                lastSmsId = smsId;
            }
    
            return flagSMS;
        }
    }
    

    将此代码放在应启用观察者的位置

    ContentResolver contentResolver = getContentResolver();
    contentResolver.registerContentObserver(Uri.parse("content://sms"), true, new smsObserver(new Handler()));
    

    这假设您正在使用一个活动。请记住,您需要一个上下文引用才能从服务或接收器中调用getContentResolver()

    【讨论】:

    • @CrazyMind 更新了答案。从示例中删除“专有”代码时必须丢失。希望这对你有用。
    • 当您展示应该可以工作的代码时,您可能会考虑在分享之前对其进行测试。例如 mContext 从未定义。您是使用构造函数发送它还是什么?顺便提一句。这不适用于我的 Nexus 5,版本 6+
    • @miroslavign 如上所述,它是从实现中缩短的。您正在调用 getContentResolver() 并且它是假设您可能需要上下文引用而编写的。在盲目地将示例复制到自己的实现中之前,您应该花一些时间来理解示例。
    • @LoungeKatt tnx 进行编辑。它将帮助用户了解他们需要从服务或活动中提供上下文。仍然无法在 Nexus 5 上运行,但这可能与服务的正确上下文有关:ContentResolver contentResolver = getBaseContext().getContentResolver();
    • @miroslavign 大多数用户都知道mContext 是上下文引用。听起来您可能不熟悉上下文。我建议在 stackoverflow.com/a/14230055/461982 上查看有关如何获取上下文参考的答案。
    【解决方案4】:

    我看到出了什么问题。上线了:

     contentResolver.registerContentObserver(Uri.parse("content://sms/sent"), true, _myObserver);
    

    您必须删除 '/sent' 并只写 'content://sms' 它已在 ContentObserver 中指定以查看发送的短信。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-25
      • 1970-01-01
      • 1970-01-01
      • 2016-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多