Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MethodChannelLocation.enableBackgroundMode #961

Open
dharambudh1 opened this issue Jun 22, 2024 · 4 comments
Open

MethodChannelLocation.enableBackgroundMode #961

dharambudh1 opened this issue Jun 22, 2024 · 4 comments

Comments

@dharambudh1
Copy link

MethodChannelLocation.enableBackgroundMode

Stack trace:
PlatformException(error, Service.startForeground() not allowed due to mAllowStartForeground false: service com.ahinsaaggregator.vendor/com.lyokone.location.FlutterLocationService, null, android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() not allowed due to mAllowStartForeground false: service com.ahinsaaggregator.vendor/com.lyokone.location.FlutterLocationService at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54) at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50) at android.os.Parcel.readParcelableInternal(Parcel.java:4882) at android.os.Parcel.readParcelable(Parcel.java:4864) at android.os.Parcel.createExceptionOrNull(Parcel.java:3064) at android.os.Parcel.createException(Parcel.java:3053) at android.os.Parcel.readException(Parcel.java:3036) at android.os.Parcel.readException(Parcel.java:2978) at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:7234) at android.app.Service.startForeground(Service.java:775) at com.lyokone.location.FlutterLocationService.d(SourceFile:1) at bb.h.a(SourceFile:1) at bb.h.onMethodCall(SourceFile:1) at xb.j$a.a(SourceFile:1) at ob.c.l(SourceFile:1) at ob.c.m(SourceFile:1) at ob.c.i(SourceFile:1) at ob.b.run(SourceFile:1) at android.os.Handler.handleCallback(Handler.java:958) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:230) at android.os.Looper.loop(Looper.java:319) at android.app.ActivityThread.main(ActivityThread.java:8934) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103) )

Screenshot from 2024-06-22 10-53-38

Flutter version: Flutter (Channel stable, 3.19.3, on Ubuntu 24.04 LTS 6.8.0-35-generic, locale en_US.UTF-8)
Plugin version: location: ^6.0.2
Device information: Samsung Galaxy A23 running Android 14

@edwinmacalopu
Copy link

edwinmacalopu commented Jul 3, 2024

You are missing this permission uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"

@dharambudh1
Copy link
Author

Thank you for the reply! I am currently utilizing <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />, while <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> is not documented anywhere. Let's test it out.

@edwinmacalopu
Copy link

edwinmacalopu commented Jul 4, 2024

android.permission.FOREGROUND_SERVICE_LOCATION

Since Android 14, the permission is required
https://developer.android.com/develop/background-work/services/foreground-services?hl=es-419#fgs-prerequisites

@PistonShot1
Copy link

PistonShot1 commented Oct 1, 2024

Currently there is a different in requesting permissions for android 11 and above there are certain times , the option for the background location settings doesnt get invoked as expected. For example, when I test on my android 14 , it immediately shows but for my andoid 12 it doesnt.

The background location permission is a bit different for android 11 and above , reference , here

So the solution that may guarantee to work is using native platform channel where you would invoke requestPermission , reference for this , here

I currently inovke the platform channel methods on initstate of the widget screen that expected to use it

Here is the native side of code, ofc will have to be added at MainActivity.kt

package com.cloone.edo

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.widget.Toast


class MainActivity : FlutterActivity() {
  private val CHANNEL = "android.flutter.dev/permission"
  private val REQUEST_CODE_BACKGROUND_LOCATION = 1001
  private var permissionResult: MethodChannel.Result? = null

  override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
      if (call.method == "requestBackgroundLocationPermission") {
        permissionResult = result
        requestBackgroundLocationPermission()
      } else {
        result.notImplemented()
      }
    }
  }

  private fun requestBackgroundLocationPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
      // Check if permission is already granted
      if (checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        permissionResult?.success("already_granted")
      } else {
        // Request background location permission
        requestPermissions(arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), REQUEST_CODE_BACKGROUND_LOCATION)
      }
    } else {
      // For android 10 and below , not required
      permissionResult?.success("not_required")
    }
  }

  override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when (requestCode) {
      REQUEST_CODE_BACKGROUND_LOCATION -> {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
          Toast.makeText(this, "Background Location Permission Granted", Toast.LENGTH_SHORT).show()
          permissionResult?.success("granted")
        } else {
          Toast.makeText(this, "Background Location Permission Denied", Toast.LENGTH_SHORT).show()
          permissionResult?.success("denied")
        }
      }
    }
  }
}

and on the dart side

Future<void> _getBackgroundLocationPermission() async {
    String locationPermission = '';
    try {
      final result = await platform
          .invokeMethod<String>('requestBackgroundLocationPermission');
      locationPermission = 'Permission : $result % .';
    } on PlatformException catch (e) {
      locationPermission = "Failed to get permission: '${e.message}'.";
    }

    setState(() {
      _locationPermission = locationPermission;
    });
  }

this would be the method you would invoke on the initstate

I am quite new to native, so the code quality may not be the best but it currently request permission as expected and would show a native toast . Hope this helps.

And referring to what you issued originally, it is most likely you did not handle what happens when user denies. Usually on testing u should do for denied and then check if app attempts to loop back or redirect user back, and forcing user to allow permission regardless in order to use that particular service.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants