Android6.0相比之前的Android版本有一個很大的不同點,就是動態的獲取權限。之前我們需要什么權限只需要在Manifest文件中聲明即可,在6.0中,又新增了運行時權限的動態檢測。
Android6.0分了兩種權限Normal Permissions(安裝時自動授權,用戶也不能取消權限) and Dangerous Permissions(詳情在文章最后):
如果在 Android 6.0 以前的設備上,我們之前在清單文件中聲明權限是沒有問題的,但是如果是在 Android 6.0 設備上,并且項目targetSdkVersion
你設置的是23,那再像之前那樣聲明權限,是不起作用的
此時你肯定想到了 如果 targetSdkVersion 值設置的小于23是不是就不會奔潰了,恩,確實如此, 此時即使使用Android6.0的設備,程序也不會奔潰,原因顯而易見,Android 的權限機制是 Android M 后才加入的。從 Android M 開始 應用程序申請的權限是在運行時動態賦給用戶的。所以就需要我們動態的申請權限了
之所以寫這篇文章是因為最近在寫一個APP的時候用到了百度定位,之前使用百度定位的SDK好好的,但是換了手機之后開始不行了,折騰半天,才意識到新手機是6.0的系統,搜索一番,有所了解,經過修改完成了工作,寫下來,權作備份,留人一起進步一個簡單的例子,實現點擊按鈕,屏幕出現當前位置申請密鑰,配置環境就按照官網上面的來,我們按照之前的方法來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系統做出修改,來動態申請權限了。修改代碼: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(); } }04-24 02:29:16.163 6134-6134/cn.lixyz.testpermission D/TTTT: 彈出提示
我們點擊“始終允許”之后,退出程序再此進入,則可以定位了,我們如果我們像要在運行了權限之后立即就可以獲取到位置信息呢?Android提供了onRequestPermissionsResult
方法來幫我們實現我們執行了權限規則之后的操作,這個方法和onActivityResult
方法類似
publicvoidonRequestPermissionsResult(int requestCode, String[] permissions,int[] grantResults){
switch (requestCode)
{
case1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
{ mLocationClient.start(); } else { Log.d("TTTT","啊偶,被拒絕了,少年不哭,站起來擼"); } break;
default:super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }
當我們點擊禁止按鈕的時候,Log提示"啊偶,被拒絕了,少年不哭,站起來擼"當我們點擊允許按鈕的時候,定位成功完整代碼如下
publicclassMainActivityextendsActivity{
private Button bt;
private TextView tv;
public LocationClient mLocationClient = null;
public BDLocationListener myListener = new MyLocationListener();
@OverrideprotectedvoidonCreate(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);
/**
*點擊執行6.0動態定位權限
*/bt.setOnClickListener(new View.OnClickListener() {
@Override
publicvoidonClick(View v){//mLocationClient.start(); startLocation(); } }); }
privatevoidstartLocation(){
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
publicvoidonRequestPermissionsResult(int requestCode, String[] permissions,int[] grantResults){
switch (requestCode) {
case1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {mLocationClient.start(); }
else { Log.d("TTTT","啊偶,被拒絕了,少年不哭,站起來擼"); } break;
default:super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }
/**
*下面就是常規的定位了,如果不懂可以去百度API查詢
*/
privatevoidinitLocation(){ 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); }classMyLocationListenerimplementsBDLocationListener{@OverridepublicvoidonReceiveLocation(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定位成功"); } elseif(location.getLocType()== BDLocation.TypeNetWorkLocation) {// 網絡定位結果 sb.append("/naddr : "); sb.append(location.getAddrStr());// 運營商信息 sb.append("/noperationers : "); sb.append(location.getOperators()); sb.append("/ndescribe : "); sb.append("網絡定位成功"); } elseif(location.getLocType()== BDLocation.TypeOffLineLocation) {// 離線定位結果 sb.append("/ndescribe : "); sb.append("離線定位成功,離線定位結果也是有效的"); } elseif(location.getLocType()== BDLocation.TypeServerError) { sb.append("/ndescribe : "); sb.append("服務端網絡定位失敗,可以反饋IMEI號和大體定位時間到loc-bugs@baidu.com,會有人追查原因"); } elseif(location.getLocType()== BDLocation.TypeNetWorkException) { sb.append("/ndescribe : "); sb.append("網絡不同導致定位失敗,請檢查網絡是否通暢"); } elseif(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() { publicvoidhandleMessage(android.os.Message msg){ tv.setText((String) msg.obj); mLocationClient.stop(); } };}
新聞熱點
疑難解答