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 の間で設定することになっています。
高い数字の方が高い優先度になります。