I am working on MVVM app and I am getting the following error when using location tracking with GoogleMap composable:
2022-10-02 18:43:48.734 31711-31750/com.park.reserved W/MobStoreFlagStore: Unable to update local snapshot for com.google.android.libraries.consentverifier#com.park.reserved, may result in stale flags.
java.util.concurrent.ExecutionException: java.lang.SecurityException: GoogleCertificatesRslt: not allowed: pkg=com.park.reserved, sha256=[462925ab37c5ec4ab8550323438372023f34e9897a556848dd8c35d18c4e71c6], atk=false, ver=223616044.true (go/gsrlt)
at ahn.s(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):3)
at ahn.get(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):2)
at aix.g(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):2)
at xq.d(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):1)
at xs.run(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):0)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:463)
at java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:307)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Caused by: java.lang.SecurityException: GoogleCertificatesRslt: not allowed: pkg=com.park.reserved, sha256=[462925ab37c5ec4ab8550323438372023f34e9897a556848dd8c35d18c4e71c6], atk=false, ver=223616044.true (go/gsrlt)
at android.os.Parcel.createExceptionOrNull(Parcel.java:2426)
at android.os.Parcel.createException(Parcel.java:2410)
at android.os.Parcel.readException(Parcel.java:2393)
at android.os.Parcel.readException(Parcel.java:2335)
at em.c(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):2)
at rc.a(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):4)
at it.e(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):2)
at js.t(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):2)
at js.u(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):3)
at js.e(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):2)
at jw.handleMessage(:com.google.android.gms.dynamite_mapsdynamite@223616044@22.36.16 (190400-0):69)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.os.HandlerThread.run(HandlerThread.java:67)
The app still runs when this happens, but the location tracking on GoogleMap compose doesn't work [I can successfully track the phone location, but I get the exception when trying to show the location on GoogleMap
compose]
Gradle:
implementation "com.google.maps.android:maps-compose:2.7.2"
implementation "com.google.android.gms:play-services-maps:18.1.0"
I looked at the following similar StackOverflow post, but the error I'm getting is different: SecurityException - GoogleCertificatesRslt: not allowed
The only way I was able to fix the issue is by creating the viewModel outside of the NavHost. The location tracking works doing it this way, but the exception still gets thrown in Logcat
Here's the code:
I have SharedLocationManager
class that serves as location data source:
class SharedLocationManager constructor(
private val context: Context,
// The Fused Location Provider provides access to location APIs
private val fusedLocationClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(context)
) {
. . .
}
I have LocationRepository
class:
class LocationRepository @Inject constructor(
private val sharedLocationManager: SharedLocationManager
) {
// Observe flow for device last location updates
fun lastLocation(): Flow<Location> = sharedLocationManager.lastLocationFlow()
// Observable flow for device location updates
fun getLocationFlow(): SharedFlow<Location?> = sharedLocationManager.locationFlow()
}
I have viewModel
that takes the LocationRepository
:
@HiltViewModel
class FindParkingViewModel @Inject constructor(
private val repository: LocationRepository // Data store from which to receive location updates via Flow, injected via Hilt
) : ViewModel() {
. . .
}
Then, I have a composable that takes the viewModel
argument, gets the location from the viewModel and displays it on GoogleMaps:
@Composable
fun FindParking(findParkingViewModel: FindParkingViewModel) {
findParkingViewModel location has value
val deviceCurrentLoc by findParkingViewModel.location.collectAsState(initial = null)
. . .
val cameraPosState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(deviceCurrentLocLatLng, 12f)
}
GoogleMap(
modifier = modifier,
cameraPositionState = cameraPositionState,
properties = mapProperties,
uiSettings = uiSettings,
onMapLoaded = onMapLoaded
) {
}
}
Finally, I have the NavHost
:
@Composable
fun MapAppNavHost(
navController: NavHostController,
modifier: Modifier = Modifier
) {
// ** Creating the viewModel here solves the issue
location tracking val findParkingViewModel: FindParkingViewModel = hiltViewModel()
NavHost(
navController = navController,
startDestination = TopLevelDestination.Parking.route,
modifier = modifier
) {
composable(route = TopLevelDestination.Parking.route) {
FindParking(findParkingViewModel)
}
. . .
}
Doing it the following way throws the exception:
I prefer #1
approach because the code is cleaner.
#1.
Assigning the viewModel as a default parameter throws an error:
@Composable
fun FindParking(findParkingViewModel: FindParkingViewModel = hiltViewModel()) {
. . .
}
#2
creating the viewModel
within the NavHost
Composable
function also throws an error:
NavHost(
navController = navController,
startDestination = TopLevelDestination.Parking.route,
modifier = modifier
) {
composable(route = TopLevelDestination.Parking.route) {
// ---> creating this here breaks it
val findParkingViewModel: FindParkingViewModel = hiltViewModel()
FindParking(findParkingViewModel)
}
}