眾所周知,Android 6.0 相比之前的Android版本有一個(gè)很大的不同點(diǎn),就是動(dòng)態(tài)獲取權(quán)限。今天自己在做撥號(hào)功能時(shí),正巧遇到這個(gè)問(wèn)題, 順手記錄下在Android 6.0 上如何動(dòng)態(tài)獲取權(quán)限。
下面從自己一開(kāi)始的問(wèn)題入手
原網(wǎng)址
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1110/3670.html
說(shuō)到撥號(hào),一個(gè) Intent 就搞定,代碼如下,
PRivate void callDirectly(String mobile){ Intent intent = new Intent(); intent.setAction("android.intent.action.CALL"); intent.setData(Uri.parse("tel:" + mobile)); mContext.startActivity(intent); }當(dāng)然 你可別忘了在 Manifest 文件中去聲明撥號(hào)的權(quán)限
<uses-permission android:name="android.permission.CALL_PHONE" />問(wèn)題
如果在Android6.0以前的設(shè)備上,上面的代碼都是沒(méi)有問(wèn)題的,但是如果是在Android6.0設(shè)備上, 你就會(huì)發(fā)現(xiàn),撥號(hào)鍵盤是不能正常吊起的,因?yàn)?Android M 的權(quán)限是在運(yùn)行時(shí)動(dòng)態(tài)賦給用戶的。關(guān)于動(dòng)態(tài)分配權(quán)限,一些同學(xué)可能不是很清楚。 這里稍稍提一下 Android6.0 的權(quán)限動(dòng)態(tài)分配。如果你只對(duì)最終的解決方案感興趣,可以跳過(guò)下面這節(jié),直接去看解決方案
權(quán)限動(dòng)態(tài)分配
在 Android6.0 之前,下載好一個(gè)應(yīng)用程序,點(diǎn)擊安裝我們看到的大都是像這樣的界面。
上圖分別是Nexus6和小米手機(jī)在安裝軟件時(shí)的界面。
在安裝時(shí)你會(huì)發(fā)現(xiàn),手機(jī)操作系統(tǒng)會(huì)提示,這個(gè)軟件會(huì)索要了你手機(jī)的那些權(quán)限,并且給用一個(gè)列表進(jìn)行展示,但是這些提示只是在安裝是提示,只要你點(diǎn)擊接受或者安裝, 表示你允許這個(gè)應(yīng)用在可以獲取它申明的所有權(quán)限。一般很少有人在安裝時(shí),會(huì)因?yàn)榭吹侥硞€(gè)應(yīng)用因?yàn)樯暾?qǐng)了某一個(gè)敏感權(quán)限而放棄安裝應(yīng)用。因?yàn)檫@個(gè)權(quán)限雖然敏感, 但是對(duì)于當(dāng)前的用戶是不可感知的,因?yàn)樗F(xiàn)在并沒(méi)有立即去查看你的最近通話、短信記錄…
說(shuō)到這里,我們自然而然的會(huì)想到,其實(shí)最好的方式是,當(dāng)這個(gè)應(yīng)用在用戶使用過(guò)程中,正準(zhǔn)備使用某個(gè)權(quán)限時(shí),比如說(shuō)讀取短信列表,系統(tǒng)能及時(shí)的彈出一個(gè)提示框,說(shuō)這個(gè)應(yīng)用要讀取您的短信內(nèi)容, 您是否允許。然后用戶結(jié)合當(dāng)前應(yīng)用的執(zhí)行動(dòng)作,依據(jù)當(dāng)前條件判斷,是不是應(yīng)該授予應(yīng)用讀取短信記錄的權(quán)限。這絕對(duì)的最完美的。 因?yàn)樵诰唧w的使用過(guò)程中,用戶可以結(jié)合當(dāng)前應(yīng)用的使用場(chǎng)景,去思考、判斷是不是應(yīng)該給這個(gè)應(yīng)用相應(yīng)的權(quán)限。不給能怎樣,給了會(huì)怎樣, 這樣對(duì)用戶而言,完全是主動(dòng)的,相比安裝時(shí)那種選擇,這樣的做法無(wú)疑是對(duì)用戶莫大的尊重,同時(shí)這也保證了用戶的個(gè)人隱私。
說(shuō)到這里,不得不插一句,其實(shí) MIUI 早就實(shí)現(xiàn)了這個(gè)系統(tǒng)特性,在這一點(diǎn)上 MIUI 確實(shí)走到了 Android團(tuán)隊(duì)的前面,恩,給 MIUI 點(diǎn)個(gè)贊。
然而直到 Android 6.0 這個(gè)版本開(kāi)始,上面的假設(shè)終于得到了谷歌的實(shí)踐,除了在應(yīng)用安裝時(shí),操作系統(tǒng)會(huì)提示應(yīng)用會(huì)獲取那些權(quán)限,在運(yùn)行過(guò)程中,當(dāng)應(yīng)用去真的獲取一些敏感 權(quán)限時(shí),系統(tǒng)還會(huì)彈出一個(gè)提示框,詢問(wèn)用戶是不是授予應(yīng)用相應(yīng)的權(quán)限。如下圖所示。
這就是 Android 6.0 的運(yùn)行時(shí)權(quán)限檢查機(jī)制。下面是Google官方對(duì)此的解釋,只截取介紹部分
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen.
解決方案
對(duì)Android版本做判斷,然后對(duì)Android 6.0 做特殊處理,代碼如下
final public static int REQUEST_CODE_ASK_CALL_PHONE = 123; public void onCall(String mobile){ this.mMobile = mobile; if (Build.VERSION.SDK_INT >= 23) { int checkCallPhonePermission = ContextCompat.checkSelfPermission(mContext,Manifest.permission.CALL_PHONE); if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(mContext,new String[]{Manifest.permission.CALL_PHONE},REQUEST_CODE_ASK_CALL_PHONE); return; }else{ //上面已經(jīng)寫(xiě)好的撥號(hào)方法 callDirectly(mobile); } } else { //上面已經(jīng)寫(xiě)好的撥號(hào)方法 callDirectly(mobile); } }此時(shí),如果一個(gè)Android6.0的用戶觸發(fā)撥號(hào)動(dòng)作,執(zhí)行上面的代碼,那么他將會(huì)看到一個(gè)很好看的MaterialDialog,如下圖所示。
那么用戶點(diǎn)擊拒絕或者允許,我們?cè)趺床拍苣玫交卣{(diào)呢,如果能拿到回調(diào),我們就可以根據(jù)用戶的選擇來(lái)執(zhí)行不同的操作了。
這里應(yīng)該會(huì)看到在 ActivityCompat 的 requestPermissions 方法中,最后一個(gè)參數(shù)是一個(gè)requestCode,看到它自然而然想到了經(jīng)常用到的onActivityResult, 這里當(dāng)執(zhí)行 ActivityCompat 的 requestPermissions 方法后有一個(gè)回調(diào)機(jī)制,需要我們?cè)诋?dāng)前 Activity 中實(shí)現(xiàn) onRequestPermissionsResult 這個(gè)方法,具體如下
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case REQUEST_CODE_ASK_CALL_PHONE: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission Granted callDirectly(mobile); } else { // Permission Denied Toast.makeText(MainActivity.this, "CALL_PHONE Denied", Toast.LENGTH_SHORT) .show(); } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }這里會(huì)對(duì)提供了一個(gè)對(duì)用戶點(diǎn)擊做判斷的入口,開(kāi)發(fā)者可以根據(jù) grantResults[0] 的類型,來(lái)判斷用戶點(diǎn)擊的是允許還是拒絕,接著就可以執(zhí)行相應(yīng)的邏輯了。
關(guān)于AndroidM上權(quán)限的動(dòng)態(tài)獲取,這里只給出了一個(gè)最簡(jiǎn)單的示例,如果你還沒(méi)有盡興,那么下面這篇國(guó)外的博文,一定會(huì)讓你滿足。
Everything every Android Developer must know about new Android’s Runtime Permission
這篇英文博文內(nèi)容很長(zhǎng)、內(nèi)容也比較多,十足的干貨。您慢用~
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注