第十二章 Android 6 權限

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();
            }
        }
    }
}

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *