Android系統中關於短信(SMS)的操作

忙着遊戲的開發,很長一段時間沒來更新了。最近的一片都是去年更新的了。感嘆時間過得真快啊。今天記錄下Android手機上的短信操作,Android上的短信操作主要有這麼三種:
1、發送短信
2、收短信
3、查看短信
下面逐個介紹;首先看下發送短信的demo

輸入手機號碼、短信內容;點擊發送按鈕便發送短信到指定號碼的手機上了。當然這裏只是個很簡單demo了,如果做個良好用戶體驗的應用那還有很多內容需要判斷的:1、手機號碼的合法性2、短信內容是否過長(超過140個字)3、短信發送狀態的跟蹤,並提示用戶關於這些操作的api,後面會陸續介紹。先看下這個簡單demo:發送短信操作涉及到用戶的個人信息和手機資費,所以必須獲得用戶的授權。在Androidmenifest.xml文件中添加相應的權限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sendsms"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="15" />

    <uses-permission android:name="android.permission.SEND_SMS" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MainActivity 的代碼:
public class MainActivity extends Activity {
	private static final String TAG = "MainActivity";

	EditText phoneNumberTxt;
	EditText msgTxt;
	Button sendBtn;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		phoneNumberTxt = (EditText) findViewById(R.id.phone_number_txt);
		msgTxt = (EditText) findViewById(R.id.msg_txt);
		sendBtn = (Button) findViewById(R.id.send_btn);

		sendBtn.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				String phoneNumber = phoneNumberTxt.getText().toString();
				String msg = msgTxt.getText().toString();

				if (phoneNumber.length() > 0 && msg.length() > 0) {
					sendSMS(phoneNumber, msg);				
				} else {
					Toast.makeText(MainActivity.this, "請輸入手機號和短信內容", Toast.LENGTH_SHORT).show();
				}
			}
		});
	}

	private void sendSMS(String number, String message) {
		SmsManager smsManager = SmsManager.getDefault();
		smsManager.sendTextMessage(number, null, message, null, null);
	}
}

發送短信的操作在sendSMS方法中,需要注意的是Android framework中有兩個SmsManager。
android.telephony.gsm.SmsManager和android.telephony.SmsManager;從Api level 4開始前者就被後者代替了。因爲後者同時支持GSM和CDMA。
上面發送短信的操作非常簡單,但是發送短信的整個過程用戶體驗很差,短信是否發送出去?對方是否已經接收到了?這些都未提示。要做到更好的用戶
體驗就需要仔細閱讀下sendTextMessage這個API了。


destinationAddress the address to send the message to

scAddress is the service center address or null to use the current default SMSC 

text                 the body of the message to send

sentIntent if not NULL this PendingIntent is broadcast when the message is successfully sent, or failed. The result code will be Activity.RESULT_OK for success, or one of these errors:
RESULT_ERROR_GENERIC_FAILURE
RESULT_ERROR_RADIO_OFF
RESULT_ERROR_NULL_PDU
For RESULT_ERROR_GENERIC_FAILURE the sentIntent may include the extra "errorCode" containing a radio technology specific value, generally only useful for troubleshooting.The per-application based SMS control checks sentIntent. If sentIntent is NULL the caller will be checked against all unknown applications, which cause smaller number of SMS to be sent in checking period.
deliveryIntent if not NULL this PendingIntent is broadcast when the message is delivered to the recipient. The raw pdu of the status report is in the extended data ("pdu").

這裏簡單描述下五個參數
destinationAddress  短信的目標地址,也就是短信要發送到的手機號碼
scAddress  關於這個地址可以查看 wiki文檔 http://en.wikipedia.org/wiki/Short_message_service_center,沒有特別指定就設置爲null
text 這個爲短信的內容
sentIntent  一個PendingIntent,在短信發送成功後發送的廣播。(關於PendingIntent這裏暫時不表,後面會寫文章介紹。這裏只需要知道可以通過它在短信發送成功後調用提示用戶發送成功的代碼)
deliveryIntent 同樣是PendingIntent,是在對方接收到短信後發送的廣播。
這裏需要明白的是:短信發送並不是點對點(P2P),A發送短信給B,並不是直接就發送到B上,中間是要經過運營商的。所以會分兩步,第一步是短信成功發送到運營商,第二步是運營商成功發送到目標用戶。
所以這裏會出現sentIntent,deliveryIntent兩個PendingIntent。找到這兩個入口點後,就可以添加一些代碼來完成良好的用戶體驗了。

public class MainActivity extends Activity {

	private static final String TAG = "MainActivity";
	private static final String SENT = "SENT_SMS";
	private static final String DELIVERED = "DELIVERED_SMS";

	EditText phoneNumberTxt;
	EditText msgTxt;
	Button sendBtn;

	BroadcastReceiver sentReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			Log.e(TAG, "sent receiver onReceive");
			switch (getResultCode()) {
			case SmsManager.RESULT_ERROR_NO_SERVICE:
				showToast("短信服務不可用");
				break;
			case SmsManager.RESULT_ERROR_NULL_PDU:
				showToast("沒有短信格式描述單元");
				break;
			case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
				showToast("短信未發送成功");
				break;
			case SmsManager.RESULT_ERROR_RADIO_OFF:
				showToast("沒有信號");
				break;
			case Activity.RESULT_OK:
				showToast("短信已發送");
				break;
			default:
				break;
			}
		}
	};

	BroadcastReceiver deliveredReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			showToast("對方已經接收到短信");
		}
	};

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		phoneNumberTxt = (EditText) findViewById(R.id.phone_number_txt);
		msgTxt = (EditText) findViewById(R.id.msg_txt);
		sendBtn = (Button) findViewById(R.id.send_btn);

		sendBtn.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				String phoneNumber = phoneNumberTxt.getText().toString();
				String msg = msgTxt.getText().toString();

				if (phoneNumber.length() > 0 && msg.length() > 0) {
					sendSMSWithMonitor(phoneNumber, msg);
				} else {
					Toast.makeText(MainActivity.this, "請輸入手機號和短信內容", Toast.LENGTH_SHORT).show();
				}
			}
		});
	}

	@Override
	protected void onResume() {
		super.onResume();
		registerReceiver(sentReceiver, new IntentFilter(SENT));
		registerReceiver(deliveredReceiver, new IntentFilter(DELIVERED));
	}

	@Override
	protected void onPause() {
		super.onPause();
		unregisterReceiver(sentReceiver);
		unregisterReceiver(deliveredReceiver);
	}

	private void sendSMSWithMonitor(String number, String message) {
		PendingIntent sendPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
		PendingIntent deliveredPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(DELIVERED), 0);

		SmsManager smsManager = SmsManager.getDefault();
		smsManager.sendTextMessage(number, null, message, sendPendingIntent, deliveredPendingIntent);
	}

	private void showToast(String text) {
		Toast.makeText(this, text, Toast.LENGTH_LONG).show();
	}
}

相對之前的代碼主要添加了兩個BraodcastReceiver,接收短信發送成功和對方接收到的廣播。這裏使用的是兩個隱式Intent來廣播。關於顯示Intent和隱式Intent會在後面的文章中說明。上面代碼發送的短信是在系統的短信庫裏無法查到的,因爲並未寫入到系統的短信庫中。如何寫入到系統的短信庫,後面的短信內容操作會詳細介紹。

介紹完發送短信後,接着介紹下接收短信。接收短信相對發送短信來得簡單得多。Android系統在接收到短信後會廣播一個android.provider.Telephony.SMS_RECEIVED消息,接收短信只需接收這個消息,顯示短信的內容即可。
public class SMSReceiver extends BroadcastReceiver {


	@Override
	public void onReceive(Context context, Intent intent) {
		Bundle bundle = intent.getExtras();
		SmsMessage[] msgs = null;
		StringBuilder sb = new StringBuilder();
		if (bundle != null) {
			Object[] pdus = (Object[]) bundle.get("pdus");
			msgs = new SmsMessage[pdus.length];
			for (int i = 0; i < pdus.length; i++) {
				msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
				sb.append(buildContentFromSmsMessage(msgs[i])).append("\n");
			}
			Toast.makeText(context, sb.toString(), Toast.LENGTH_SHORT).show();
		}


	}


	private String buildContentFromSmsMessage(SmsMessage smsMsg) {
		return smsMsg.getOriginatingAddress() + " : " + smsMsg.getMessageBody().toString();
	}
}
代碼中出現的pdus表示的多個PDU,PDU是短信的數據格式(內部包含指令和數據),具體查看wiki文檔http://en.wikipedia.org/wiki/Protocol_data_unit

同時在Androidmenifest.xml文件中註冊:
<receiver android:name=".SMSReceiver" >
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

先寫到這,後面會盡快更新短信的操作。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章