Android 6 授權架構
應用程式若需要使用到系統聯絡人等個人機密資料時, 需於設定檔加入授權設定. 此時使用者下載安裝時, 會彈出是否允許授權. 這種機制可以防止惡意程式在暗中搞鬼偷取個人資料.
設定檔授權設定如下, 需寫於<application>標簽的上面
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.ddns.mahaljsp.ch11_02_system_action" >
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application> .... </application>
但這種授權模式, 有個缺失, 就是如果應用程式要求10幾個授權, 使用者要一一允許授權. 若其中一項不允許, 應用程式就不會安裝
到了Android 6.0(API 23)開始, 使用新的授權架構, 將授權分二大類
Normal permissions : 一般授權, 不影響使用者隱私的授權, 安裝時系統會自動授權
Dangerous permissions : 危險授權, 可以存取使用者隱私資料的授權. 使用者運作此應用程式時, 需執行授權工作, 開發人員需執行相關的設計與判斷
也就是說, 在Android 6.0中, 下載安裝應用程式時, 並不會要求允許授權, 而是在執行中若需要使用到危險授權, 才會彈出詢問.
這兩種權限同樣都要在AndroidManifest.xml中使用<uses-permission>宣告. 在執行應用程式時, 若要存取危險權限, 還需要使用requestPermissions()方法, 此時畫面會出現請求權限的對話框, 要求使用者允許存取資料.
危險權限依照功能分為以下幾個組別:
| No | Group | Item | Remark |
| 1 | CALENDAR日曆 | READ_CALENDAR | 讀取日曆 |
| WRITE_CALENDAR | 寫入日曆 | ||
| 2 | CAMERA | CAMERA | 相機拍照功能 |
| 3 | CONTACTS聯絡人 | READ_CONTACTS | 讀取聯絡人 |
| WRITE_CONTACTS | 寫入聯絡人 | ||
| GET_ACCOUNTS | 取得手機帳號 | ||
| 4 | LOCATION位置 | ACCESS_FINE_LOCATION | 取得精確位置 |
| ACCESS_COARSE_LOCATION | 取得大約位置 | ||
| 5 | MICROPHONE麥克風 | RECORD_AUDIO | 錄製聲音 |
| 6 | PHONE電話 | READ_PHONE_STATE | 讀取通話狀態 |
| CALL_PHONE | 撥出電話 | ||
| READ_CALL_LOG | 讀取通話記錄 | ||
| WRITE_CALL_LOG | 寫入通話記錄 | ||
| ADD_VOICEMAIL | 新增語音留言 | ||
| USE_SIP | 使用SIP網路電話 | ||
| PROCESS_OUTGOING_CALLS | 存取撥出電話 | ||
| 7 | SENSORS感應器 | BODY_SENSORS | 讀取體感資料 |
| 8 | SMS簡訊 | SEND_SMS | 傳送簡訊 |
| RECEIVE_SMS | 接收簡訊 | ||
| READ_SMS | 讀取簡訊 | ||
| RECEIVE_WAP_PUSH | 接收WAP推播訊息 | ||
| RECEIVE_MMS | 接收多媒體簡訊 | ||
| 9 | STORAGE儲存 | READ_EXTERNAL_STORAGE | 讀取外部儲存 |
| WRITE_EXTERNAL_STORAGE | 寫入外部儲存 |
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_PERMISSION=100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
processPermission();
}
private void processPermission(){
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
int hasPermission=checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
if(hasPermission!= PackageManager.PERMISSION_GRANTED){
requestPermissions(
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION_PERMISSION);
}
else{
init();
}
}
else{
init();
}
}
@Override
public void onRequestPermissionsResult(
int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
if(requestCode==REQUEST_LOCATION_PERMISSION){
if (grantResults[0]==PackageManager.PERMISSION_GRANTED){
init();
}
else{
Toast.makeText(this, "No permission", Toast.LENGTH_LONG).show();
}
}
else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void init(){
Intent intent=new Intent();
intent.setAction(Intent.ACTION_CALL);
Uri uri=Uri.parse("tel:0987000000");
intent.setData(uri);
startActivity(intent);
}
}
上述程式碼中, 利用 Build.VERSION.SDK_INT>=Build.VERSION_CODES.M 來判斷目前的裝置版本是否大於23. 如果是大於23, 就要用Activity的checkSelfPermission(String)方法來檢查是否有授權. 如果檢查結果不是 PackageManager.PERMISSION_GRANTED, 就要用Activity的 requestPermissions() 方法請求授權. 當結束授權對話方框後, 會回到Activity的
public void onRequestPermissionsResult() 方法, 所以在這方法中再檢查一次是否得到了PackageManager.PERMISSION_GRANTED, 如果得到授權了, 就開始撥打電話. 如果沒得到授權, 就顯示權限不足
多項權限
AndroidManifest.xml 加入如下三項權限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
public class MainActivity extends AppCompatActivity { String perms[]=new String[3]; final public static int REQUEST_PERMISSION=100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); perms[0] = Manifest.permission.ACCESS_FINE_LOCATION; perms[1] = Manifest.permission.CAMERA; perms[2] = Manifest.permission.WRITE_EXTERNAL_STORAGE; processPermission(); } private void processPermission(){ if(Build.VERSION.SDK_INT<Build.VERSION_CODES.M) { init(); } else{ if(checkSelfPermission(perms[0])!= PackageManager.PERMISSION_GRANTED || checkSelfPermission(perms[1])!= PackageManager.PERMISSION_GRANTED || checkSelfPermission(perms[2])!= PackageManager.PERMISSION_GRANTED){ requestPermissions(perms, REQUEST_PERMISSION); } else{ init(); } } } private void init(){}; public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if(requestCode!=REQUEST_PERMISSION){ super.onRequestPermissionsResult(requestCode, permissions, grantResults); } else{ Map<String, Integer> map = new HashMap<String, Integer>(); for (int i = 0; i < permissions.length; i++) { map.put(permissions[i], grantResults[i]); } if (map.get(perms[0]) == PackageManager.PERMISSION_GRANTED && map.get(perms[1]) == PackageManager.PERMISSION_GRANTED && map.get(perms[2]) == PackageManager.PERMISSION_GRANTED) { init(); } else{ Toast.makeText(this, "No permission", Toast.LENGTH_SHORT).show(); finish(); } } } }
