Android系統(tǒng)中調(diào)用電話和短信功能的實(shí)現(xiàn)方法
前言
- 本文將聚焦系統(tǒng)級(jí)功能調(diào)用——打電話與發(fā)短信。這兩個(gè)功能是移動(dòng)應(yīng)用的核心基礎(chǔ)能力,本質(zhì)是通過(guò)
Intent(意圖)喚醒Android系統(tǒng)自帶的電話/短信應(yīng)用,實(shí)現(xiàn)跨應(yīng)用交互。 - 對(duì)于后端開(kāi)發(fā)者,系統(tǒng)功能調(diào)用可類比“后端接口調(diào)用第三方服務(wù)”(如調(diào)用短信平臺(tái)API、支付接口):
Intent相當(dāng)于“請(qǐng)求參數(shù)”,系統(tǒng)應(yīng)用相當(dāng)于“第三方服務(wù)”,權(quán)限申請(qǐng)相當(dāng)于“接口調(diào)用授權(quán)”,整個(gè)流程遵循“請(qǐng)求→授權(quán)→執(zhí)行”的邏輯。
一、Intent與系統(tǒng)權(quán)限
調(diào)用系統(tǒng)功能的核心是Intent的“隱式意圖”(無(wú)需指定具體Activity,只聲明動(dòng)作和數(shù)據(jù)),再配合Android的“權(quán)限機(jī)制”(保護(hù)用戶隱私,需明確申請(qǐng)敏感權(quán)限)。
1.1 隱式意圖
隱式意圖不直接指定目標(biāo)組件(如系統(tǒng)電話應(yīng)用的Activity),而是通過(guò)Action(動(dòng)作)和Data(數(shù)據(jù))描述“要做什么”,由Android系統(tǒng)匹配對(duì)應(yīng)的系統(tǒng)應(yīng)用來(lái)執(zhí)行。
| 核心要素 | 作用 | 示例(打電話) |
|---|---|---|
Action | 聲明要執(zhí)行的動(dòng)作(如打電話、發(fā)短信) | Intent.ACTION_CALL(直接撥號(hào)) |
Data | 傳遞動(dòng)作所需的數(shù)據(jù)(如電話號(hào)碼、收件人) | Uri.parse("tel:666666")(目標(biāo)號(hào)碼) |
1.2 系統(tǒng)權(quán)限機(jī)制
打電話、發(fā)短信屬于“敏感權(quán)限”(涉及用戶通信隱私和費(fèi)用),Android 6.0(API 23)及以上版本要求動(dòng)態(tài)申請(qǐng)權(quán)限(僅在Manifest中聲明不夠,需在代碼中彈窗詢問(wèn)用戶授權(quán))。
| 權(quán)限類型 | 聲明方式 | 適用場(chǎng)景 |
|---|---|---|
| 靜態(tài)權(quán)限 | 在AndroidManifest.xml中聲明 | 低風(fēng)險(xiǎn)功能(如訪問(wèn)網(wǎng)絡(luò)、讀取外部存儲(chǔ)) |
| 動(dòng)態(tài)權(quán)限 | 代碼中申請(qǐng)+用戶手動(dòng)授權(quán) | 高風(fēng)險(xiǎn)功能(如打電話、發(fā)短信、獲取位置) |
二、實(shí)戰(zhàn)一:打電話功能實(shí)現(xiàn)(兩種方式)
打電話有兩種常用實(shí)現(xiàn)方式:直接撥號(hào)(無(wú)需用戶確認(rèn),需危險(xiǎn)權(quán)限)和跳轉(zhuǎn)到撥號(hào)盤(用戶手動(dòng)點(diǎn)擊撥打,需普通權(quán)限),可根據(jù)場(chǎng)景選擇。
2.1 方式一:直接撥號(hào)(ACTION_CALL)
直接喚醒系統(tǒng)電話應(yīng)用并撥打指定號(hào)碼,無(wú)需用戶額外操作,但需申請(qǐng)CALL_PHONE危險(xiǎn)權(quán)限。
2.1.1 步驟1:聲明靜態(tài)權(quán)限(AndroidManifest.xml)
在manifests/AndroidManifest.xml中添加權(quán)限聲明(放在<application>標(biāo)簽外):
<!-- 打電話權(quán)限(危險(xiǎn)權(quán)限) --> <uses-permission android:name="android.permission.CALL_PHONE" />
2.1.2 步驟2:代碼實(shí)現(xiàn)
以下是完整實(shí)現(xiàn)(含動(dòng)態(tài)權(quán)限申請(qǐng)):
public class MainActivity extends AppCompatActivity {
// 權(quán)限請(qǐng)求碼(自定義,需唯一)
private static final int REQUEST_CALL_PERMISSION = 100;
private Button callBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化按鈕
callBtn = findViewById(R.id.call);
callBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String phoneNum = "666666"; // 目標(biāo)電話號(hào)碼
// 1. 檢查是否已獲得權(quán)限
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
// 2. 權(quán)限已授權(quán),執(zhí)行打電話邏輯
callPhoneDirect(phoneNum);
} else {
// 3. 未授權(quán),申請(qǐng)動(dòng)態(tài)權(quán)限(彈窗詢問(wèn)用戶)
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CALL_PHONE},
REQUEST_CALL_PERMISSION);
}
}
});
}
// 直接撥號(hào)核心邏輯
private void callPhoneDirect(String phoneNum) {
Intent intent = new Intent(Intent.ACTION_CALL);
// 設(shè)置電話號(hào)碼(tel:是固定協(xié)議,不能省略)
intent.setData(Uri.parse("tel:" + phoneNum));
startActivity(intent);
}
// 監(jiān)聽(tīng)權(quán)限申請(qǐng)結(jié)果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CALL_PERMISSION) {
// 用戶同意授權(quán)
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
callPhoneDirect("666666");
} else {
// 用戶拒絕授權(quán),提示無(wú)法使用功能
Toast.makeText(this, "未授權(quán)打電話權(quán)限,功能無(wú)法使用", Toast.LENGTH_SHORT).show();
}
}
}
}
2.2 方式二:跳轉(zhuǎn)到撥號(hào)盤(ACTION_DIAL)
僅打開(kāi)系統(tǒng)撥號(hào)盤并填充號(hào)碼,需用戶手動(dòng)點(diǎn)擊“撥打”按鈕,無(wú)需動(dòng)態(tài)權(quán)限(僅需靜態(tài)聲明,甚至可省略),更安全。
2.2.1 代碼實(shí)現(xiàn)(無(wú)需動(dòng)態(tài)權(quán)限)
// 按鈕點(diǎn)擊事件中直接執(zhí)行
callBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String phoneNum = "666666";
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + phoneNum));
startActivity(intent);
}
});
2.2.2 兩種方式對(duì)比表
| 實(shí)現(xiàn)方式 | 核心Action | 權(quán)限要求 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|---|
| 直接撥號(hào) | Intent.ACTION_CALL | 動(dòng)態(tài)申請(qǐng)CALL_PHONE權(quán)限 | 操作便捷,無(wú)需用戶額外點(diǎn)擊 | 風(fēng)險(xiǎn)高(誤觸會(huì)產(chǎn)生費(fèi)用),需處理權(quán)限 |
| 跳轉(zhuǎn)撥號(hào)盤 | Intent.ACTION_DIAL | 無(wú)需動(dòng)態(tài)權(quán)限(靜態(tài)聲明可選) | 安全(用戶確認(rèn)后撥打),無(wú)權(quán)限風(fēng)險(xiǎn) | 多一步用戶操作 |
三、實(shí)戰(zhàn)二:發(fā)短信功能實(shí)現(xiàn)
發(fā)短信功能通過(guò)ACTION_SENDTO指定收件人,配合.putExtra("sms_body")傳遞默認(rèn)短信內(nèi)容,用戶可修改后發(fā)送,權(quán)限要求低于打電話。
3.1 步驟1:聲明靜態(tài)權(quán)限
發(fā)短信的SEND_SMS權(quán)限屬于危險(xiǎn)權(quán)限,但ACTION_SENDTO方式會(huì)跳轉(zhuǎn)到系統(tǒng)短信應(yīng)用,由系統(tǒng)應(yīng)用執(zhí)行發(fā)送操作,無(wú)需申請(qǐng)動(dòng)態(tài)權(quán)限(僅需在Manifest中聲明靜態(tài)權(quán)限,部分設(shè)備可不聲明):
<!-- 發(fā)短信權(quán)限(靜態(tài)聲明即可,無(wú)需動(dòng)態(tài)申請(qǐng)) --> <uses-permission android:name="android.permission.SEND_SMS" />
3.2 步驟2:代碼實(shí)現(xiàn)
Button smsBtn = findViewById(R.id.sms);
smsBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String phoneNum = "10086"; // 收件人號(hào)碼
String smsContent = "java1"; // 默認(rèn)短信內(nèi)容
// 1. 創(chuàng)建隱式意圖,指定動(dòng)作:發(fā)送短信
Intent intent = new Intent(Intent.ACTION_SENDTO);
// 2. 設(shè)置收件人(smsto:是固定協(xié)議,不能省略)
intent.setData(Uri.parse("smsto:" + phoneNum));
// 3. 傳遞默認(rèn)短信內(nèi)容(key固定為"sms_body")
intent.putExtra("sms_body", smsContent);
// 4. 啟動(dòng)系統(tǒng)短信應(yīng)用
startActivity(intent);
}
});
點(diǎn)擊“發(fā)短信”按鈕后,會(huì)自動(dòng)打開(kāi)系統(tǒng)短信應(yīng)用:
- 收件人已填充為“10086”;
- 短信內(nèi)容已填充為“java1”;
- 用戶可修改號(hào)碼或內(nèi)容,點(diǎn)擊發(fā)送即可。
3.4 關(guān)鍵注意事項(xiàng)
- 協(xié)議格式:
smsto:不能省略,否則系統(tǒng)無(wú)法識(shí)別是“發(fā)送短信”動(dòng)作,可能跳轉(zhuǎn)錯(cuò)誤應(yīng)用。 - 內(nèi)容傳遞:必須使用
intent.putExtra("sms_body", 內(nèi)容),key固定為sms_body(系統(tǒng)短信應(yīng)用只識(shí)別該key)。 - 權(quán)限說(shuō)明:若直接使用
SmsManager類發(fā)送短信(不跳轉(zhuǎn)到系統(tǒng)應(yīng)用),則需動(dòng)態(tài)申請(qǐng)SEND_SMS權(quán)限,推薦新手使用跳轉(zhuǎn)到系統(tǒng)應(yīng)用的方式(簡(jiǎn)單且安全)。
到此這篇關(guān)于Android系統(tǒng)中調(diào)用電話和短信功能的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Android調(diào)用電話和短信功能內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程實(shí)現(xiàn)google消息通知功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)google消息通知功能,結(jié)合具體實(shí)例形式分析了Android消息處理及C#服務(wù)器端與google交互的相關(guān)操作技巧,需要的朋友可以參考下2017-06-06
一行代碼教你解決Scrollview和TextInput焦點(diǎn)獲取問(wèn)題
這篇文章主要為大家介紹了一行代碼教你解決Scrollview和TextInput焦點(diǎn)獲取問(wèn)題,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Android自定義view實(shí)現(xiàn)拖動(dòng)小球移動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android自定義view實(shí)現(xiàn)拖動(dòng)小球移動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
Android自定義加載loading view動(dòng)畫(huà)組件
這篇文章主要為大家詳細(xì)介紹了Android自定義加載loading view動(dòng)畫(huà)組件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
Android簡(jiǎn)單實(shí)現(xiàn)引導(dǎo)頁(yè)
這篇文章主要為大家詳細(xì)介紹了Android簡(jiǎn)單實(shí)現(xiàn)引導(dǎo)頁(yè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04
Android實(shí)戰(zhàn)打飛機(jī)游戲之菜單頁(yè)面設(shè)計(jì)(1)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)戰(zhàn)打飛機(jī)游戲之菜單頁(yè)面設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07
Android通過(guò)ExifInterface判斷Camera圖片方向的方法
今天小編就為大家分享一篇關(guān)于Android通過(guò)ExifInterface判斷相機(jī)圖片朝向的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
Android基于OpenGL的GLSurfaceView創(chuàng)建一個(gè)Activity實(shí)現(xiàn)方法
這篇文章主要介紹了Android基于OpenGL的GLSurfaceView創(chuàng)建一個(gè)Activity實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Android中OpenGL圖形操作類GLSurfaceView的功能、用法及相關(guān)使用技巧,需要的朋友可以參考下2016-10-10
Android?debug包運(yùn)行正常release包崩潰的解決辦法
這篇文章主要介紹了Android?debug包運(yùn)行正常,release包崩潰解決辦法,文中通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家解決問(wèn)題有一定的幫助,需要的朋友可以參考下2024-04-04

