Open masus04 opened 1 year ago
This is a follow up to #785
So, no updates?
Any updates on this? There is still not a single Location package that supports WearOS.
While wearOS is still not officially supported by flutter, most use cases can be covered by third party packages like this one and I personally have multiple apps productive on the play store.
However, there is still no location package available for wearOS applications, signifficantly reducing the appeal of using Flutter for wearOS. Supporting this use case could be huge for Flutter on WearOS.
I am considering implementing this feature in the near future. Can you point me to what would have to be done in order to do so?
This woul dbe the first time I work on Flutter plugins, so I would really appreciate the help.
Also, would a wearOS implementation be part of the geolocator_android federated plugin, or would it be implement as a separate federated plugin?
It would be so great to see geolocator working on WearOS ! I just started a WearOS project on my own with geolocator as its key feature. I was surprised to see no location packages works on WearOS so far...
As of the WearOS implementation for geolocator, I guess it could be part of geolocator_android plugin, but might not be the easiest way though.
If any help is necessary I would be glad to join, even if I'm in the same situation as you are regarding Flutter packages.
@masus04 @SkylL3r I need this too for my project and would also being willing to chip in. Yeah I believe the geolocator_android is the place to start. I was able to build a local bridge between android and flutter to get it working on my emulator (can't see to get it working my device though), that's where I added my code.
@masus04 @SkylL3r I was able to get the location working on WearOS writing my own code (not using this package). The trick is to use the FusedLocationProviderClient
instead of the regular location provider (a smartwatch gets its GPS data differently than a phone). Let me know if you want my code, and/or if we should add it to this package for future users.
@tgritter Indeed, I also was able to get the location on WearOs using FusedLocationClientProvider
last night on my own plugin.
But I admit my own is pretty standard and maybe not quite strong enough on permissions checks and stuff based on what geolocator_android
does.
So I'd be interested in seeing your code as a comparison and/or show you mine.
I also keep thinking it would be a great addition to this package for future users. 👍🏽
@SkylL3r Here is my code:
build.gradle
implementation 'com.google.android.gms:play-services-location:18.0.0'
MainActivity.kt
import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.annotation.NonNull
import androidx.core.app.ActivityCompat
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
import android.location.Location
import android.os.Bundle
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import io.flutter.plugin.common.EventChannel
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationRequest
import java.util.concurrent.TimeUnit
class MainActivity : FlutterActivity() {
private val CHANNEL = "location_permission"
private val LOCATION_CHANNEL = "location_updates"
private val PERMISSION_REQUEST_CODE = 123
private lateinit var fusedLocationClient: FusedLocationProviderClient
private var eventSink: EventChannel.EventSink? = null
private lateinit var locationCallback: LocationCallback // Declare locationCallback as a class property
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
}
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
when (call.method) {
"requestPermission" -> {
requestLocationPermission(result)
}
"checkPermission" -> {
result.success(checkLocationPermission())
}
else -> result.notImplemented()
}
}
EventChannel(flutterEngine.dartExecutor.binaryMessenger, LOCATION_CHANNEL)
.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) {
this@MainActivity.eventSink = eventSink
startLocationUpdates()
}
override fun onCancel(arguments: Any?) {
stopLocationUpdates()
}
})
}
private fun requestLocationPermission(result: MethodChannel.Result) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
result.success(true)
return
}
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_REQUEST_CODE
)
}
}
private fun checkLocationPermission(): Boolean {
return ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
private fun startLocationUpdates() {
if (checkLocationPermission()) {
val locationRequest = getLocationRequest()
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
for (location in locationResult.locations) {
eventSink?.success("${location.latitude} ${location.longitude}")
}
}
}
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
}
}
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
private fun getLocationRequest(): LocationRequest {
return LocationRequest.create().apply {
interval = TimeUnit.SECONDS.toMillis(1)
fastestInterval = TimeUnit.SECONDS.toMillis(1)
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
eventSink?.success(true)
} else {
eventSink?.success(false)
}
}
}
}
Then you can call it in Flutter like so:
Future<void> _startLocationUpdates() async {
try {
await platform.invokeMethod('requestPermission');
final bool result = await platform.invokeMethod('checkPermission');
if (result) {
eventChannel.receiveBroadcastStream().listen((event) {
List<double> coords = parseCoordinates(event);
print("Coordinates: $coords");
});
}
} on PlatformException catch (e) {
print("Failed to start location updates: '${e.message}'.");
}
}
And yeah would be great to get this package working for future users. Although it's probably not as simple as just copying and pasting this code 😟
Any news here ? I'm also willing to help in this case.
@momo21584 I haven't made a PR for this change, no. If you need GPS for the watch I would advise building it yourself using a bridge modal. The code I posted above ^ was mainly working for me. The key difference between the watch and phone is using the com.google.android.gms.location.FusedLocationProviderClient
package for the watch.
If it's not that big of a change, would it be possible to open a PR for it?
@masus04 I think it would be a big change unfortunately. There would be a lot of device based logic you'd have to be very careful about. You'd probably need to test on various devices too, different watches handle GPS differently I've found. There may be other device based problems encountered too.
Unless someone really wants to take this on, I think writing a bridging module is going to be much easier for getting Flutter GPS on WearOS. A good experience too, I learned a lot about bridging writing mine!
🚀 WearOs Support Feature Request
As WearOS is based on android and works quite similar, it would be great to have geolocator support it. So far none of the Flutter location packages are supporting WearOS and this could be a great argument to use geolocator.
Contextualize the feature
Geolocator supports most relevant platforms on which location is required. The only exception being Apple watchOS and Android WearOS. This feature request seeks to address one of these. Doing so would also make geolocator the first flutter plugin that supports location integration on wearOS devices.
Describe the feature
Ideally the full feature set that is currently supported on mobile android should be supported. If there are limitations, the key features would be a great start.
I suspect the fact that geolocator does not currently work on wearOS, even though it works great on android is mostly due to different permission / service requirements.
Platforms affected (mark all that apply)
Test Application
I have set up a very minimal test application to showcase the current behaviour: https://github.com/masus04/Flutter-WearOS-Location/blob/main/README.md
The same behaviour can be observed when running the application on an emulator in Android Studio or a physical device.
When running this application on Android mobile / wearOS, the following log is printed:
Android Mobile
WearOS
This is with the latest Flutter & dependencies at the time of this issue