Android开发之SmsManager和SmsMessage
Android的手机功能(通话与短信)都放在android.telephony包中,到了4.4时(也就是API19)android.provider.Telephony及相关类横空出世辅助电话功能以及制定安卓世界手机功能的新秩序。
短信功能用到了SmsManager和SmsMessage两个主要类。
接受短信广播,由Intent解析出短信内容明文, intent中的短信是以pud形式传出的,即byte[][]二位数组,
从Android 4.4开始,SmsMessage不推荐使用createFromPdu(byte[] pdu)
推荐使用createFromPdu(byte[], String)。
createFromPdu(byte[], String)
The message format is passed in the SMS_RECEIVED_ACTION as the format String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
第一个参数:意图为SMS_RECEIVED_ACTION中的PDU信息,是一个byte[]数组
第二个参数:通过上面的那段英文可以知道,第二个参数为"3gpp"(GSM/UMTS/LTE)或者"3gpp2"(CDMA/LTE)。所以第二个参数想要获取,可以通过
String format = intent.getStringExtra("format");
获取到,然后传入到形参中。
发送短信via Intent
万能的intent能够帮我们做很多事,只要你有“意图”它就会满足你。
1 private void sendMessageViaSystem() { 2 Uri uri = Uri.parse("smsto:"+etNumber.getText()); 3 Intent intent = new Intent(Intent.ACTION_VIEW,uri); 4 intent.putExtra("sms_body",etMessage.getText().toString()); 5 startActivity(intent); 6 }
发送短信via SmsManager
1 private void sendMessage() { 2 SmsManager smsManager = SmsManager.getDefault(); 3 smsManager.sendTextMessage(etNumber.getText().toString(), null, 4 etMessage.getText().toString(), null, null); 5 }
最简单的发送短信条件就是有电话号码和短信内容,调用SmsManager的sendTextMessage方法即可。
监听短信的发送状态
sendTextMessage方法的后两个参数是PendingIntent,函数原型如下:
1 * @param sentIntent if not NULL this <code>PendingIntent</code> is 2 * broadcast when the message is successfully sent, or failed. 3 * The result code will be <code>Activity.RESULT_OK</code> for success, 4 * or one of these errors:<br> 5 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 6 * <code>RESULT_ERROR_RADIO_OFF</code><br> 7 * <code>RESULT_ERROR_NULL_PDU</code><br> 8 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 9 * the extra "errorCode" containing a radio technology specific value, 10 * generally only useful for troubleshooting.<br> 11 * The per-application based SMS control checks sentIntent. If sentIntent 12 * is NULL the caller will be checked against all unknown applications, 13 * which cause smaller number of SMS to be sent in checking period. 14 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 15 * broadcast when the message is delivered to the recipient. The 16 * raw pdu of the status report is in the extended data ("pdu"). 17 public void sendTextMessage( 18 String destinationAddress, String scAddress, String text, 19 PendingIntent sentIntent, PendingIntent deliveryIntent)
而我们要监听发送状态就要用到这两个参数。与这个两个PendingIntent联系的是两个Broadcast Receiver,其会接收到发送过程中状态广播。就像上面参数解释的一样。
代码示例如下:
1 private String SMS_SEND_ACTIOIN = "SMS_SEND"; 2 private String SMS_DELIVERED_ACTION = "SMS_DELIVERED"; 3 4 private SmsStatusReceiver mSmsStatusReceiver; 5 private SmsDeliveryStatusReceiver mSmsDeliveryStatusReceiver; 6 7 @Override 8 protected void onResume() { 9 super.onResume(); 10 mSmsStatusReceiver = new SmsStatusReceiver(); 11 registerReceiver(mSmsStatusReceiver,new IntentFilter(SMS_SEND_ACTIOIN)); 12 13 mSmsDeliveryStatusReceiver = new SmsDeliveryStatusReceiver(); 14 registerReceiver(mSmsDeliveryStatusReceiver,new IntentFilter(SMS_DELIVERED_ACTION)); 15 } 16 17 @Override 18 protected void onPause() { 19 super.onPause(); 20 unregisterReceiver(mSmsStatusReceiver); 21 unregisterReceiver(mSmsDeliveryStatusReceiver); 22 } 23 24 private void sendMessage() { 25 SmsManager smsManager = SmsManager.getDefault(); 26 PendingIntent sentIntent = PendingIntent.getBroadcast(this, 0, new Intent(SMS_SEND_ACTIOIN), 0); 27 PendingIntent deliveryIntent = PendingIntent.getBroadcast(this, 0, 28 new Intent(SMS_DELIVERED_ACTION), 0); 29 smsManager.sendTextMessage(etNumber.getText().toString(), null, 30 etMessage.getText().toString(), sentIntent, deliveryIntent); 31 Log.d(TAG,"sent message."); 32 } 33 34 public class SmsStatusReceiver extends BroadcastReceiver { 35 36 @Override 37 public void onReceive(Context context, Intent intent) { 38 Log.d(TAG,"SmsStatusReceiver onReceive."); 39 switch(getResultCode()) { 40 case Activity.RESULT_OK: 41 Log.d(TAG, "Activity.RESULT_OK"); 42 break; 43 case SmsManager.RESULT_ERROR_GENERIC_FAILURE: 44 Log.d(TAG, "RESULT_ERROR_GENERIC_FAILURE"); 45 break; 46 case SmsManager.RESULT_ERROR_NO_SERVICE: 47 Log.d(TAG, "RESULT_ERROR_NO_SERVICE"); 48 break; 49 case SmsManager.RESULT_ERROR_NULL_PDU: 50 Log.d(TAG, "RESULT_ERROR_NULL_PDU"); 51 break; 52 case SmsManager.RESULT_ERROR_RADIO_OFF: 53 Log.d(TAG, "RESULT_ERROR_RADIO_OFF"); 54 break; 55 } 56 } 57 } 58 59 public class SmsDeliveryStatusReceiver extends BroadcastReceiver { 60 61 @Override 62 public void onReceive(Context context, Intent intent) { 63 Log.d(TAG,"SmsDeliveryStatusReceiver onReceive."); 64 switch(getResultCode()) { 65 case Activity.RESULT_OK: 66 Log.i(TAG, "RESULT_OK"); 67 break; 68 case Activity.RESULT_CANCELED: 69 Log.i(TAG, "RESULT_CANCELED"); 70 break; 71 } 72 } 73 }
短信接收
与发送状态监听类似,短信的接收也是用广播接收器。为了一直对短信广播的接收,我采用了在Manifest中注册广播的方法。
android:priority系统默认最大值为1000,但是为了获得最高优先级,可以设置为int的最大值,即2147483647
1 <receiver android:name="com.linc.intercept.SmsReceiver" > 2 <intent-filter android:priority="1000" > 3 <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 4 </intent-filter> 5 </receiver>
并且将用一个单独类作为短信接收类(这样的方式是不能将其放到内部类中的)。
1 public class SmsReceiver extends BroadcastReceiver { 2 private static final String TAG = "SmsReceiver"; 3 public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED"; 4 5 @Override 6 public void onReceive(Context context, Intent intent) { 7 String action = intent.getAction(); 8 Log.d(TAG,"action: "+action); 9 if (SMS_RECEIVED_ACTION.equals(action)) { 10 Bundle bundle = intent.getExtras(); 11 StringBuffer messageContent = new StringBuffer(); 12 if (bundle != null) { 13 Object[] pdus = (Object[]) bundle.get("pdus"); 14 for (Object pdu : pdus) { 15 SmsMessage message = SmsMessage.createFromPdu((byte[]) pdu); 16 String sender = message.getOriginatingAddress(); 17 Log.d(TAG,"sender: "+sender); 18 if ("10086".equals(sender) || "10010".equals(sender) || 19 "10001".equals(sender)) { 20 messageContent.append(message.getMessageBody()); 21 } 22 } 23 if(!messageContent.toString().isEmpty()) { 24 Log.d(TAG,"send message broadcast."); 25 Intent intentBroadcast = new Intent(); 26 intentBroadcast.putExtra("message", messageContent.toString()); 27 intentBroadcast.setAction("sms_received"); 28 context.sendBroadcast(intentBroadcast); 29 Log.d(TAG, "send broadcast and abort"); 30 // abortBroadcast(); 31 } 32 } 33 } 34 } 35 }
但是这样做的弊端就是,接收到的短信如何显示到界面?路有多条,我最后还是选择了广播。
1 private SmsReceiver mSmsReceiver; 2 @Override 3 protected void onResume() { 4 super.onResume(); 5 mSmsReceiver = new SmsReceiver(); 6 IntentFilter intentFilter = new IntentFilter(); 7 intentFilter.addAction("sms_received"); 8 registerReceiver(mSmsReceiver, intentFilter); 9 } 10 @Override 11 protected void onPause() { 12 super.onPause(); 13 unregisterReceiver(mSmsReceiver); 14 } 15 public class SmsReceiver extends BroadcastReceiver { 16 public static final String SMS_RECEIVED_ACTION = "sms_received"; 17 18 @Override 19 public void onReceive(Context context, Intent intent) { 20 String action = intent.getAction(); 21 Log.d(TAG,"action: "+action); 22 if (SMS_RECEIVED_ACTION.equals(action)) { 23 Bundle bundle = intent.getExtras(); 24 25 String messageContent = bundle.getString("message"); 26 tvMessage.setText(messageContent); 27 } 28 } 29 }