-
Notifications
You must be signed in to change notification settings - Fork 0
RG-T133 Removing background geolocation, forground service fix #55
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import type { ConfigContext } from '@expo/config'; | ||
|
|
||
| import createExpoConfig from '../../app.config'; | ||
|
|
||
| const { removeLocationTaskService, LOCATION_TASK_SERVICE } = require('../withoutBackgroundLocation'); | ||
|
|
||
| jest.mock('zod', () => jest.requireActual('zod')); | ||
|
|
||
| type Manifest = { | ||
| manifest: { | ||
| $: Record<string, string>; | ||
| application: { | ||
| $: Record<string, string>; | ||
| service?: { $: Record<string, string> }[]; | ||
| }[]; | ||
| }; | ||
| }; | ||
|
|
||
| // Mirrors what expo-location contributes during manifest merging. | ||
| const createManifest = (): Manifest => ({ | ||
| manifest: { | ||
| $: { 'xmlns:android': 'http://schemas.android.com/apk/res/android' }, | ||
| application: [ | ||
| { | ||
| $: { 'android:name': '.MainApplication' }, | ||
| service: [{ $: { 'android:name': LOCATION_TASK_SERVICE, 'android:exported': 'false', 'android:foregroundServiceType': 'location' } }], | ||
| }, | ||
| ], | ||
| }, | ||
| }); | ||
|
|
||
| const findService = (manifest: Manifest, name: string) => manifest.manifest.application[0].service?.find((service) => service.$['android:name'] === name); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Undefined property access in Kody rule violation: Add null checks to prevent NullReferenceException const findService = (manifest: Manifest, name: string) => manifest.manifest.application?.[0]?.service?.find((service) => service.$['android:name'] === name);Prompt for LLMTalk to Kody by mentioning @kody Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction. |
||
|
|
||
| describe('background location removal', () => { | ||
| it('replaces the location task service with a merger removal directive', () => { | ||
| const manifest = removeLocationTaskService(createManifest()) as Manifest; | ||
| const service = findService(manifest, LOCATION_TASK_SERVICE); | ||
|
|
||
| expect(service?.$['tools:node']).toBe('remove'); | ||
| expect(service?.$['android:foregroundServiceType']).toBeUndefined(); | ||
| expect(manifest.manifest.$['xmlns:tools']).toBe('http://schemas.android.com/tools'); | ||
| }); | ||
|
|
||
| it('declares the removal even when the library manifest has not been merged in yet', () => { | ||
| const manifest = removeLocationTaskService({ | ||
| manifest: { | ||
| $: { 'xmlns:android': 'http://schemas.android.com/apk/res/android' }, | ||
| application: [{ $: { 'android:name': '.MainApplication' } }], | ||
| }, | ||
| } as Manifest) as Manifest; | ||
|
|
||
| expect(findService(manifest, LOCATION_TASK_SERVICE)?.$['tools:node']).toBe('remove'); | ||
| }); | ||
|
|
||
| it('is idempotent across repeated prebuilds', () => { | ||
| const once = removeLocationTaskService(createManifest()) as Manifest; | ||
| const twice = removeLocationTaskService(once) as Manifest; | ||
|
|
||
| expect(twice.manifest.application[0].service).toHaveLength(1); | ||
| expect(findService(twice, LOCATION_TASK_SERVICE)?.$['tools:node']).toBe('remove'); | ||
| }); | ||
|
|
||
| it('keeps background location out of the app config', () => { | ||
| const config = createExpoConfig({ | ||
| config: { | ||
| name: 'Resgrid IC', | ||
| slug: 'resgrid-ic', | ||
| }, | ||
| } as ConfigContext); | ||
|
|
||
| expect(config.plugins).toContain('./plugins/withoutBackgroundLocation.js'); | ||
| expect(config.android?.blockedPermissions).toContain('android.permission.ACCESS_BACKGROUND_LOCATION'); | ||
| expect(config.android?.permissions).not.toContain('android.permission.ACCESS_BACKGROUND_LOCATION'); | ||
| expect(config.ios?.infoPlist?.UIBackgroundModes).not.toContain('location'); | ||
| expect(config.ios?.infoPlist?.NSLocationAlwaysUsageDescription).toBeUndefined(); | ||
| expect(config.ios?.infoPlist?.NSLocationAlwaysAndWhenInUseUsageDescription).toBeUndefined(); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| const { withAndroidManifest, AndroidConfig } = require('expo/config-plugins'); | ||
|
|
||
| const TOOLS_NAMESPACE = 'http://schemas.android.com/tools'; | ||
|
|
||
| /** | ||
| * The IC app tracks location only while it is in the foreground (map centering and | ||
| * distance calculations — see src/services/location.ts). It has no background-location | ||
| * feature, which is why app.config.ts leaves every expo-location background flag off and | ||
| * blocks ACCESS_BACKGROUND_LOCATION / FOREGROUND_SERVICE_LOCATION outright. | ||
| * | ||
| * expo-location's own library manifest still contributes this during merging: | ||
| * | ||
| * <service android:name=".services.LocationTaskService" | ||
| * android:foregroundServiceType="location" /> | ||
| * | ||
| * Nothing starts it (the app never calls Location.startLocationUpdatesAsync and | ||
| * expo-task-manager is not installed), but it leaves a location-typed foreground service | ||
| * in the shipped manifest — exactly the signal a Play policy review reads as background | ||
| * location. Library manifests cannot be edited directly, so declare the same service in | ||
| * the app manifest with tools:node="remove": the merger drops the element and emits | ||
| * nothing for it. | ||
| */ | ||
| const LOCATION_TASK_SERVICE = 'expo.modules.location.services.LocationTaskService'; | ||
|
|
||
| /** | ||
| * Pure manifest transform, exported for tests. | ||
| * | ||
| * @param {object} androidManifest parsed AndroidManifest.xml (xml2js shape) | ||
| * @returns {object} the same manifest, mutated | ||
| */ | ||
| const removeLocationTaskService = (androidManifest) => { | ||
| if (!androidManifest.manifest.$['xmlns:tools']) { | ||
| androidManifest.manifest.$['xmlns:tools'] = TOOLS_NAMESPACE; | ||
| } | ||
|
|
||
| const mainApplication = AndroidConfig.Manifest.getMainApplicationOrThrow(androidManifest); | ||
| const services = mainApplication.service ?? []; | ||
| const removal = { $: { 'android:name': LOCATION_TASK_SERVICE, 'tools:node': 'remove' } }; | ||
| const existingIndex = services.findIndex((service) => service.$?.['android:name'] === LOCATION_TASK_SERVICE); | ||
|
|
||
| if (existingIndex >= 0) { | ||
| services[existingIndex] = removal; | ||
| } else { | ||
| services.push(removal); | ||
| } | ||
|
|
||
| mainApplication.service = services; | ||
| return androidManifest; | ||
| }; | ||
|
|
||
| const withoutBackgroundLocation = (config) => | ||
| withAndroidManifest(config, (config) => { | ||
| config.modResults = removeLocationTaskService(config.modResults); | ||
| return config; | ||
| }); | ||
|
|
||
| module.exports = withoutBackgroundLocation; | ||
| module.exports.removeLocationTaskService = removeLocationTaskService; | ||
| module.exports.LOCATION_TASK_SERVICE = LOCATION_TASK_SERVICE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undefined property access in
plugins/__tests__/without-background-location.test.ts:manifest.manifest.application[0]may be absent, so dereferencing.servicecan throw in thefindServicehelper, including at line 59. Guard the nested path with optional chaining before accessingapplication[0].service.Kody rule violation: Add null checks before accessing properties
Prompt for LLM
Talk to Kody by mentioning @kody
Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.