package com.dayu.pipirrapp.service; import android.Manifest; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.BitmapFactory; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationCompat; import com.baidu.location.BDAbstractLocationListener; import com.baidu.location.BDLocation; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.dayu.pipirrapp.R; import com.dayu.pipirrapp.activity.MainActivity; import com.dayu.pipirrapp.bean.db.LatLonBean; import com.dayu.pipirrapp.utils.CommonKeyName; import com.dayu.pipirrapp.utils.MyLog; import com.dayu.pipirrapp.utils.ToastUtil; import com.jeremyliao.liveeventbus.LiveEventBus; import com.tencent.bugly.crashreport.CrashReport; /** * author: zuo * Date: 2024-01-10 * Time: 14:39 * 备注: */ public class MyLocationService extends Service { private LocationManager locationManager; private MyLocationListener listener; private LocationClient mBDLocationClient = null; private MyBDLocationListener mBDLocationListener; /** * 是否一次性定位 */ boolean isSingle = false; // 是否已经定位 boolean isPositioned = false; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { MyLog.i("onStartCommand()"); isSingle = intent.getBooleanExtra("isSingle", false); if (!isSingle) { // 在API11之后构建Notification的方式 Notification.Builder builder = new Notification.Builder (this.getApplicationContext()); //获取一个Notification构造器 Intent nfIntent = new Intent(this, MainActivity.class); builder.setContentIntent(PendingIntent. getActivity(this, 0, nfIntent, PendingIntent.FLAG_IMMUTABLE)) // 设置PendingIntent .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标) .setContentTitle(getResources().getString(R.string.app_name)) // 设置下拉列表里的标题 .setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标 .setContentText("正在后台运行") // 设置上下文内容 .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间 Notification notification = builder.build(); // 获取构建好的Notification notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音 } return START_STICKY;// 如果系统终止该服务,之后会重启 } @Override public void onCreate() { super.onCreate(); // 启动前台服务 startForegroundService(); createNativeLocation(); // createBDLocation(); } private void startForegroundService() { // 针对 Android 8.0 及更高版本创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( "location_channel", "Location Service Channel", NotificationManager.IMPORTANCE_DEFAULT ); NotificationManager manager = getSystemService(NotificationManager.class); if (manager != null) { manager.createNotificationChannel(channel); } } // 创建通知 Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); Notification notification = new NotificationCompat.Builder(this, "location_channel") .setContentTitle("巡检定位") .setContentText("巡检定位服务正在后台运行") .setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(pendingIntent) .build(); // 将服务设置为前台服务 startForeground(1, notification); } /** * 原生的定位服务 */ private void createNativeLocation() { try { locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { // 提示用户开启定位 Toast.makeText(this, "请开启GPS定位", Toast.LENGTH_SHORT).show(); } listener = new MyLocationListener(); Criteria criteria = new Criteria(); // 查询精度:高,Criteria.ACCURACY_COARSE比较粗略,Criteria.ACCURACY_FINE则比较精确 criteria.setAccuracy(Criteria.ACCURACY_COARSE); //不要求海拔 criteria.setAltitudeRequired(false); //不要求方位 criteria.setBearingRequired(false); //允许有花费 criteria.setCostAllowed(true); //低功耗 criteria.setPowerRequirement(Criteria.POWER_LOW); String provider = locationManager.getBestProvider(criteria, true); MyLog.i("定位的provider:" + provider); //第二个参数是间隔时间 第三个参数是间隔多少距离,这里我试过了不同的各种组合,能获取到位置就是能,不能获取就是不能 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { MyLog.i("原生定位没有权限>>>>"); return; } locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER , 1000, 0, listener); } catch (Exception e) { CrashReport.postCatchedException(e); } } /** * 第三方百度定位服务 */ private void createBDLocation() { try { LocationClient.setAgreePrivacy(true); mBDLocationClient = new LocationClient(this.getBaseContext()); mBDLocationListener = new MyBDLocationListener(); //注册监听函数 mBDLocationClient.registerLocationListener(mBDLocationListener); //配置百度定位的选项 LocationClientOption option = new LocationClientOption(); //可选,默认高精度,设置定位模式,高精度,低功耗,仅设备 option.setLocationMode(LocationClientOption.LocationMode.Battery_Saving); //可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll; option.setCoorType("WGS84"); //可选,默认0,即仅定位一次,设置发起连续定位请求的间隔需要大于等于1000ms才是有效的 option.setScanSpan(1000); //可选,设置是否需要地址信息,默认不需要 option.setIsNeedAddress(true); //可选,设置是否需要地址描述 option.setIsNeedLocationDescribe(false); //可选,设置是否需要设备方向结果 option.setNeedDeviceDirect(false); //可选,默认false,设置是否当卫星定位有效时按照1S1次频率输出卫星定位结果 option.setLocationNotify(true); //可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死 option.setIgnoreKillProcess(true); //可选,默认false,设置是否开启卫星定位 option.setOpenGnss(true); //可选,默认false,设置定位时是否需要海拔信息,默认不需要,除基础定位版本都可用 option.setIsNeedAltitude(false); mBDLocationClient.setLocOption(option); //开启百度定位 mBDLocationClient.start(); } catch (Exception e) { e.printStackTrace(); CrashReport.postCatchedException(e); } } /** * 原生定位 */ class MyLocationListener implements LocationListener { // 位置改变时获取经纬度 @Override public void onLocationChanged(Location location) { String longitude = "Longitude:" + location.getLongitude(); String latitude = "Latitude:" + location.getLatitude(); MyLog.i("原生定位onLocationChanged: Latitude:" + latitude + " Longitude:" + longitude); postPosition(location.getLatitude(), location.getLongitude()); // 是否一次性定位 if (isSingle) { stopSelf(); // 获取到经纬度以后,停止该service } ToastUtil.showToast(MyLocationService.this, "原生定位onLocationChanged: Latitude:" + latitude + " Longitude:" + longitude); } // 状态改变时 @Override public void onStatusChanged(String provider, int status, Bundle extras) { MyLog.i("onStatusChanged - provider:" + provider + " status:" + status); ToastUtil.showToast(MyLocationService.this, "onStatusChanged - provider:" + provider + " status:" + status); } // 提供者可以使用时 @Override public void onProviderEnabled(String provider) { MyLog.i("GPS开启了"); ToastUtil.showToast(MyLocationService.this, "GPS开启了"); } // 提供者不可以使用时 @Override public void onProviderDisabled(String provider) { MyLog.i("GPS关闭了"); ToastUtil.showToast(MyLocationService.this, "GPS关闭了"); } } /** * 百度定位的监听 */ class MyBDLocationListener extends BDAbstractLocationListener { @Override public void onReceiveLocation(BDLocation location) { double latitude = location.getLatitude(); //获取纬度信息 double longitude = location.getLongitude(); //获取经度信息 // MyLog.i("百度的监听 latitude:" + latitude); // MyLog.i("百度的监听 longitude:" + longitude); MyLog.i("百度的监听 onBaiduLocationChanged: latitude:" + latitude + " longitude:" + longitude); if (!String.valueOf(latitude).equals("4.9E-324")) { //不为4.9E-324时才是定位成功 postPosition(latitude, longitude); if (isSingle) { stopSelf(); // 获取到经纬度以后,停止该service } } } } /** * @param latitude * @param longitude */ private void postPosition(double latitude, double longitude) { if (isSingle && isPositioned) { return; } LatLonBean latLonBean = new LatLonBean(); latLonBean.setLatitude(latitude); latLonBean.setLongitude(longitude); LiveEventBus.get(CommonKeyName.locationData).post(latLonBean); } @Override public void onDestroy() { MyLog.i("MyLocationService--onDestroy"); // 停止前台服务--参数:表示是否移除之前的通知 stopForeground(true); // 获取NotificationManager并取消通知,确保通知被移除 NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (notificationManager != null) { notificationManager.cancel(0); // 参数1对应的是startForeground()中通知的ID } super.onDestroy(); // 停止所有的定位服务 try { if (locationManager != null) { locationManager.removeUpdates(listener); } // if (mBDLocationClient != null) { // mBDLocationClient.stop(); // mBDLocationClient.unRegisterLocationListener(mBDLocationListener); // } } catch (Exception e) { CrashReport.postCatchedException(e); } } }