定位与权限

就昨天,我遇到一个神奇的问题,就是android原生的GPS定位在我的魅族4上跑的顺顺利利,但是一到了红米note4x或者最近的新android上就不能定位了,我把高德百度的定位接口都用过,但是就是报没权限的错误,我检查了一下AndroidManifest配置文件,ok都有,什么高德的key,权限等等都有。

查了一下报错,发现在android6.0版本后为了用户安全,有几个权限设置运行时权限,如果不加动态获取权限的代码,是不会提示的,没有得到权限,当然无法定位。

正常的解析是:

对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要访问通讯录、短信等)。而在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝(比如:单机的象棋对战,请求访问任何权限,我都是不同意的)。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。

新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

需要动态获取权限(Runtime Permissions)的主要有以下几个:

动态获取权限有:

参考大神:http://blog.csdn.net/lmj623565791/article/details/50709663

  

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

获取动态权限步骤:

package com.tfot.hotel.yichengyiyu.Activity;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.widget.Toast;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeAddress;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.tfot.hotel.yichengyiyu.MainActivity;
import com.tfot.hotel.yichengyiyu.R;
import com.tfot.hotel.yichengyiyu.Util.base.BaseActivity;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;

/**
 * Created by ACER on 2017/1/22.
 */

public class SplashActivity extends BaseActivity implements AMapLocationListener{
    private SharedPreferences sp;
    private SharedPreferences.Editor editor;
    //声明mLocationOption对象
    public AMapLocationClientOption mLocationOption = null;
    public AMapLocationClient mlocationClient = null;
    double lat; //维度
    double lon ;//经度
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
         sp = getSharedPreferences("sp_demo", Context.MODE_PRIVATE);
         editor = sp.edit();

        //判断是否为android6.0系统版本,如果是,需要动态添加权限
        if (Build.VERSION.SDK_INT>=23){
            showContacts();
        }else{
            new GaoDeDingWei().aMapLocationByNet();
        }

        new Handler().postDelayed(new Runnable() {
            public void run() {
                /* Create an Intent that will start the Main WordPress Activity. */
                Intent mainIntent = new Intent(SplashActivity.this, MainActivity.class);
                SplashActivity.this.startActivity(mainIntent);
                SplashActivity.this.finish();
            }
        }, 3000);
    }

    //6.0定位需要的权限申请
     public void showContacts(){
        if (ActivityCompat.checkSelfPermission(this, "android.permission.ACCESS_COARSE_LOCATION")
                != PackageManager.PERMISSION_GRANTED){
            Toast.makeText(getApplicationContext(),"没有权限,请手动开启定位权限", Toast.LENGTH_SHORT).show();
            // 申请一个(或多个)权限,并提供用于回调返回的获取码(用户定义)
            ActivityCompat.requestPermissions(SplashActivity.this,new String[]{"android.permission.ACCESS_COARSE_LOCATION"}, 100);
        }else{
            System.out.println("定位开始!!!!!!!!!!!!!!!!");
            new GaoDeDingWei().aMapLocationByNet();
        }
    }

    //Android6.0申请权限的回调方法
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            // requestCode即所声明的权限获取码,在checkSelfPermission时传入
            case 100:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 获取到权限,作相应处理(调用定位SDK应当确保相关权限均被授权,否则可能引起定位失败)
                    new GaoDeDingWei().aMapLocationByNet();
                } else {
                    // 没有获取到权限,做特殊处理
                    Toast.makeText(getApplicationContext(), "获取位置权限失败,请手动开启", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }

    //高德定位
    class GaoDeDingWei {
        public GaoDeDingWei(){

        }
        public  void  aMapLocationByNet(){
            //获取网络管理对象
            ConnectivityManager connmanager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
            //获取当前活跃的网络
            NetworkInfo info = connmanager.getActiveNetworkInfo();
            if (info == null) {
//                Intent intent = new Intent();
//                intent.setAction(Settings.ACTION_AIRPLANE_MODE_SETTINGS);//跳转打开网络的手机界面
//                startActivity(intent);
                Toast.makeText(SplashActivity.this,"请打开网络",Toast.LENGTH_SHORT).show();
            } else {
                //city_tv.setText("定位中,请稍等");
                aMapLocation();
            }
        }
        public  void aMapLocation(){
            mlocationClient = new AMapLocationClient(SplashActivity.this);
            //初始化定位参数
            mLocationOption = new AMapLocationClientOption();
            //设置定位监听
            mlocationClient.setLocationListener(SplashActivity.this);
            //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
            //设置定位间隔,单位毫秒,默认为2000ms
            mLocationOption.setInterval(2000);
            //设置定位参数
            mlocationClient.setLocationOption(mLocationOption);
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
            // 注意设置合适的定位时间的间隔(最小间隔支持为1000ms),并且在合适时间调用stopLocation()方法来取消定位请求
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
            //启动定位
            mlocationClient.startLocation();
        }

    }

    //高德地图数据监听改变
    @Override
    public void onLocationChanged(AMapLocation amapLocation) {
        if (amapLocation != null) {
            if (amapLocation.getErrorCode() == 0) {
                //定位成功回调信息,设置相关消息
                // amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
                lat= amapLocation.getLatitude();//获取纬度
                lon =amapLocation.getLongitude();//获取经度
                //amapLocation.getAccuracy();//获取精度信息
                    /*SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date date = new Date(amapLocation.getTime());
                    df.format(date);//定位时间*/
                //把经纬度转换成城市
                if (this!=null){

                    GeocodeSearch geocoderSearch = new GeocodeSearch(this);
                    geocoderSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener(){

                        @Override
                        public void onGeocodeSearched(GeocodeResult result, int rCode) {
                            // TODO Auto-generated method stub

                        }

                        @Override
                        public void onRegeocodeSearched(RegeocodeResult result, int rCode) {
                            //两个附近点的位置
                            String city  = result.getRegeocodeAddress().getCity();
                            editor.putString("lat", lat+"");
                            editor.putString("lon", lon+"");
                            editor.putString("city_tv",city);
                            editor.commit();
                            System.out.println("###############当前位置城市###############-->"+city);
                        }});
                    LatLonPoint lp = new LatLonPoint(lat,lon);
                    RegeocodeQuery query = new RegeocodeQuery(lp, 200,GeocodeSearch.AMAP);
                     geocoderSearch.getFromLocationAsyn(query);

                }else {
                    //  return;
                }
            } else {
                //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
                Log.e("AmapError","location Error, ErrCode:"
                        + amapLocation.getErrorCode() + ", errInfo:"
                        + amapLocation.getErrorInfo());
            }
        }
    }
}

在fragment中获取定位权限:

基本一样

但是

Fragment中运行时权限的特殊处理
在Fragment中申请权限,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的 onRequestPermissionsResult
父子fragment中子fragment获取权限:http://blog.csdn.net/qfanmingyiq/article/details/52561658

最后找到的hongyang干货:

MPermissions用法

对外的接口和PermissionGen基本一致,因为申请只需要三个参数,抛弃了使用原本类库的单例的方式,直接一个几个静态方法,简单整洁暴力。

贴一个用法:

public class MainActivity extends AppCompatActivity
{

    private Button mBtnSdcard;
    private static final int REQUECT_CODE_SDCARD = 2;

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

        mBtnSdcard = (Button) findViewById(R.id.id_btn_sdcard);
        mBtnSdcard.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                MPermissions.requestPermissions(MainActivity.this, REQUECT_CODE_SDCARD, Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {
        MPermissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @PermissionGrant(REQUECT_CODE_SDCARD)
    public void requestSdcardSuccess()
    {
        Toast.makeText(this, "GRANT ACCESS SDCARD!", Toast.LENGTH_SHORT).show();
    }

    @PermissionDenied(REQUECT_CODE_SDCARD)
    public void requestSdcardFailed()
    {
        Toast.makeText(this, "DENY ACCESS SDCARD!", Toast.LENGTH_SHORT).show();
    }
}

是不是简单明了~~对于onRequestPermissionsResult所有的Activity都是一致的,所以可以放到BaseActivity中去。此外,在Fragment中使用的方式一致,详见demo。

详见库:https://github.com/hongyangAndroid/MPermissions.

至于为什么不直接介绍MPermission的源码,因为主要涉及到Annotation Processor,所以以这种方式引出,后面考虑单篇博文介绍下我目前所会的编译时注解的相关做法以及API的使用。

时间: 2024-08-24 11:05:52

定位与权限的相关文章

检测相机和定位的权限

1.判断用户是否有权限访问相册 #import <AssetsLibrary/AssetsLibrary.h> [objc] view plain copy ALAuthorizationStatus author = [ALAssetsLibraryauthorizationStatus]; if (author == kCLAuthorizationStatusRestricted || author ==kCLAuthorizationStatusDenied){ //无权限 } typ

如何偷偷在后台定位:请求后台定位权限:

[iOS9在定位的问题上,有一个坏消息一个好消息]坏消息:如果不适配iOS9,就不能偷偷在后台定位(不带蓝条,见图)!好消息:将允许出现这种场景:同一App中的多个location manager:一些只能在前台定位,另一些可在后台定位,并可随时开启或者关闭特定location manager的后台定位. 如果没有请求后台定位的权限,也是可以在后台定位的,不过会带蓝条: // 1. 实例化定位管理器 _locationManager = [[CLLocationManager alloc] in

iOS8中定位服务的变化(CLLocationManager协议方法不响应,无法回掉GPS方法,不出现获取权限提示)

最近在写一个LBS的项目的时候,因为考虑到适配iOS8,就将项目迁移到Xcode6.0.1上,出现了不能正常获取定位服务权限的问题. self.manger = [[CLLocationManager alloc]init]; self.manger.distanceFilter = kCLDistanceFilterNone; // meters self.manger.delegate = self; [self.manger requestAlwaysAuthorization]; sel

Android开发----百度定位的相关代码

百度定位联网权限 <!-- 这个权限用于进行网络定位 -->    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" >    </uses-permission>    <!-- 这个权限用于访问GPS定位 -->    <uses-permission android:name="android.permission.AC

iOS 9适配系列教程:后台定位

http://www.cocoachina.com/ios/20150624/12200.html Demo:GitHub地址 [iOS9在定位的问题上,有一个坏消息一个好消息]坏消息:如果不适配iOS9,就不能偷偷在后台定位(不带蓝条,见图)!好消息:将允许出现这种场景:同一App中的多个location manager:一些只能在前台定位,另一些可在后台定位,并可随时开启或者关闭特定location manager的后台定位. 如果没有请求后台定位的权限,也是可以在后台定位的,不过会带蓝条:

后台持续定位CLLocationManager详解

CLLocationManager 8.0方法 locationManager.requestWhenInUseAuthorization() locationManager.requestAlwaysAuthorization() 9.0方法 locationManager.allowsBackgroundLocationUpdates = true locationManager.pausesLocationUpdatesAutomatically = false 此方法不关闭20分钟后自动

Python For Android (P4a):添加权限(Permissions)

写个小东西,一直调试,无法访问,最后定位在权限上. .p4a 配置文件中添加一行,下方是给网络权限. –permission INTERNET 如果是多条权限,请重复输入多条 –permission Android应用访问网络时需要先设置权限,在AndroidManifest.xml文件里设置权限:<uses-permission android:name="android.permission.INTERNET"/>.设置完后应用才可以联网. 并且Android应用不允许

补充总结

1.对前期提出的问题的回答. (1)软件工程的知识领域主要包括方法,工具以及过程. (2)团队是指一种为了实现某一目标而由相互协作的个体所组成的正式群体.是由员工和管理层组成的一个共同体,它合理利用每一个成员的知识和技能协同工作,解决问题,达到共同的目标.团队的构成要素总结为5P,分别为目标.人.定位.权限.计划.团队和群体有着根本性的一些区别,群体可以向团队过渡.一般根据团队存在的目的和拥有自主权的大小将团队分为三种类型:问题解决型团队.自我管理型团队.多功能型团队. 团队的构成要素,团队有几

程序员到项目经理:从内而外的提升

转自:http://www.cnblogs.com/watsonyin/archive/2012/09/10/2679528.html 目录 从程序员到项目经理(一):为什么要当项目经理 从程序员到项目经理(二):升职之辨 从程序员到项目经理(三):认识项目经理 从程序员到项目经理(四):外行可以领导内行吗 从程序员到项目经理(五):程序员加油站,不是人人都懂的学习要点 从程序员到项目经理(六):程序员加油站 — 懂电脑更要懂人脑 从程序员到项目经理(七):程序员加油站 — 完美主义也是一种错