Reputation: 11
I'm currently working on a Flutter app for a watch using WearOS, since there is no plugin for targetting GPS position using a WearOS watch, you need to do it manually by using the FusedLocationProviderClient from Google Play Services that you need to handle from the ./app/src/main/com/.../.../MainActivity.kt
by using a entire script and a system of events broadcasting.
With the code I've currently wrote, I can manage to get the passive GPS position registered by the watch, since it's better when you're currently loading the application and that you're potentially not connected from Wi-Fi or cellular connection.
PS D:\Codes\Flutter projects\idfm_wearos> flutter run --release
Launching lib\main.dart on sdk gwear x86 64 in release mode...
Running Gradle task 'assembleRelease'... 75,8s
√ Built build\app\outputs\flutter-apk\app-release.apk (28.4MB)
Installing build\app\outputs\flutter-apk\app-release.apk... 3,1s
Flutter run key commands.
h List all available interactive commands.
c Clear the screen
q Quit (terminate the application on the device).
I/flutter ( 5618): {latitude: 48.808303333333335, longitude: 3.08294}
However, after this GPS position is broadcasted by the event system, I can't manage to get the real GPS position, even if I'm connected or getting reconnected.
Here is the code of MainActivity.kt
code :
package com.example.idfm_wearos
import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import androidx.annotation.NonNull
import androidx.core.app.ActivityCompat
import com.google.android.gms.location.*
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodChannel
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
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?) {
[email protected] = 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()) {
// Use LocationManager to get last known location from passive provider
val locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
val lastKnownLocation: Location? = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
// Check if a valid last known location is available
if (lastKnownLocation != null) {
Log.d("Location", "Last known location: $lastKnownLocation")
eventSink?.success("${lastKnownLocation.latitude}|${lastKnownLocation.longitude}")
} else {
Log.d("Location", "No passive last known location available")
}
// Now request location updates
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(5)
fastestInterval = TimeUnit.SECONDS.toMillis(3)
priority = LocationRequest.PRIORITY_BALANCED_POWER_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)
startLocationUpdates() // Start location updates after permission is granted
} else {
eventSink?.success(false)
}
}
}
}
Here is the code from the Flutter class I'm using :
import 'package:flutter/services.dart';
class LocationService {
static const MethodChannel _methodChannel = MethodChannel('location_permission');
static const EventChannel _eventChannel = EventChannel('location_updates');
final Map<String, dynamic> _locationData = {
'latitude': 0.0,
'longitude': 0.0,
};
Future<void> startLocationUpdates() async {
try {
await _methodChannel.invokeMethod('requestPermission');
final bool result = await _methodChannel.invokeMethod('checkPermission');
if (result) {
_eventChannel.receiveBroadcastStream().listen((event) {
// Parse the location data (event is a string)
final List<String> data = event.split('|');
_locationData['latitude'] = double.parse(data[0]);
_locationData['longitude'] = double.parse(data[1]);
print(_locationData);
//print("Coordinates: $event");
});
}
} catch (e) {
print("Failed to start location updates: $e");
}
}
Map<String, dynamic> getLocationData() {
return _locationData;
}
}
Timer.periodic(Duration(seconds: 5), (timer) async {
Map<String, dynamic> location = _gpsLocation.getLocationData();
if (location["latitude"] != _locationData["latitude"] || location["longitude"] != _locationData["longitude"]) {
_locationData = location;
await refreshStations();
}
});
Upvotes: 0
Views: 37