Android6.0中的權限

前言

Android6.0相比以前的Android版本有一個很大的不一樣點,就是動態的獲取權限。以前咱們須要什麼權限只須要在Manifest文件中聲明便可,在6.0中,又新增了運行時權限的動態檢測。
Android6.0分了兩種權限Normal Permissions(安裝時自動受權,用戶也不能取消權限) and Dangerous Permissions(詳情在文章最後):java

使用環境

若是在 Android 6.0 之前的設備上,咱們以前在清單文件中聲明權限是沒有問題的,可是若是是在 Android 6.0 設備上,而且項目targetSdkVersion你設置的是23,那再像以前那樣聲明權限,是不起做用的android

此時你確定想到了 若是 targetSdkVersion 值設置的小於23是否是就不會奔潰了,恩,確實如此, 此時即便使用Android6.0的設備,程序也不會奔潰,緣由顯而易見,Android 的權限機制是 Android M 後才加入的。從 Android M 開始 應用程序申請的權限是在運行時動態賦給用戶的。因此就須要咱們動態的申請權限了git

示例

之因此寫這篇文章是由於最近在寫一個APP的時候用到了百度定位,以前使用百度定位的SDK好好的,可是換了手機以後開始不行了,折騰半天,才意識到新手機是6.0的系統,搜索一番,有所瞭解,寫下來,權做備份
一個簡單的例子,實現點擊按鈕,屏幕出現當前位置
申請密鑰,配置環境就按照官網上面的來,咱們按照以前的方法來web

package cn.lixyz.testpermission;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.Poi;

import java.util.List;

public class MainActivity extends Activity /*implements BDLocationListener*/ {

    private Button bt;
    private TextView tv;

    public LocationClient mLocationClient = null;
    public BDLocationListener myListener = new MyLocationListener();

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

        mLocationClient = new LocationClient(getApplicationContext()); // 聲明LocationClient類
        mLocationClient.registerLocationListener(myListener); // 註冊監聽函數
        initLocation();
        bt = (Button) findViewById(R.id.bt);
        tv = (TextView) findViewById(R.id.tv);
        bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                mLocationClient.start();
            }
        });
    }

    private void initLocation() {
        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);// 可選,默認高精度,設置定位模式,高精度,低功耗,僅設備
        option.setCoorType("bd09ll");// 可選,默認gcj02,設置返回的定位結果座標系
        int span = 1000;
        option.setScanSpan(span);// 可選,默認0,即僅定位一次,設置發起定位請求的間隔須要大於等於1000ms纔是有效的
        option.setIsNeedAddress(true);// 可選,設置是否須要地址信息,默認不須要
        option.setOpenGps(true);// 可選,默認false,設置是否使用gps
        option.setLocationNotify(true);// 可選,默認false,設置是否當gps有效時按照1S1次頻率輸出GPS結果
        option.setIsNeedLocationDescribe(true);// 可選,默認false,設置是否須要位置語義化結果,能夠在BDLocation.getLocationDescribe裏獲得,結果相似於「在北京天安門附近」
        option.setIsNeedLocationPoiList(true);// 可選,默認false,設置是否須要POI結果,能夠在BDLocation.getPoiList裏獲得
        option.setIgnoreKillProcess(false);// 可選,默認true,定位SDK內部是一個SERVICE,並放到了獨立進程,設置是否在stop的時候殺死這個進程,默認不殺死
        option.SetIgnoreCacheException(false);// 可選,默認false,設置是否收集CRASH信息,默認收集
        option.setEnableSimulateGps(false);// 可選,默認false,設置是否須要過濾gps仿真結果,默認須要
        mLocationClient.setLocOption(option);
    }

    class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            // Receive Location
            StringBuffer sb = new StringBuffer(256);
            sb.append("time : ");
            sb.append(location.getTime());
            sb.append("\nerror code : ");
            sb.append(location.getLocType());
            sb.append("\nlatitude : ");
            sb.append(location.getLatitude());
            sb.append("\nlontitude : ");
            sb.append(location.getLongitude());
            sb.append("\nradius : ");
            sb.append(location.getRadius());
            if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS定位結果
                sb.append("\nspeed : ");
                sb.append(location.getSpeed());// 單位:千米每小時
                sb.append("\nsatellite : ");
                sb.append(location.getSatelliteNumber());
                sb.append("\nheight : ");
                sb.append(location.getAltitude());// 單位:米
                sb.append("\ndirection : ");
                sb.append(location.getDirection());// 單位度
                sb.append("\naddr : ");
                sb.append(location.getAddrStr());
                sb.append("\ndescribe : ");
                sb.append("gps定位成功");

            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {// 網絡定位結果
                sb.append("\naddr : ");
                sb.append(location.getAddrStr());
                // 運營商信息
                sb.append("\noperationers : ");
                sb.append(location.getOperators());
                sb.append("\ndescribe : ");
                sb.append("網絡定位成功");
            } else if (location.getLocType() == BDLocation.TypeOffLineLocation) {// 離線定位結果
                sb.append("\ndescribe : ");
                sb.append("離線定位成功,離線定位結果也是有效的");
            } else if (location.getLocType() == BDLocation.TypeServerError) {
                sb.append("\ndescribe : ");
                sb.append("服務端網絡定位失敗,能夠反饋IMEI號和大致定位時間到loc-bugs@baidu.com,會有人追查緣由");
            } else if (location.getLocType() == BDLocation.TypeNetWorkException) {
                sb.append("\ndescribe : ");
                sb.append("網絡不一樣致使定位失敗,請檢查網絡是否通暢");
            } else if (location.getLocType() == BDLocation.TypeCriteriaException) {
                sb.append("\ndescribe : ");
                sb.append("沒法獲取有效定位依據致使定位失敗,通常是因爲手機的緣由,處於飛行模式下通常會形成這種結果,能夠試着重啓手機");
            }
            sb.append("\nlocationdescribe : ");
            sb.append(location.getLocationDescribe());// 位置語義化信息
            List<Poi> list = location.getPoiList();// POI數據
            if (list != null) {
                sb.append("\npoilist size = : ");
                sb.append(list.size());
                for (Poi p : list) {
                    sb.append("\npoi= : ");
                    sb.append(p.getId() + " " + p.getName() + " " + p.getRank());
                }
            }
            if (location.getCity() != null) {
                Message msg = new Message();
                msg.obj = location.getCity();
                handler.sendMessage(msg);
            }
        }
    }


    Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            tv.setText((String) msg.obj);
            mLocationClient.stop();
        }
    };
}

咱們點擊按鈕,發現並無定位成功,查看log,發現以下log網絡

04-24 02:16:59.994 5329-5354/? W/System.err: java.lang.SecurityException: getAllCellInfo: Neither user 10198 nor current process has android.permission.ACCESS_COARSE_LOCATION.
04-24 02:16:59.994 5329-5354/? W/System.err:     at android.app.ContextImpl.enforce(ContextImpl.java:1595)
04-24 02:16:59.994 5329-5354/? W/System.err:     at android.app.ContextImpl.enforceCallingOrSelfPermission(ContextImpl.java:1627)
04-24 02:16:59.994 5329-5354/? W/System.err:     at android.content.ContextWrapper.enforceCallingOrSelfPermission(ContextWrapper.java:675)
04-24 02:16:59.994 5329-5354/? W/System.err:     at android.content.ContextWrapper.enforceCallingOrSelfPermission(ContextWrapper.java:675)
04-24 02:16:59.994 5329-5354/? W/System.err:     at com.android.phone.PhoneInterfaceManager.enforceFineOrCoarseLocationPermission(PhoneInterfaceManager.java:1835)
04-24 02:16:59.994 5329-5354/? W/System.err:     at com.android.phone.PhoneInterfaceManager.getAllCellInfoUsingSubId(PhoneInterfaceManager.java:1920)
04-24 02:16:59.994 5329-5354/? W/System.err:     at com.android.phone.PhoneInterfaceManager.getAllCellInfo(PhoneInterfaceManager.java:1916)
04-24 02:16:59.994 5329-5354/? W/System.err:     at com.android.internal.telephony.ITelephony$Stub.onTransact(ITelephony.java:732)
04-24 02:16:59.994 5329-5354/? W/System.err:     at android.os.Binder.execTransact(Binder.java:453)

須要android.permission.ACCESS_COARSE_LOCATION權限,咱們在Manifest文件中添加以後再運行,發現仍是拋一樣的異常,依舊獲取不到位置
因此咱們就須要針對6.0系統作出修改,來動態申請權限了。
修改代碼:app

bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                startLocation();
            }
        });
private void startLocation() {
        int checkPermission = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
        if (checkPermission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
            Log.d("TTTT", "彈出提示");
            return;
        } else {
            mLocationClient.start();
        }
    }

從新運行,點擊按鈕,發現彈出提示:
enter description here
而且Log提示ide

04-24 02:29:16.163 6134-6134/cn.lixyz.testpermission D/TTTT: 彈出提示

咱們點擊「始終容許」以後,退出程序再此進入,則能夠定位了,咱們若是咱們像要在運行了權限以後當即就能夠獲取到位置信息呢?
Android提供了onRequestPermissionsResult方法來幫咱們實現咱們執行了權限規則以後的操做,這個方法和onActivityResult方法相似函數

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationClient.start();
                } else {
                    Log.d("TTTT", "啊偶,被拒絕了,少年不哭,站起來擼");
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

當咱們點擊禁止按鈕的時候,Log提示"啊偶,被拒絕了,少年不哭,站起來擼"
當咱們點擊容許按鈕的時候,定位成功
完整代碼以下ui

public class MainActivity extends Activity{

    private Button bt;
    private TextView tv;

    public LocationClient mLocationClient = null;
    public BDLocationListener myListener = new MyLocationListener();

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

        mLocationClient = new LocationClient(getApplicationContext()); // 聲明LocationClient類
        mLocationClient.registerLocationListener(myListener); // 註冊監聽函數
        initLocation();
        bt = (Button) findViewById(R.id.bt);
        tv = (TextView) findViewById(R.id.tv);
        bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                //mLocationClient.start();
                startLocation();
            }
        });
    }

    private void startLocation() {
if(Build.VERSION.SDK_INT>=23){ int checkPermission = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION); if (checkPermission != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1); return; } else { mLocationClient.start(); }
}else{
  mLocationClient.start();
} } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case 1: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { mLocationClient.start(); } else { Log.d("TTTT", "啊偶,被拒絕了,少年不哭,站起來擼"); } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } private void initLocation() { LocationClientOption option = new LocationClientOption(); option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);// 可選,默認高精度,設置定位模式,高精度,低功耗,僅設備 option.setCoorType("bd09ll");// 可選,默認gcj02,設置返回的定位結果座標系 int span = 1000; option.setScanSpan(span);// 可選,默認0,即僅定位一次,設置發起定位請求的間隔須要大於等於1000ms纔是有效的 option.setIsNeedAddress(true);// 可選,設置是否須要地址信息,默認不須要 option.setOpenGps(true);// 可選,默認false,設置是否使用gps option.setLocationNotify(true);// 可選,默認false,設置是否當gps有效時按照1S1次頻率輸出GPS結果 option.setIsNeedLocationDescribe(true);// 可選,默認false,設置是否須要位置語義化結果,能夠在BDLocation.getLocationDescribe裏獲得,結果相似於「在北京天安門附近」 option.setIsNeedLocationPoiList(true);// 可選,默認false,設置是否須要POI結果,能夠在BDLocation.getPoiList裏獲得 option.setIgnoreKillProcess(false);// 可選,默認true,定位SDK內部是一個SERVICE,並放到了獨立進程,設置是否在stop的時候殺死這個進程,默認不殺死 option.SetIgnoreCacheException(false);// 可選,默認false,設置是否收集CRASH信息,默認收集 option.setEnableSimulateGps(false);// 可選,默認false,設置是否須要過濾gps仿真結果,默認須要 mLocationClient.setLocOption(option); } class MyLocationListener implements BDLocationListener { @Override public void onReceiveLocation(BDLocation location) { // Receive Location StringBuffer sb = new StringBuffer(256); sb.append("time : "); sb.append(location.getTime()); sb.append("\nerror code : "); sb.append(location.getLocType()); sb.append("\nlatitude : "); sb.append(location.getLatitude()); sb.append("\nlontitude : "); sb.append(location.getLongitude()); sb.append("\nradius : "); sb.append(location.getRadius()); if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS定位結果 sb.append("\nspeed : "); sb.append(location.getSpeed());// 單位:千米每小時 sb.append("\nsatellite : "); sb.append(location.getSatelliteNumber()); sb.append("\nheight : "); sb.append(location.getAltitude());// 單位:米 sb.append("\ndirection : "); sb.append(location.getDirection());// 單位度 sb.append("\naddr : "); sb.append(location.getAddrStr()); sb.append("\ndescribe : "); sb.append("gps定位成功"); } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {// 網絡定位結果 sb.append("\naddr : "); sb.append(location.getAddrStr()); // 運營商信息 sb.append("\noperationers : "); sb.append(location.getOperators()); sb.append("\ndescribe : "); sb.append("網絡定位成功"); } else if (location.getLocType() == BDLocation.TypeOffLineLocation) {// 離線定位結果 sb.append("\ndescribe : "); sb.append("離線定位成功,離線定位結果也是有效的"); } else if (location.getLocType() == BDLocation.TypeServerError) { sb.append("\ndescribe : "); sb.append("服務端網絡定位失敗,能夠反饋IMEI號和大致定位時間到loc-bugs@baidu.com,會有人追查緣由"); } else if (location.getLocType() == BDLocation.TypeNetWorkException) { sb.append("\ndescribe : "); sb.append("網絡不一樣致使定位失敗,請檢查網絡是否通暢"); } else if (location.getLocType() == BDLocation.TypeCriteriaException) { sb.append("\ndescribe : "); sb.append("沒法獲取有效定位依據致使定位失敗,通常是因爲手機的緣由,處於飛行模式下通常會形成這種結果,能夠試着重啓手機"); } sb.append("\nlocationdescribe : "); sb.append(location.getLocationDescribe());// 位置語義化信息 List<Poi> list = location.getPoiList();// POI數據 if (list != null) { sb.append("\npoilist size = : "); sb.append(list.size()); for (Poi p : list) { sb.append("\npoi= : "); sb.append(p.getId() + " " + p.getName() + " " + p.getRank()); } } if (location.getCity() != null) { Message msg = new Message(); msg.obj = location.getCity(); handler.sendMessage(msg); } } } Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { tv.setText((String) msg.obj); mLocationClient.stop(); } }; }

 

 

6.0中的權限分類

  • Normal Permissions
    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_PACKAGESthis

  • Dangerous Permissions

    1. Permission Group:CALENDAR

    • READ_CALENDAR

    • WRITE_CALENDAR

    1. Permission Group:CAMERA

    • CAMERA

    1. Permission Group:CONTACTS

    • READ_CONTACTS

    • WRITE_CONTACTS

    • GET_ACCOUNTS

    1. Permission Group:LOCATION

    • ACCESS_FINE_LOCATION

    • ACCESS_COARSE_LOCATION

    1. Permission Group:MICROPHONE

    • RECORD_AUDIO

    1. Permission Group:PHONE

    • READ_PHONE_STATE

    • CALL_PHONE

    • READ_CALL_LOG

    • WRITE_CALL_LOG

    • ADD_VOICEMAIL

    • USE_SIP

    • PROCESS_OUTGOING_CALLS

    1. Permission Group:SENSORS

    • BODY_SENSORS

    1. Permission Group:SMS

    • SEND_SMS

    • RECEIVE_SMS

    • READ_SMS

    • RECEIVE_WAP_PUSH

    • RECEIVE_MMS

    1. Permission Group:STORAGE

    • READ_EXTERNAL_STORAGE

    • WRITE_EXTERNAL_STORAGE

相關文章
相關標籤/搜索