引言
本文通過運行兩個Android模擬器,介紹在Android中如何實現(xiàn)短信服務(wù)(SMS,short message service)的功能。通過這個例子,我想帶給大家的是:更加熟悉之前介紹過的Android應(yīng)用程序的概念及技術(shù)細節(jié),且通過實例調(diào)度大家的興趣。我之所以選擇SMS為例子,主要原因是SMS已經(jīng)非常成熟了,從中可以發(fā)掘更多的信息和技術(shù)細節(jié),而且我相信大部分人發(fā)短信比打電話多。
本文的主要內(nèi)容如下:
- 1、溫故知新
- 2、準(zhǔn)備工作:SMS涉及的主要類SmsManager
-
3、簡單的SMS發(fā)送程序
- 3.1、運行SMS程序給另一個android模擬器發(fā)短
- 4、SMS增強(一)
- 5、SMS增強(二)
- 6、SMS接收程序(下篇)
- 7、emulator工具(下篇)
- 8、…
1、溫故知新
廣播接收者 :一個廣播接收者是這樣一個組件,它不做什么事,僅是接受廣播公告并作出相應(yīng)的反應(yīng)。許多廣播源自于系統(tǒng)代碼,例如公告時區(qū)的改變、電池電量低、已采取圖片、用戶改變了語言偏好。應(yīng)用程序也可以發(fā)起廣播,例如為了他其他程序知道某些數(shù)據(jù)已經(jīng)下載到設(shè)備且他們可以使用這些數(shù)據(jù)
BroadcastReceiver 類:是接受 sendBroadcast() 發(fā)送的意圖(intents)的基類。可以用 Context.registerReceiver() 動態(tài)地注冊這個類的實例,或者通過 AndroidManifest.xml 中<receiver>標(biāo)簽靜態(tài)發(fā)布。
廣播接收者不顯示一個用戶界面。然而,它們啟動一個活動去響應(yīng)收到的信息,或者他們可能使用
NotificationManager
去通知用戶。通知可以使用多種方式獲得用戶的注意——閃爍的背光、振動設(shè)備、播放聲音等等。典型的是放在一個持久的圖標(biāo)在狀態(tài)欄,用戶可以打開獲取信息。
2、準(zhǔn)備工作:SMS涉及的主要類SmsManager
實現(xiàn)SMS主要用到 SmsManager 類,該類繼承自 java.lang.Object 類,下面我們介紹一下該類的主要成員。
公有方法:
-
ArrayList
<
String
>
divideMessage
(String text)
當(dāng)短信超過SMS消息的最大長度時,將短信分割為幾塊。
參數(shù) : text ——初始的消息,不能為空
返回值 :有序的 ArrayList < String > ,可以重新組合為初始的消息 -
static
SmsManager
getDefault
()
獲取SmsManager的默認實例。
返回值 : SmsManager 的默認實例 -
void
SendDataMessage
(
String
destinationAddress
,
String
scAddress
,
short
destinationPort
,
byte[]
data
,
PendingIntent
sentIntent,
PendingIntent
deliveryIntent)
發(fā)送一個基于SMS的數(shù)據(jù)到指定的應(yīng)用程序端口。
參數(shù) :
1)、 destinationAddress ——消息的目標(biāo)地址
2)、 scAddress ——服務(wù)中心的地址or為空使用當(dāng)前默認的SMSC 3) destinationPort ——消息的目標(biāo)端口號
4)、 data ——消息的主體,即消息要發(fā)送的數(shù)據(jù)
5)、 sentIntent ——如果不為空,當(dāng)消息成功發(fā)送或失敗這個PendingIntent就廣播。結(jié)果代碼是Activity.RESULT_OK表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU之一表示錯誤。對應(yīng)RESULT_ERROR_GENERIC_FAILURE, sentIntent 可能包括額外的“錯誤代碼”包含一個無線電廣播技術(shù)特定的值,通常只在修復(fù)故障時有用。
每一個基于SMS的應(yīng)用程序控制檢測 sentIntent 。如果 sentIntent 是空,調(diào)用者將檢測所有未知的應(yīng)用程序,這將導(dǎo)致在檢測的時候發(fā)送較小數(shù)量的SMS。
6)、 deliveryIntent ——如果不為空,當(dāng)消息成功傳送到接收者這個PendingIntent就廣播。
異常 :如果 destinationAddress 或 data 是空時,拋出IllegalArgumentException異常。 -
void
sendMultipartTextMessage
(
String
destinationAddress
,
String
scAddress
,
ArrayList
<
String
>
parts
,
ArrayList
<
PendingIntent
>
sentIntents, ArrayList
<
PendingIntent
>
?
deliverIntents)
發(fā)送一個基于SMS的多部分文本,調(diào)用者應(yīng)用已經(jīng)通過調(diào)用 divideMessage (String text)將消息分割成正確的大小。
參數(shù) :
1)、 destinationAddress ——消息的目標(biāo)地址
2)、 scAddress ——服務(wù)中心的地址or為空使用當(dāng)前默認的SMSC
3)、 parts ——有序的 ArrayList < String > ,可以重新組合為初始的消息
4)、 sentIntents ——跟 SendDataMessage 方法中一樣,只不過這里的是一組PendingIntent
5)、 deliverIntents ——跟 SendDataMessage 方法中一樣,只不過這里的是一組PendingIntent
異常 :如果 destinationAddress 或 data 是空時,拋出IllegalArgumentException異常。 -
void
sendTextMessage
(
String
destinationAddress,
String
scAddress,
String
text,
PendingIntent
sentIntent,
PendingIntent
deliveryIntent)
發(fā)送一個基于SMS的文本。參數(shù)的意義和異常前面的已存在的一樣,不再累述。
常量:
-
public static final int
RESULT_ERROR_GENERIC_FAILURE
表示普通錯誤,值為1(0x00000001) -
public static final int
RESULT_ERROR_NO_SERVICE
表示服務(wù)當(dāng)前不可用,值為4 (0x00000004) -
public static final int
RESULT_ERROR_NULL_PDU
表示沒有提供pdu,值為3 (0x00000003) -
public static final int
RESULT_ERROR_RADIO_OFF
表示無線廣播被明確地關(guān)閉,值為2 (0x00000002) -
public static final int
STATUS_ON_ICC_FREE
表示自由空間,值為0 (0x00000000) -
public static final int
STATUS_ON_ICC_READ
表示接收且已讀,值為1 (0x00000001) -
public static final int
STATUS_ON_ICC_SENT
表示存儲且已發(fā)送,值為5 (0x00000005) -
public static final int
STATUS_ON_ICC_UNREAD
表示接收但未讀,值為3 (0x00000003) -
public static final int
STATUS_ON_ICC_UNSENT
表示存儲但為發(fā)送,值為7 (0x00000007)
3、簡單的SMS發(fā)送程序
1)、首先,編輯布局文件 res/layout/main.xml ,達到我們想要的結(jié)果,界面如下:
圖1、程序運行界面
?
對應(yīng)的xml代碼如下:
<?
xml version="1.0" encoding="utf-8"
?>
<
LinearLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
orientation
=
"vertical"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"fill_parent"
>
<
TextView
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"@string/txtPhoneNo"
/>
<!-- text's value define in res/values/strings.xml -->
<
EditText
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
id
=
"@+id/edtPhoneNo"
/>
<
TextView
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"@string/txtContent"
/>
<
EditText
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
minLines
=
"3"
android
:
id
=
"@+id/edtContent"
/>
<
Button
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"@string/btnText"
android
:
id
=
"@+id/btnSend"
/>
</
LinearLayout
>
?
?
相應(yīng)的要在 res/values/strings.xm 中添加上面定義的視圖的text的值,如下:
<?
xml version="1.0" encoding="utf-8"
?>
<
resources
>
<
string
name
=
"txtPhoneNo"
>
Please input phone NO:
</
string
>
<
string
name
=
"txtContent"
>
Please input SMS\'s content:
</
string
>
<
string
name
=
"btnText"
>
send!
</
string
>
<
string
name
=
"app_name"
>
SMS
</
string
>
</
resources
>
?
?
2)、做完這些準(zhǔn)備工作之后,我么要開始編寫代碼實現(xiàn)簡單的短信發(fā)送了。
通過第一步我們構(gòu)建好界面之后,現(xiàn)在要在上面的基礎(chǔ)上編寫業(yè)務(wù)邏輯了。大致過程為:在java源文件中,獲取用戶在edtPhoneNo中輸入的電話號碼,edtContent中輸入要發(fā)送的內(nèi)容;然后點擊btnSend按鈕發(fā)送短信,要達到這個目的我們要設(shè)置btnSend的OnClickListener以達到當(dāng)點擊它觸發(fā)發(fā)送短信的功能,而且要發(fā)送短信就要用到我們前面介紹的 SmsManager 類提供的方法接口。
設(shè)置btnSend的OnClickListener的代碼如下:
btnSend.setOnClickListener(
new
View.OnClickListener() {
public
void
onClick(View v) {
String phoneNo = edtPhoneNo.getText().toString();
String message = edtContent.getText().toString();
if
(phoneNo.length() > 0 && message.length() > 0){
//call sendSMS to send message to phoneNo
sendSMS(phoneNo, message);
}
else
Toast.makeText(getBaseContext(),
"
Please enter both phone number and message.
",
Toast.LENGTH_SHORT).show();
}
});
?
?
發(fā)送短信的功能的代碼如下:
private
void
sendSMS(String phoneNumber, String message) {
// ---sends an SMS message to another device---
SmsManager sms = SmsManager.getDefault();
PendingIntent pi = PendingIntent.getActivity(
this
, 0,
new
Intent(
this
,TextMessage.
class
), 0);
//if message's length more than 70 ,
//then call divideMessage to dive message into several part
//and call sendTextMessage()
//else direct call sendTextMessage()
if
(message.length() > 70) {
ArrayList<String> msgs = sms.divideMessage(message);
for
(String msg : msgs) {
sms.sendTextMessage(phoneNumber,
null
, msg, pi,
null
);
}
}
else
{
sms.sendTextMessage(phoneNumber,
null
, message, pi,
null
);
}
Toast.makeText(TextMessage.
this
, "
短信發(fā)送完成
", Toast.LENGTH_LONG).show();
}
?
?
如果你已經(jīng)看了第2節(jié)介紹的 SmsManager 類的介紹,代碼應(yīng)該很好理解。在這里要說明的是,sendTextMessage方法中的第4個和第5個參數(shù)PendingIntent設(shè)為null,這樣的話不能根據(jù)短信發(fā)出之后的狀態(tài)做相應(yīng)的事情,如短信發(fā)送失敗后的提醒、接收者成功接收后的回執(zhí)……完整的流程源碼如下:
TextMessage.java源文件全部代碼
?
?
3)運行前,還要在清單文件AndroidManifest.xml中加入允許發(fā)送短信的權(quán)限:
AndroidManifest.xml
?
3.1、運行SMS程序給另一個android模擬器發(fā)短信
運行上面我們編寫的TextMessage程序,另外在Windows的命令行下切換到tools目錄下,并輸入emulator –data smsReceiver,我的如下:
這樣就會啟動一個android模擬器,如下所示:( 注意它的編號:5556,就是用這個編號與它通信的 )
圖2、通過emulator啟動一個android模擬器
通過我們TextMessage程序啟動的android模擬器,編寫短信:
圖3、TextMessage程序個5556模擬器發(fā)短信
點擊發(fā)送之后,通過命令行啟動的5556號android模擬器會收到我們剛才發(fā)送的短信,如下所示:
圖4、收到短信的提示
tips:
如果通過命令行的emulator啟動android模擬器提示“NO DNS servers found!”,這時我們發(fā)的短信模擬器是收不到的。
-
在Windows下,如果電腦沒有介入網(wǎng)絡(luò),即找不DNS服務(wù)器的話會出現(xiàn)這種情況!
-
在Mac下,如果提示這個警告的話,可以這樣解決:檢查你是否有
/etc/resolv.conf文件,如果沒有的話,通過下面的命令行ln -s /private/var/run/resolv.conf /etc/resolv.conf可以解決。
4、SMS增強(一)
上面我們實現(xiàn)了一個簡單的SMS程序,下面我們要對它進行增強!你肯定已經(jīng)注意到了,我們上面的SMS程序的sendTextMessage方法中的第4個和第5個參數(shù)PendingIntent設(shè)為null,即sentIntent和deliveryIntent。
第4個參數(shù)-sendIntent,當(dāng)消息成功發(fā)送或發(fā)送失敗都將被觸發(fā)。廣播接收者的結(jié)果碼,Activity.RESULT_OK表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU之一表示錯誤。對應(yīng)RESULT_ERROR_GENERIC_FAILURE, sentIntent 可能包括額外的“錯誤代碼”包含一個無線電廣播技術(shù)特定的值,通常只在修復(fù)故障時有用。第5個參數(shù)-deliveryIntent,僅當(dāng)目標(biāo)接收到你的SMS消息才觸發(fā)。
為了跟蹤發(fā)出的短信的狀態(tài),實現(xiàn)和注冊Broadcast Receiver(廣播接收者)監(jiān)聽傳遞給sendTextMessage方法的參數(shù)Pending Intents。下面我們就實現(xiàn)和注冊這個廣播接收者:
String SENT_SMS_ACTION="
SENT_SMS_ACTION
";
String DELIVERED_SMS_ACTION="
DELIVERED_SMS_ACTION
";
//create the sentIntent parameter
Intent sentIntent=
new
Intent(SENT_SMS_ACTION);
PendingIntent sentPI=PendingIntent.getBroadcast(
this
,
0,
sentIntent,
0);
//create the deilverIntent parameter
Intent deliverIntent=
new
Intent(DELIVERED_SMS_ACTION);
PendingIntent deliverPI=PendingIntent.getBroadcast(
this
,
0,
deliverIntent,
0);
//register the Broadcast Receivers
registerReceiver(
new
BroadcastReceiver(){
@Override
public
void
onReceive(Context _context,Intent _intent)
{
switch
(getResultCode()){
case
Activity.RESULT_OK:
Toast.makeText(getBaseContext(),
"
SMS sent success actions
",
Toast.LENGTH_SHORT).show();
break
;
case
SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(getBaseContext(),
"
SMS generic failure actions
",
Toast.LENGTH_SHORT).show();
break
;
case
SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(getBaseContext(),
"
SMS radio off failure actions
",
Toast.LENGTH_SHORT).show();
break
;
case
SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(getBaseContext(),
"
SMS null PDU failure actions
",
Toast.LENGTH_SHORT).show();
break
;
}
}
},
new
IntentFilter(SENT_SMS_ACTION));
registerReceiver(
new
BroadcastReceiver(){
@Override
public
void
onReceive(Context _context,Intent _intent)
{
Toast.makeText(getBaseContext(),
"
SMS delivered actions
",
Toast.LENGTH_SHORT).show();
}
},
new
IntentFilter(DELIVERED_SMS_ACTION));
?
在基本完成了要做的工作,接下來要做的就是將sendTextMessage的第4個和第5個參數(shù)改為sentPI、deliverPI,這樣工作基本完成,修改后的sendSMS方法如下:
修改后的sendSMS方法完整代碼
?
運行之后的,發(fā)送短信成功的話就可以看到如下界面:
圖5、增強SMS(一)
5、SMS增強(二)
下面這個增強是使SMS能夠發(fā)送二進制數(shù)據(jù)。要發(fā)送數(shù)據(jù)要使用SmsManager類的sendDataMessage方法,跟sendTextMessage方法類似,只不過該方法多了一個目標(biāo)端口的參數(shù),構(gòu)建該SMS的過程跟前面的類似這里就不在累述。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

