安卓7.0以上关闭屏幕高德后台持续定位

不知道大家在用高德地图的时候有没有发现,7.0以上的手机屏幕关闭后如果还在定位的话间隔两分钟后定位就停止了,8.0以上就更加了 用官方的通知也没用。下面说重点:

用服务定位通过广播发送在页面里面接收,这种能在后台定位2个小时左右,两个小时后还是会熄灭一切操作,不过两个小时已经可以满足大多数要求了吧。如果还需要更久那就定时重启服务,前提是应用没被杀死 只针对熄屏操作。下面是代码:

package com.swq.mcsrefine.service;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;

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.swq.mcsrefine.activity.R;
import com.swq.mcsrefine.utils.ContantUtils;

import java.text.SimpleDateFormat;
import java.util.Date;

public class LocationService extends Service {

    public AMapLocationClient locationClient;
    //声明mLocationOption对象
    public AMapLocationClientOption locationOption = null;

    //android 8.0后台定位权限
    private static final String NOTIFICATION_CHANNEL_NAME = "Location";
    private NotificationManager notificationManager = null;
    boolean isCreateChannel = false;
    private  Intent locationIntent = new Intent();
    public LocationService() {
    }

    @Override
    public void onCreate() {
        initLocation();
        Log.e("234", "3334455");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startLocation();
        Log.e("234", "33344");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        destroyLocation();

    }

    /**
     * 销毁定位
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    private void destroyLocation() {
        if (null != locationClient) {
            /**
             * 如果AMapLocationClient是在当前Activity实例化的,
             * 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy
             */
            locationClient.disableBackgroundLocation(true);
            locationClient.stopLocation();
            locationClient.unRegisterLocationListener(locationListener);
            locationClient.onDestroy();
            locationClient = null;
            locationOption = null;
        }
    }

    /**
     * 初始化定位
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    private void initLocation() {
        //初始化client
        locationClient = new AMapLocationClient(this.getApplicationContext());
        locationOption = getDefaultOption();
        //设置定位参数
        locationClient.setLocationOption(locationOption);
        // 设置定位监听
        locationClient.setLocationListener(locationListener);
        // 设置是否单次定位
        locationOption.setOnceLocation(false);
        // 设置是否需要显示地址信息
        locationOption.setNeedAddress(true);
        // 设置是否开启缓存
        locationOption.setLocationCacheEnable(true);
        //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
        locationClient.enableBackgroundLocation(2004, buildNotification());
        locationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);

    }

    private void startLocation() {
        // 启动定位
        if (ContantUtils.XUNCAHSERVICE) {
            startAlarm();
            locationClient.startLocation();
        } else {
            locationClient.stopLocation();
        }
    }

    /**
     * 默认的定位参数
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    private AMapLocationClientOption getDefaultOption() {
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
        mOption.setGpsFirst(true);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭
        mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
        mOption.setInterval(1000);//可选,设置定位间隔。默认为2秒
        mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true
        mOption.setOnceLocation(false);//可选,设置是否单次定位。默认是false
        mOption.setOnceLocationLatest(false);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
        AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
        mOption.setSensorEnable(false);//可选,设置是否使用传感器。默认是false
        mOption.setWifiScan(true); //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差
        mOption.setLocationCacheEnable(true); //可选,设置是否使用缓存定位,默认为true
        mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);//可选,设置逆地理信息的语言,默认值为默认语言(根据所在地区选择语言)
        return mOption;
    }

    /**
     * 定位监听
     */
    AMapLocationListener locationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation location) {

            if (null != location) {

                StringBuffer sb = new StringBuffer();
                //errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明
                if (location.getErrorCode() == 0) {
                    double lat = location.getLatitude();
                    double lon = location.getLongitude();

                    locationIntent.setAction("com.swq.mcsrefine.activity.mylocation");
                    locationIntent.putExtra("location", location);
                    sendBroadcast(locationIntent);
                } else {
                    //定位失败
                    sb.append("定位失败" + "\n");
                    sb.append("错误码:" + location.getErrorCode() + "\n");
                    sb.append("错误信息:" + location.getErrorInfo() + "\n");
                    sb.append("错误描述:" + location.getLocationDetail() + "\n");
                }

            } else {
            }
        }
    };


    /**
     * 获取时间
     *
     * @return
     */
    public String getTime() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");
        Date curDate = new Date(System.currentTimeMillis());//获取当前时间
        String str = formatter.format(curDate);
        return str;
    }


    private Notification buildNotification() {

        Notification.Builder builder = null;
        Notification notification = null;
        if (android.os.Build.VERSION.SDK_INT >= 26) {
            //Android O上对Notification进行了修改,如果设置的targetSDKVersion>=26建议使用此种方式创建通知栏
            if (null == notificationManager) {
                notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            }
            String channelId = getPackageName()+"001";
            if (!isCreateChannel) {
                NotificationChannel notificationChannel = new NotificationChannel(channelId,
                        NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
                notificationChannel.enableLights(true);//是否在桌面icon右上角展示小圆点
                notificationChannel.setLightColor(Color.BLUE); //小圆点颜色
                notificationChannel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知
                notificationManager.createNotificationChannel(notificationChannel);
                isCreateChannel = true;
            }
            builder = new Notification.Builder(getApplicationContext(), channelId);
        } else {
            builder = new Notification.Builder(getApplicationContext());
        }
        builder.setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("定位")
                .setContentText("")
                .setWhen(System.currentTimeMillis());

        if (android.os.Build.VERSION.SDK_INT >= 16) {
            notification = builder.build();
        } else {
            return builder.getNotification();
        }
        return notification;
    }

    /**
     * 防止后台2个小时后就休眠
     */
    public void startAlarm() {
        AlarmManager am;
        Intent intentAlarm;
        PendingIntent pendSender;
        //首先获得系统服务
        am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        //设置闹钟的意图,我这里是去调用一个服务,该服务功能就是获取位置并且上传
        intentAlarm = new Intent(this, LocationService.class);
        pendSender = PendingIntent.getService(this, 0, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
//        am.cancel(pendSender);
        //AlarmManager.RTC_WAKEUP ;这个参数表示系统会唤醒进程;设置的间隔时间是20分钟
        long triggerAtTime = System.currentTimeMillis() + 20 * 60 * 1000;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtTime,
                    pendSender);
//            am.setWindow(AlarmManager.RTC_WAKEUP, triggerAtTime,  1000, pendSender);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            am.setExact(AlarmManager.RTC_WAKEUP, triggerAtTime,
                    pendSender);
//            am.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime,  1000, pendSender);
        } else {
            am.set(AlarmManager.RTC_WAKEUP, triggerAtTime,
                    pendSender);
        }
    }


}

至于定位的操作就不多说了 可以看高德的官方文档,这里用的是系统的闹钟,对于4.4以上的set方法定时闹钟有点不准所以对不同版本有不同的定时启动闹钟的方法。setExactAndAllowWhileIdle方法和setExact都是一次性的不会循环,所以在onStartCommand这个方法里重复调用造成可以循环启动。定位成功后通过广播发送,在有需要的地方接收广播,如果还有其他方式发送和接收的可以跟我说说,最后注意服务记得注册,不用的时候取消服务,注销广播。接收就不放了,不知道的可以问我

 

8.0以上无效的话只能后台开一个服务,在服务里面循环播放一个无声的音乐,也只能管几个小时。完全跟微信一样的话只能跟厂商加入白名单。

 
当您在尝试对运行安卓7.0及以上版本的设备进行抓包操作时遇到失败的情况,这通常涉及到几个可能的问题: 1. **权限限制**:安卓系统对于应用的网络访问进行了严格的权限控制。为了进行网络抓包操作,您的应用程序需要获取特定的权限。如果应用程序未在AndroidManifest.xml文件中声明必要的权限,或是用户拒绝了相应的权限请求,那么抓包功能将无法正常工作。 - 需要在`<manifest>`标签内添加`<uses-permission>`元素,例如: ```xml <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.WIFI_DEBUGGING" /> ``` - 用户在安装应用时,可能会看到一个弹出窗口提示关于获取某些权限的必要性,并询问是否允许。确保用户正确地授予了所有必需的权限。 2. **开发者工具限制**:部分开发者工具可能受限于操作系统或安全策略。例如,某些工具可能无法通过标准API直接访问网络数据流,而需要使用特殊的方法或绕过常规机制,如使用root权限或其他非官方手段。然而,在安卓上,这样做可能存在风险并违反隐私政策。 3. **防火墙规则**:设备上可能已经配置了防火墙规则,阻止了特定应用的网络通信。检查防火墙设置,确认是否存在针对您的应用的禁止规则。 4. **应用自身限制**:有时,问题可能出现在应用本身的实现上。比如,代码中有错误、逻辑漏洞,或者是资源加载、初始化不当等导致应用无法正常获取网络数据。仔细审查应用的网络访问代码,查找可能的异常处理不足或资源管理问题。 5. **兼容性和稳定性**:安卓7.0引入了一些新的安全特性,可能导致一些较旧的应用或库无法完全兼容。确保使用的依赖库和框架都支持最新的安全规范。 解决上述问题的一般步骤包括: - 确认应用已正确声明所需权限并在设备上获得授权。 - 检查网络访问相关的代码,确保没有逻辑错误或资源泄漏。 - 使用开发者文档和社区资源验证是否有兼容性或权限方面的更新信息。 - 调试日志和性能监控工具可以帮助定位问题所在。 如果您正在使用的是某个特定的开发者工具或库,可以查阅其官方文档或论坛,寻求更具体的解决方案和最佳实践建议。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值