天天看點

Android 6.0 (M) 系統特性詳解

 一.簡介

Android6.0釋出以來,在權限上做出了很大的變動,不再是之前的隻要在manifest設定就可以任意擷取權限,而是更加的注重使用者的隐私和體驗,不會再強迫使用者因拒絕不該擁有的權限而導緻的無法安裝的事情,也不會再不征求使用者授權的情況下,就可以任意的通路使用者隐私,而且即使在授權之後也可以及時的更改權限。這就是6.0版本做出的更擁護和注重使用者的一大展現。

Android6.0系統把權限分為兩個級别:

一類是Normal Permissions,即普通權限,這類權限不會潛藏有侵害使用者隐私和安全的問題,比如,通路網絡的權限,通路WIFI的權限等。

一類是Dangerous Permissions,即危險權限,這類權限會直接的威脅到使用者的安全和隐私問題,比如說通路短信,相冊等權限,地理位置權限。

二.權限

<1> 普通權限舉例

ACCESS_LOCATION_EXTRA_COMMANDS

ACCESS_NETWORK_STATE

ACCESS_NOTIFICATION_POLICY

ACCESS_WIFI_STATE

BLUETOOTH

BLUETOOTH_ADMIN

BROADCAST_STICKY

CHANGE_NETWORK_STATE

CHANGE_WIFI_MULTICAST_STATE

CHANGE_WIFI_STATE

DISABLE_KEYGUARD

EXPAND_STATUS_BAR

GET_PACKAGE_SIZE

INSTALL_SHORTCUT

INTERNET

KILL_BACKGROUND_PROCESSES

MODIFY_AUDIO_SETTINGS

NFC

READ_SYNC_SETTINGS

READ_SYNC_STATS

RECEIVE_BOOT_COMPLETED

REORDER_TASKS

REQUEST_IGNORE_BATTERY_OPTIMIZATIONS

REQUEST_INSTALL_PACKAGES

SET_ALARM

SET_TIME_ZONE

SET_WALLPAPER

SET_WALLPAPER_HINTS

TRANSMIT_IR

UNINSTALL_SHORTCUT

USE_FINGERPRINT

VIBRATE

WAKE_LOCK

WRITE_SYNC_SETTINGS
           

使用以上權限是不會威脅到使用者安全的,是以這類權限是可以直接的在manifest裡面直接的使用,而且在安裝後也會直接的生效了。

<2> 危險權限(敏感權限)舉例

SMS(短信)

   SEND_SMS

   RECEIVE_SMS

   READ_SMS

   RECEIVE_WAP_PUSH

   RECEIVE_MMS


<uses-permission android:name="android.permission.SEND_SMS"/>

<uses-permission android:name="android.permission.RECEIVE_SMS"/>

<uses-permission android:name="android.permission.READ_SMS"/>

<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>

<uses-permission android:name="android.permission.RECEIVE_MMS"/>



**********************************************************************



STORAGE(存儲卡)

   READ_EXTERNAL_STORAGE

   WRITE_EXTERNAL_STORAGE


<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


**********************************************************************



CONTACTS(聯系人)
   
   READ_CONTACTS

   WRITE_CONTACTS

   GET_ACCOUNTS


<uses-permission android:name="android.permission.READ_CONTACTS"/>

<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

<uses-permission android:name="android.permission.GET_ACCOUNTS"/

************************************************************************



PHONE(手機)

   READ_PHONE_STATE

   CALL_PHONE

   READ_CALL_LOG

   WRITE_CALL_LOG

   ADD_VOICEMAIL

   USE_SIP

   PROCESS_OUTGOING_CALLS


<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

<uses-permission android:name="android.permission.CALL_PHONE"/>

<uses-permission android:name="android.permission.READ_CALL_LOG"/>

<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>

<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>

<uses-permission android:name="android.permission.USE_SIP"/>

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

************************************************************************



CALENDAR(月曆)

   READ_CALENDAR

   WRITE_CALENDAR


<uses-permission android:name="android.permission.READ_CALENDAR"/>

<uses-permission android:name="android.permission.WRITE_CALENDAR"/>

*************************************************************************



CAMERA(相機)

   CAMERA


<uses-permission android:name="android.permission.CAMERA"/>

*************************************************************************



LOCATION(位置)
   
   ACCESS_FINE_LOCATION

   ACCESS_COARSE_LOCATION


<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

*************************************************************************



SENSORS(傳感器)

   BODY_SENSORS


<uses-permission android:name="android.permission.BODY_SENSORS"/>

**************************************************************************



MICROPHONE(麥克風)

   RECORD_AUDIO

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

           
Android 6.0 (M) 系統特性詳解

注意:

危險權限和普通權限也有差別,普通權限是單條的權限,而危險權限是以組展示的,也就是說,當你接受一個危險權限時,不但但接受的是界面上展示的這一個權限,而是它所在這個組裡面的其他所有通路權限也将會被自動擷取權限,比如,一旦WRITE_CONTACTS被授權了,App也有READ_CONTACTS和GET_ACCOUNTS的權限了。值得注意的是,這類權限也是需要在manifest中注冊的。

三.Demo

寫一個Demo,動态申請 聯系人和相機的權限

清單檔案

<!--   手機聯系人 讀 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!--   手機聯系人 寫 -->
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<!--   手機聯系人 擷取 -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>


<!-- 相機 -->
<uses-permission android:name="android.permission.CAMERA"/>


<!-- 傳感器 -->
<uses-permission android:name="android.permission.BODY_SENSORS"/>
           

工具類

package com.example.test;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class AndroidPermissionUtils {

    /**
     * 目前系統是否是Android 6.0及以上
     */

    public static boolean isMarshmallow = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;

    /**
     * Android 6.0及以上 檢測是否具有某些權限
     */

    public static boolean hasAndroidPermission(Context context, String[] permission) {
        boolean has = true;
        for (String per : permission) {
            if (ContextCompat.checkSelfPermission(context, per) != PackageManager.PERMISSION_GRANTED) {
                has = false;
                break;
            }
        }
        return has;
    }

    /**
     * Android 6.0及以上 申請某些權限
     */

    public static void requestAndroidPermission(Activity activity, int code, String[] permission) {
        ActivityCompat.requestPermissions(activity, permission, code);
    }

}
           

Activity

package com.example.test;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.HashMap;

public class PermissionActivity extends AppCompatActivity {

    //手機聯系人
    private String permission1 = "android.permission.READ_CONTACTS";
    private String[] permission11 = new String[]{permission1};//敏感權限
    private int Code1 = 123;

    //相機權限
    private String permission2 = "android.permission.CAMERA";
    private String[] permission22 = new String[]{permission2};//敏感權限
    private int Code2 = 456;

    //傳感器
    private String permission3 = "android.permission.BODY_SENSORS";
    private String[] permission33 = new String[]{permission3};//敏感權限
    private int Code3 = 789;

    private String[] permission = new String[]{permission1, permission2, permission3};//總權限
    private int Code = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_permission);
        initView();
    }

    /**
     * 初始化各種View
     */

    private void initView() {

        initPermissions();

        //手機聯系人權限相關
        TextView textView1 = findViewById(R.id.activity_permission_textview1);
        textView1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
                    if (AndroidPermissionUtils.hasAndroidPermission(PermissionActivity.this, permission11)) {//有權限 直接操作
                        getPhone("6.0及以上有權限 直接操作");
                    } else {//沒權限 申請
                        AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code1, permission11);
                    }
                } else {//6.0以下 直接操作
                    getPhone("6.0以下 直接操作");
                }
            }
        });


        //相機權限相關
        TextView textView2 = findViewById(R.id.activity_permission_textview2);
        textView2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
                    if (AndroidPermissionUtils.hasAndroidPermission(PermissionActivity.this, permission22)) {//有權限 直接操作
                        getCamera("6.0及以上有權限 直接操作");
                    } else {//沒權限 申請
                        AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code2, permission22);
                    }
                } else {//6.0以下 直接操作
                    getCamera("6.0以下 直接操作");
                }
            }
        });


        //傳感器權限相關
        TextView textView3 = findViewById(R.id.activity_permission_textview3);
        textView3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
                    if (AndroidPermissionUtils.hasAndroidPermission(PermissionActivity.this, permission33)) {//有權限 直接操作
                        getSensors("6.0及以上有權限 直接操作");
                    } else {//沒權限 申請
                        AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code3, permission33);
                    }
                } else {//6.0以下 直接操作
                    getSensors("6.0以下 直接操作");
                }
            }
        });
    }

    /**
     * 手機聯系人
     */

    private void getPhone(String type) {
        Log.d("PermissionActivity", "手機聯系人type----:" + type);
        ArrayList<HashMap<String, String>> list = readContact();
        int count = list.size();
        StringBuilder sb = new StringBuilder();
        sb.append("目前裝置聯系人數:" + count + "\n\n\n");
        for (int i = 0; i < count; i++) {
            HashMap<String, String> map = list.get(i);
            String name = map.get("name");
            String phone = map.get("phone");
            sb.append("姓名:" + name + "     手機号:" + phone + "\n\n\n");
        }
        String result = sb.toString();
        Log.d("PermissionActivity", "手機聯系人result----:" + result);
    }

    /**
     * 相機權限
     */

    private void getCamera(String type) {
        Log.d("PermissionActivity", "相機權限type----:" + type);
    }

    /**
     * 傳感器權限
     */

    private void getSensors(String type) {
        Log.d("PermissionActivity", "傳感器權限type----:" + type);
    }

    /**
     * 初始化時申請三個權限
     */

    private void initPermissions() {
        if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
            AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code, permission);
        }
    }

    /**
     * 權限回調
     */

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        Log.d("PermissionActivity", "權限回調requestCode----:" + requestCode);
        Log.d("PermissionActivity", "權限回調permissions.toString()----:" + permissions.toString());
        Log.d("PermissionActivity", "權限回調permissions.length----:" + permissions.length);
        Log.d("PermissionActivity", "權限回調grantResults.toString()----:" + grantResults.toString());
        Log.d("PermissionActivity", "權限回調grantResults.length----:" + grantResults.length);
        if (Code1 == requestCode) {//聯系人權限相關
            if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {//同意了權限
                getPhone("同意了權限——回調");
            } else {//拒絕了權限
                Log.d("PermissionActivity", "聯系人權限相關 拒絕了權限——回調");
            }
        } else if (Code2 == requestCode) {//相機權限相關
            if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {//同意了權限
                getCamera("同意了權限——回調");
            } else {//拒絕了權限
                Log.d("PermissionActivity", "相機權限相關 拒絕了權限——回調");
            }
        } else if (Code3 == requestCode) {//傳感器權限相關
            if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {//同意了權限
                getSensors("同意了權限——回調");
            } else {//拒絕了權限
                Log.d("PermissionActivity", "傳感器權限相關 拒絕了權限——回調");
            }
        } else if (Code == requestCode) {//初始化申請的三個權限
            if (grantResults.length == 3) {
                if ((grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    getPhone("初始化——同意了權限——回調");
                } else {
                    Log.d("PermissionActivity", "聯系人權限相關 初始化—拒絕了權限——回調");
                }

                if ((grantResults[1] == PackageManager.PERMISSION_GRANTED)) {
                    getCamera("初始化——同意了權限——回調");
                } else {
                    Log.d("PermissionActivity", "相機權限相關 初始化——拒絕了權限——回調");
                }

                if ((grantResults[2] == PackageManager.PERMISSION_GRANTED)) {
                    getSensors("初始化——同意了權限——回調");
                } else {
                    Log.d("PermissionActivity", "傳感器權限相關 初始化——拒絕了權限——回調");
                }
            }
        }
    }

    /**
     * 擷取目前裝置聯系人資訊
     * 1.從raw_contacts中讀取聯系人的id("contact_id")
     * 2.根據contact_id從data表中查詢出相應的電話号碼和聯系人名稱
     * 3.根據mimetype來區分哪個是聯系人,哪個是電話号碼
     */

    private ArrayList<HashMap<String, String>> readContact() {
        Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri dataUri = Uri.parse("content://com.android.contacts/data");
        ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
        //從raw_contacts中讀取聯系人的id("contact_id")
        Cursor rawContactsCursor = getContentResolver().query(rawContactsUri, new String[]{"contact_id"}, null, null, null);
        if (rawContactsCursor != null) {
            while (rawContactsCursor.moveToNext()) {
                String contactId = rawContactsCursor.getString(0);
                //根據contact_id從data表中查詢出相應的電話号碼和聯系人名稱, 實際上查詢的是視圖view_data
                Cursor dataCursor = getContentResolver().query(dataUri, new String[]{"data1", "mimetype"}, "contact_id=?", new String[]{contactId}, null);
                if (dataCursor != null) {
                    HashMap<String, String> map = new HashMap<String, String>();
                    while (dataCursor.moveToNext()) {
                        String data1 = dataCursor.getString(0);
                        String mimetype = dataCursor.getString(1);
                        if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
                            map.put("phone", data1);
                        } else if ("vnd.android.cursor.item/name".equals(mimetype)) {
                            map.put("name", data1);
                        }
                    }
                    list.add(map);
                    dataCursor.close();
                }
            }
            rawContactsCursor.close();
        }
        return list;
    }

}
           

注意

<1> 敏感權限動态申請一個分組下隻申請一個就好。

<2> 權限回調方法中可以根據requestCode判斷具體是申請的那個敏感權限,進而判斷是同意了還是拒絕了。

附:官網:https://developer.android.google.cn/about/versions/marshmallow

繼續閱讀