flutter 应用程序在Android上关闭后后台服务未停止

brc7rcf0  于 2022-12-14  发布在  Flutter
关注(0)|答案(2)|浏览(314)

在我的flutter应用程序中,我写了一个后台服务来获取用户的位置。当应用程序在后台时,这个位置服务仍然可以获取用户的位置,应用程序仍然可以运行。
我不希望后台位置服务在用户终止应用程序后运行。
但当我在Android上终止我的应用程序时,位置服务似乎仍在运行。
另外,当我第二次启动应用程序时,它不能正常工作。我假设这是因为后台服务仍在运行。

  • 如果我通过“强制停止”停止应用程序,所有工作正常,在第二次。
  • 此外,如果我手动停止后台服务,从应用程序(说,从一个按钮点击,调用停止功能),然后关闭应用程序,再次所有工作正常。

有人能提供一些建议,如何停止后台服务时,我关闭应用程序?
主要活动.kt为;

class MainActivity: FlutterActivity() {

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, LOCATION_CHANNEL).setMethodCallHandler {
                call, result ->

            if (call.method == "startLocationUpdate") {
                var status = startUpdateLocation()
                result.success(status.toString())
            } else if (call.method == "stopLocationUpdate")
            {
                var status = stopUpdateLocation()
                result.success(status.toString())
            } else if (call.method == "isLocationPermissionEnabled")
            {
                var status = checkPermission()
                result.success(status.toString())
            }
            else {
                result.notImplemented()
            }
        }

        EventChannel(flutterEngine.dartExecutor, LOCATION_EVENT_CHANNEL).setStreamHandler(
            object : EventChannel.StreamHandler {
                override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
                    locationUpdateReceiver = receiveLocationUpdate(events)
                }

                override fun onCancel(arguments: Any?) {
                    unregisterReceiver(locationUpdateReceiver)
                    locationUpdateReceiver = null
                    isServiceStarted = false
                }
            }
        )

    }

    override fun onDestroy() {
        try {
            if (locationUpdateReceiver != null )
            {

                unregisterReceiver(locationUpdateReceiver)

            }

        } catch (e: Exception) {
        }
        super.onDestroy()
    }

    private fun stopUpdateLocation() : Int {
        if (isServiceStarted) {
            unregisterReceiver(locationUpdateReceiver)
            stopService(this)
            isServiceStarted = false
            return SUCCESS
        }
        else {
            return SERVICE_NOT_RUNNING
        }
    }

    private fun startUpdateLocation() : Int {
        if (isServiceStarted) {
            return SERVICE_ALREADY_STARTED
        }
        else if (!checkPermission()) {
            //requestPermission()
            return REQUESTING_PERMISSION
        }
        else {
            registerReceiver(locationUpdateReceiver, locationIntentFilter);
            isServiceStarted = true
            startService(this)
            return SUCCESS
        }
    }

    private fun receiveLocationUpdate(events: EventChannel.EventSink): BroadcastReceiver {
        return object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                val key = LocationManager.KEY_LOCATION_CHANGED
                val location: Location? = intent.extras!![key] as Location?
                if (location != null) {
                    val runningAppProcessInfo = ActivityManager.RunningAppProcessInfo()
                    ActivityManager.getMyMemoryState(runningAppProcessInfo)
                    var appRunningBackground: Boolean = runningAppProcessInfo.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                    if (appRunningBackground) {
                        events.success("0," + location.latitude.toString() + "," + location.longitude.toString())
                    }
                    else {
                        events.success("1," + location.latitude.toString() + "," + location.longitude.toString())
                    }
                }
            }
        }
    }

    private fun checkPermission(): Boolean {
        val result = ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)
        val result1 = ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION)
        return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED
    }

    companion object {
        private const val LOCATION_CHANNEL = "flutter.io/location"
        private const val LOCATION_EVENT_CHANNEL = "flutter.io/locationEvent"
        private const val LOCATION_UPDATE_INTENT = "FLUTTER_LOCATION"
        private const val PERMISSION_REQUEST_CODE = 1

        private final const val SERVICE_NOT_RUNNING = 0;
        private final const val SUCCESS = 1;
        private final const val REQUESTING_PERMISSION = 100;
        private final const val SERVICE_ALREADY_STARTED = 2;

        var isServiceStarted = false
        var duration = "1" ;
        var distance = "20";
        var locationIntentFilter = IntentFilter(LOCATION_UPDATE_INTENT)
        var locationUpdateReceiver: BroadcastReceiver? = null

        fun startService(context: Context) {
            val startIntent = Intent(context, LocationService::class.java)
            ContextCompat.startForegroundService(context, startIntent)
        }
        fun stopService(context: Context) {
            val stopIntent = Intent(context, LocationService::class.java)
            context.stopService(stopIntent)
        }
    }
}

位置服务.kt

class LocationService : Service() {
    private val NOTIFICATION_CHANNEL_ID = "notification_location"
    private val duration = 5 // In Seconds
    private val distance = 0  // In Meters

    override fun onCreate() {
        super.onCreate()
        isServiceStarted = true
        val builder: NotificationCompat.Builder =
            NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                .setOngoing(false)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationManager: NotificationManager =
                getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            val notificationChannel = NotificationChannel(
                NOTIFICATION_CHANNEL_ID,
                NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW
            )
            notificationChannel.description = NOTIFICATION_CHANNEL_ID
            notificationChannel.setSound(null, null)
            notificationManager.createNotificationChannel(notificationChannel)
            startForeground(1, builder.build())
        }
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        LocationHelper().startListeningLocation(this, duration, distance);
        return START_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onDestroy() {
        super.onDestroy()
        isServiceStarted = false
    }

    override fun onTaskRemoved(rootIntent: Intent?) {
        super.onTaskRemoved(rootIntent)

        stopSelf()
    }

    companion object {
        var isServiceStarted = false
    }
}

在我的AndroidManifest.xml中,我有

android:name=".LocationService"
   android:enabled="true"
   android:exported="true"
   android:stopWithTask="true"

在flutter应用程序中,我调用了stop服务

@override
  void dispose() async {

    if (_locationUpdateEventStarted) {
      await methodChannel.invokeMethod('stopLocationUpdate');
    }

    super.dispose();
  }

我也试过跟踪,但也不行

@override
  void didChangeAppLifecycleState(AppLifecycleState state) async {
    super.didChangeAppLifecycleState(state);

    if (state == AppLifecycleState.detached) {
      
      if (_locationUpdateEventStarted) {
        await methodChannel.invokeMethod('stopLocationUpdate');
      }
    }
  }
9ceoxa92

9ceoxa921#

实际上,服务是Foreground service,即使应用程序关闭,它也会运行。
前台服务会显示状态栏通知,以便用户主动了解您的应用正在前台执行任务并消耗系统资源。除非停止服务或将其从前台移除,否则无法取消通知。

cwdobuhd

cwdobuhd2#

这就是我做的而且很管用

await service.configure(
    androidConfiguration: AndroidConfiguration(
        
        onStart: onStart,
        autoStart: true,
        isForegroundMode: false,

        notificationChannelId: 'my_foreground',
        initialNotificationTitle: 'my service',
        initialNotificationContent: 'the service is started',
        foregroundServiceNotificationId: 888,
        autoStartOnBoot: true
    ),
    iosConfiguration: IosConfiguration(
        autoStart: true,
        onForeground: onStart,
        onBackground: onIosBackground,
    ),
);

相关问题