当前位置 : 主页 > 手机开发 > android >

开箱即用的Google与百度定位坐标系转换实例

来源:互联网 收集:自由互联 发布时间:2023-02-01
目录 集成谷歌定位与百度定位并在地图上显示 项目背景 一. 集成谷歌定位 定位Api使用流程: 二. 集成百度定位 Application中初始化SDK 三. 坐标系转换与地图上的显示 集成谷歌定位与百度
目录
  • 集成谷歌定位与百度定位并在地图上显示
    • 项目背景
  • 一. 集成谷歌定位
    • 定位Api使用流程:
  • 二. 集成百度定位
    • Application中初始化SDK
  • 三. 坐标系转换与地图上的显示

    集成谷歌定位与百度定位并在地图上显示

    项目背景

    东南亚某小国的App,需要用到定位与地图显示,我们都知道海外人士都是喜欢谷歌地图与谷歌定位的,那么必然是要优先使用谷歌定位的,但是中国手机卖的很好,部分中国手机的海外版是没有谷歌服务的,那么我使用百度地图进行降级处理。

    两者使用的定位坐标系不同,如果需要在谷歌地图上展示百度定位,需要如何转换呢?或者说谷歌的定位如何在百度地图上展示呢?

    一. 集成谷歌定位

    跟项目下的build.gradle

    别的先不说,先把谷歌服务插件给引入

        dependencies {
            classpath 'com.android.tools.build:gradle:7.0.3'
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
            classpath 'com.google.gms:google-services:4.3.8'
        }
    

    app模块下的build.gradle最底部 应用谷歌服务插件

    apply plugin: 'com.google.gms.google-services'
    

    然后去谷歌后台申请App-Key相关的项目,需要填写包名和一些签名文件的SHA1值,注意这里relese包的SHA1值,和谷歌市场上架的SHA1值是不同的,上架之后需要去谷歌市场把谷歌市场上的SHA1值设置进去,因为谷歌市场上架之后会把你的签名文件包装一次,完全不同的签名文件了。

    完成此步之后 下载对应App的 google-services.json 文件。

    此步骤完成,我们再远程依赖谷歌定位的库。location

       //定位功能
        api 'com.google.android.gms:play-services-location:16.0.0'
    

    定位Api使用流程:

    权限定义

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

    注意使用之前要动态申请权限,这里不做演示

         //初始化谷歌地图API
         if (googleApiClient == null) {
            googleApiClient = new GoogleApiClient.Builder(mActivity)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        }
       //Google-Location-Api 服务连接成功回调
        @Override
        public void onConnected(@Nullable Bundle bundle) {
            Log.e("MapLastLocationUtils", "Google-Api服务连接成功了");
            getAPILastLocation();
        }
        //Google-Location-Api 服务异常连接暂停
        @Override
        public void onConnectionSuspended(int i) {
            Log.e("MapLastLocationUtils", "Google-Api服务被暂停了");
            if (googleApiClient != null && !googleApiClient.isConnected())
                googleApiClient.connect();
        }
        //Google-Location-Api 连接异常
        @Override
        public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
            Log.e("MapLastLocationUtils", "Google-Api服务连接错误");
            //如果连接错误直接用百度定位
        }
        public void stopLocation() {
            if (googleApiClient != null && googleApiClient.isConnected()){
                googleApiClient.disconnect();
            }
        }
        private void getAPILastLocation() {
        FusedLocationProviderClient fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(mActivity);
        fusedLocationProviderClient.getLastLocation().addOnSuccessListener(mActivity, location -> {
            if (location != null && location.getLatitude() > 0 && location.getLongitude() > 0) {
                double latitude = location.getLatitude();
                double longitude = location.getLongitude();
                Log.e("MapLastLocationUtils", "Google-API-获取到的最后的地址为:" + "Lat:" + latitude + " Lon:" + longitude);
            } else {
                    //如果没有值直接用百度定位
            }
        });
      }
    

    二. 集成百度定位

    我们也是需要在百度开发者平台上申请应用的App,不过这一块就比较简单,只需要验证包名就行了,然后会给你一个AppId。

    我们下载定位的jar包与so动态库,导入到项目,然后再清单文件配置

                  <meta-data
               android:name="com.baidu.lbsapi.API_KEY"
                android:value="123456789">
            </meta-data>
            <service
                android:name="com.baidu.location.f"
                android:enabled="true"
                android:process=":remote">
                <intent-filter>
                    <action android:name="com.baidu.location.service_v2.2"></action>
                </intent-filter>
            </service>
    

    Application中初始化SDK

        SDKInitializer.initialize(context);
    

    判断开启谷歌定位还是百度定位的逻辑封装

    public class MapLastLocationUtils implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
            LifecycleObserver {
        private static MapLastLocationUtils ourInstance;
        private Activity mActivity;
        private GoogleApiClient googleApiClient;
        private LocationClient mBDLocationClient;
        private LocationRequest mLocationRequest;
        private boolean isNeedBackNotifyLocation = false;
        public static MapLastLocationUtils getInstance(Activity context) {
            if (ourInstance == null) {
                ourInstance = new MapLastLocationUtils(context);
            }
            return ourInstance;
        }
        private MapLastLocationUtils(Activity context) {
            mActivity = context;
            //初始化谷歌地图API
            if (googleApiClient == null) {
                googleApiClient = new GoogleApiClient.Builder(mActivity)
                        .addConnectionCallbacks(this)
                        .addOnConnectionFailedListener(this)
                        .addApi(LocationServices.API)
                        .build();
            }
        }
        /**
         * 只是获取当前的位置一次
         */
        public void getLastLocation() {
            int code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(CommUtils.getContext());
            if (code == ConnectionResult.SUCCESS) {
                // 支持Google服务
                getAPILastLocation();
            } else {
                //开启百度定位
                getBDLastLocation();
            }
        }
        //API连接成功尝试获取最后的位置
        @SuppressLint("MissingPermission")
        private void getAPILastLocation() {
            FusedLocationProviderClient fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(mActivity);
            fusedLocationProviderClient.getLastLocation().addOnSuccessListener(mActivity, location -> {
                if (location != null && location.getLatitude() > 0 && location.getLongitude() > 0) {
                    double latitude = location.getLatitude();
                    double longitude = location.getLongitude();
                    Log.e("MapLastLocationUtils", "Google-API-获取到的最后的地址为:" + "Lat:" + latitude + " Lon:" + longitude);
                    if (mListener != null) {
                        //这里转换一下,如果国内转换为火星坐标,国外直接用
                        Gps gps = GPS84ToGCJ02(longitude, latitude);
                        mListener.onLastLocation(gps.getLatitude(), gps.getLongitude());
                    }
                } else {
                    getBDLastLocation();
                }
            });
        }
        //百度定位尝试获取最后的位置
        private void getBDLastLocation() {
            mBDLocationClient = new LocationClient(mActivity);
            //声明LocationClient类
            mBDLocationClient.registerLocationListener(mBDLastLocationListener);
            //配置百度定位的选项
            LocationClientOption option = new LocationClientOption();
            option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy); // 可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
            option.setCoorType("gcj02"); // 可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll; 国际WGS84
            option.setScanSpan(0); // 可选,默认0,即仅定位一次,设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
            option.setIsNeedAddress(false); // 可选,设置是否需要地址信息,默认不需要
            option.setIsNeedLocationDescribe(false); // 可选,设置是否需要地址描述
            option.setNeedDeviceDirect(false); // 可选,设置是否需要设备方向结果
            option.setLocationNotify(false); // 可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
            option.setIgnoreKillProcess(true); // 可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop
            option.setIsNeedLocationDescribe(false); // 可选,默认false,设置是否需要位置语义化结果,可以在BDLocation
            option.setIsNeedLocationPoiList(false); // 可选,默认false,设置是否需要POI结果,可以在BDLocation
            option.SetIgnoreCacheException(false); // 可选,默认false,设置是否收集CRASH信息,默认收集
            option.setOpenGps(false); // 可选,默认false,设置是否开启Gps定位
            option.setIsNeedAltitude(false); // 可选,默认false,设置定位时是否需要海拔信息,默认不需要,除基础定位版本都可用
            mBDLocationClient.setLocOption(option);
            //开启定位
            if (mBDLocationClient != null && !mBDLocationClient.isStarted()) {
                mBDLocationClient.start();
            }
        }
        //Google-Location-Api 服务连接成功回调
        @Override
        public void onConnected(@Nullable Bundle bundle) {
            Log.e("MapLastLocationUtils", "Google-Api服务连接成功了");
            getAPILastLocation();
        }
        //Google-Location-Api 服务异常连接暂停
        @Override
        public void onConnectionSuspended(int i) {
            Log.e("MapLastLocationUtils", "Google-Api服务被暂停了");
            if (googleApiClient != null && !googleApiClient.isConnected())
                googleApiClient.connect();
        }
        //Google-Location-Api 连接异常
        @Override
        public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
            Log.e("MapLastLocationUtils", "Google-Api服务连接错误");
            //如果连接错误直接用百度定位吧
            getBDLastLocation();
        }
        /**
         * 停止全部的定位
         */
        public void stopLocation() {
            if (googleApiClient != null && googleApiClient.isConnected()) {
                googleApiClient.disconnect();
            }
            if (mBDLocationClient != null) {
                if (mBDLastLocationListener != null) {
                    mBDLocationClient.unRegisterLocationListener(mBDLastLocationListener);
                }
                YYLogUtils.w("定位stop了");
                mBDLocationClient.stop();
            }
        }
        private OnLocationCallbackListener mListener;
        public void setOnLocationCallbackListener(OnLocationCallbackListener listener) {
            mListener = listener;
        }
        public interface OnLocationCallbackListener {
            void onLastLocation(double lat, double lon);
        }
        /**
         * 百度的监听回调(最后的地址)
         */
        BDAbstractLocationListener mBDLastLocationListener = new BDAbstractLocationListener() {
            //百度定位成功的展示
            @Override
            public void onReceiveLocation(BDLocation bdLocation) {
                if (bdLocation != null && bdLocation.getLocType() != BDLocation.TypeServerError &&
                        !(bdLocation.getLatitude() + "").equals("4.9E-324") &&
                        !(bdLocation.getLongitude() + "").equals("4.9E-324")) {
                    double latitude = bdLocation.getLatitude();    //获取纬度信息
                    double longitude = bdLocation.getLongitude();    //获取经度信息
                    Log.w("MapLastLocationUtils", "百度定位获取到的最后的地址为:" + "Lat:" + latitude + " Lon:" + longitude);
                    //获取到了最后的位置-直接回调
                    if (mListener != null) {
                        mListener.onLastLocation(latitude, longitude);
                    }
                } else {
                    Log.e("MapLastLocationUtils", "百度定位-获取位置失败");
                    if (googleApiClient != null && !googleApiClient.isConnected()) {
                        googleApiClient.connect();
                    } else {
                        getAPILastLocation();
                    }
                }
            }
            @Override
            public void onConnectHotSpotMessage(String s, int i) {
                super.onConnectHotSpotMessage(s, i);
            }
            //百度定位的错误信息展示
            @Override
            public void onLocDiagnosticMessage(int locType, int diagnosticType, String diagnosticMessage) {
                super.onLocDiagnosticMessage(locType, diagnosticType, diagnosticMessage);
                int tag = 2;
                StringBuffer sb = new StringBuffer(256);
                sb.append("诊断结果: ");
                if (locType == BDLocation.TypeNetWorkLocation) {
                    if (diagnosticType == 1) {
                        sb.append("网络定位成功,没有开启GPS,建议打开GPS会更好");
                        sb.append("\n" + diagnosticMessage);
                    } else if (diagnosticType == 2) {
                        sb.append("网络定位成功,没有开启Wi-Fi,建议打开Wi-Fi会更好");
                        sb.append("\n" + diagnosticMessage);
                    }
                } else if (locType == BDLocation.TypeOffLineLocationFail) {
                    if (diagnosticType == 3) {
                        sb.append("定位失败,请您检查您的网络状态");
                        sb.append("\n" + diagnosticMessage);
                    }
                } else if (locType == BDLocation.TypeCriteriaException) {
                    if (diagnosticType == 4) {
                        sb.append("定位失败,无法获取任何有效定位依据");
                        sb.append("\n" + diagnosticMessage);
                    } else if (diagnosticType == 5) {
                        sb.append("定位失败,无法获取有效定位依据,请检查运营商网络或者Wi-Fi网络是否正常开启,尝试重新请求定位");
                        sb.append(diagnosticMessage);
                    } else if (diagnosticType == 6) {
                        sb.append("定位失败,无法获取有效定位依据,请尝试插入一张sim卡或打开Wi-Fi重试");
                        sb.append("\n" + diagnosticMessage);
                    } else if (diagnosticType == 7) {
                        sb.append("定位失败,飞行模式下无法获取有效定位依据,请关闭飞行模式重试");
                        sb.append("\n" + diagnosticMessage);
                    } else if (diagnosticType == 9) {
                        sb.append("定位失败,无法获取任何有效定位依据");
                        sb.append("\n" + diagnosticMessage);
                    }
                } else if (locType == BDLocation.TypeServerError) {
                    if (diagnosticType == 8) {
                        sb.append("定位失败,请确认您定位的开关打开状态,是否赋予APP定位权限");
                        sb.append("\n" + diagnosticMessage);
                    }
                }
                Log.e("MapLastLocationUtils", sb.toString());
            }
        };
        // =======================  update begin ↓ =========================
        /**
         * 开启后台的通知栏定位
         */
        public void startBackNotifyLocation() {
            isNeedBackNotifyLocation = true;
            if (mBDLocationClient == null) {
                mBDLocationClient = new LocationClient(mActivity);
            }
            LocationClientOption mOption = new LocationClientOption();
            mOption.setScanSpan(15000);
            mOption.setIsNeedAddress(false);
            mOption.setOpenGps(true);
            mBDLocationClient.setLocOption(mOption);
    //                mClient.registerLocationListener(mBDUpdateLocationListener);
            Notification notification;
            if (Build.VERSION.SDK_INT >= 26) {
                NotificationUtils mNotificationUtils = new NotificationUtils(mActivity);
                Notification.Builder builder2 = mNotificationUtils.getAndroidChannelNotification("YY Circle", "Locating in the background");
                builder2.setSmallIcon(R.drawable.ic_launcher_map);
                notification = builder2.build();
            } else {
                //获取一个Notification构造器
                Notification.Builder builder = new Notification.Builder(mActivity);
                builder.setContentTitle("YY Circle") // 设置下拉列表里的标题
                        .setSmallIcon(R.drawable.ic_launcher_map) // 设置状态栏内的小图标
                        .setContentText("Locating in the background") // 设置上下文内容
                        .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
                notification = builder.build(); // 获取构建好的Notification
            }
            notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
            //开启前台通知的后台定位
            mBDLocationClient.enableLocInForeground(1, notification);
            mBDLocationClient.start();
        }
        // =======================  转换 begin ↓ =========================
        private double pi = 3.1415926535897932384626;
        private double a = 6378245.0;
        private double ee = 0.00669342162296594323;
        /**
         * 国际 GPS84 坐标系
         * 转换成
         * [国测局坐标系] 火星坐标系 (GCJ-02)
         * <p>
         * World Geodetic System ==> Mars Geodetic System
         *
         * @param lon 经度
         * @param lat 纬度
         * @return GPS实体类
         */
        public Gps GPS84ToGCJ02(double lon, double lat) {
            if (outOfChina(lat, lon)) {
                YYLogUtils.e("GPS84ToGCJ02:国外的坐标不做处理");
            return new Gps(lon, lat);
            } else {
                YYLogUtils.e("GPS84ToGCJ02:处理国内的坐标");
                double dLat = transformLat(lon - 105.0, lat - 35.0);
                double dLon = transformLon(lon - 105.0, lat - 35.0);
                double radLat = lat / 180.0 * pi;
                double magic = Math.sin(radLat);
                magic = 1 - ee * magic * magic;
                double sqrtMagic = Math.sqrt(magic);
                dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
                dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
                double mgLat = lat + dLat;
                double mgLon = lon + dLon;
                return new Gps(mgLon, mgLat);
            }
        }
        /**
         * [国测局坐标系] 火星坐标系 (GCJ-02)
         * 转换成
         * 国际 GPS84 坐标系
         *
         * @param lon 火星经度
         * @param lat 火星纬度
         */
        public Gps GCJ02ToGPS84(double lon, double lat) {
            Gps gps = transform(lon, lat);
            double lontitude = lon * 2 - gps.getLongitude();
            double latitude = lat * 2 - gps.getLatitude();
            return new Gps(lontitude, latitude);
        }
        private Gps transform(double lon, double lat) {
            if (outOfChina(lon, lat)) {
                return new Gps(lon, lat);
            }
            double dLat = transformLat(lon - 105.0, lat - 35.0);
            double dLon = transformLon(lon - 105.0, lat - 35.0);
            double radLat = lat / 180.0 * pi;
            double magic = Math.sin(radLat);
            magic = 1 - ee * magic * magic;
            double sqrtMagic = Math.sqrt(magic);
            dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
            dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
            double mgLat = lat + dLat;
            double mgLon = lon + dLon;
            return new Gps(mgLon, mgLat);
        }
        /**
         * 不在中国范围内
         *
         * @param lon 经度
         * @param lat 纬度
         * @return boolean值
         */
        public static boolean outOfChina(double lat, double lon) {
            if (lon < 72.004 || lon > 137.8347)
                return true;
            if (lat < 0.8293 || lat > 55.8271)
                return true;
            return false;
        }
        /**
         * 纬度转化算法
         *
         * @param x
         * @param y
         * @return
         */
        private double transformLat(double x, double y) {
            double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
                    + 0.2 * Math.sqrt(Math.abs(x));
            ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
            ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
            ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
            return ret;
        }
        /**
         * 经度转化算法
         *
         * @param x
         * @param y
         * @return
         */
        private double transformLon(double x, double y) {
            double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
                    * Math.sqrt(Math.abs(x));
            ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
            ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
            ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
                    * pi)) * 2.0 / 3.0;
            return ret;
        }
    }
    

    三. 坐标系转换与地图上的显示

    网上一搜坐标系那可太多了,我们不整那么复杂,我们Android就知道2个 gcj02(中国国测局) 和 wgs84(通过坐标系) 。由于我们不是国内的应用,并且集成了非单一的定位软件,所以我们就不知道私有的坐标系如bd09之类的。

    可以看到我们上面的工具类都是使用的gcj02坐标系定位的,在中国就需要gcj02定位,这样比较准确,如果要在对应的地图上展示,则需要对应的坐标系经纬度,在对应的坐标系地图上展示。

    如我们的定位是gcj02的坐标系,在谷歌地图上展示则需要转换为wgs之后才对,不然会有大概800米的误差。百度地图则可以设置坐标系,设置为gcj02之后就可以在百度地图上展示。

    坐标系的转换工具类在上面就有了。

    以上就是开箱即用的Google与百度定位坐标系转换实例的详细内容,更多关于Google 百度定位坐标系转换的资料请关注自由互联其它相关文章!

    网友评论