SMS によるテキストメッセージの受信とフィルター

SMS メッセージは、電子メールと同様に友人等とのコミュニケーションツールとして使われる他、 プッシュ通知手段などにも使われます。

プッシュというのは、一般的にサーバーから端末への即時性の高い通知のことです。

例えばサーバーで何らかの変更があったときに、クライアントの状態を変えたいとします。

この場合、何らかの方法でサーバーへ問合せを行う必要があるわけですが、 クライアント側から定期的に問合せを行い、変更を検出する方法がひとつあります。

ポーリングというやつですね。

ポーリングは考え方も実装も単純であるため、よくあるものではありますが、ユーザー数が増加するにつれ急速に問合せ数も増えるため、 多数のユーザーをサポートしたい場合の要求には向きません。

一方プッシュ通知というのもあります。これは要はサーバーからクライアントに対して、何かあったら何か教えるということです。

その方法としてクライアントとサーバーとの間の通信チャネルを開きっぱなしにすることもできますが、こちらもスケーリングの問題があります。

ここでは SMS による通知は即時性も高いし、通常通信チャネルもいわゆるデータ通信チャネルではなく、安定したサービスが期待できます。

特定のテキストメッセージのフィルター。ブロードキャストのアボート

しかし、アプリケーション内部で使うだけのデータなど、テキストメッセージングの Inbox に残っても邪魔なだけです。

こうした場合、特定の送信元からのメッセージあるいはその他何らかの条件(例えばボディー部に特別な文字を書いておくなど)で、 メッセージをフィルターして、このアプリケーションだけで完結させてしまうことも可能です。

ここで紹介するのはその方法です。

ポイントは、SMS_RECEIVED のブロードキャストを高い優先度で受け取り、それを他にブロードキャストしないというところです。

次の例では、送信元が "1234567890" の場合に、abortBroadcast メソッドを呼び出してブロードキャストを止めています。

これによって、他のアプリケーションが SMS_RECEIVED を受け取ることが出来なくなります。

package com.example.sms3;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;

public class SMSReceiveBroadcastReceiver 
  extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    
    Bundle bundle = intent.getExtras();
    SmsMessage[] msgs = null;
    
    if(bundle == null){
      return;
    }

    boolean b = false;
    StringBuilder sb = new StringBuilder();
    Object[] pdus = (Object[]) bundle.get("pdus");
    msgs = new SmsMessage[pdus.length];
    for(int i=0; i<msgs.length; i++){
      msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
      
      sb.append("--------" + i + "--------\n");
      String s = msgs[i].getOriginatingAddress();
      if(s.equals("1234567890")){
        b = true;
      }
      sb.append("OriginatingAddress: " +
      	msgs[i].getOriginatingAddress() + "\n");
      sb.append("MessageBody: " + 
      	msgs[i].getMessageBody() + "\n");
    }
    
    // Send Broadcast
    Intent broadcastIntent = new Intent();
    broadcastIntent.putExtra("txt", sb.toString());
    broadcastIntent.setAction(MainActivity.ACTION_RECEIVED);
    context.sendBroadcast(broadcastIntent);
    
    if(b){
      abortBroadcast();
    }
  }

}

優先度については、レシーバーの登録箇所、intent-filter の priority として高い整数値を設定すれば OK です。

<receiver android:name=".SMSReceiveBroadcastReceiver">
  <intent-filter
   android:priority="1000">
    <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
  </intent-filter>
</receiver>

尚、この値は Android のリファレンスによれば -1000 から 1000 の間で設定することになっています。

高い数字の方が高い優先度になります。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門