-
Notifications
You must be signed in to change notification settings - Fork 0
Develop #57
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
Develop #57
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| const { withAndroidManifest, AndroidConfig } = require('expo/config-plugins'); | ||
|
|
||
| const SERVICE_NAME = 'app.notifee.core.ForegroundService'; | ||
|
|
||
| const withForegroundService = (config) => { | ||
| return withAndroidManifest(config, async (config) => { | ||
| const manifest = config.modResults; | ||
|
|
@@ -11,13 +13,23 @@ const withForegroundService = (config) => { | |
| const mainApplication = AndroidConfig.Manifest.getMainApplicationOrThrow(manifest); | ||
|
|
||
| mainApplication['service'] = mainApplication['service'] || []; | ||
| mainApplication['service'].push({ | ||
|
|
||
| // Idempotent: a prebuild that reuses an existing android/ dir already has this service in | ||
| // the base manifest — and non-clean prebuilds have already accumulated duplicates there — so | ||
| // drop every copy before adding the canonical one. | ||
| const serviceEntry = { | ||
| $: { | ||
| 'android:name': 'app.notifee.core.ForegroundService', | ||
| 'android:foregroundServiceType': 'microphone|connectedDevice', | ||
| 'android:name': SERVICE_NAME, | ||
| // microphone only. mediaPlayback and connectedDevice are intentionally absent: this | ||
| // service backs PTT capture, expo-audio owns its own mediaPlayback service for stream | ||
| // playback, and Bluetooth PTT handsets run on the same microphone session. Play rejects | ||
| // foreground-service types whose use case cannot be demonstrated in the app. | ||
| 'android:foregroundServiceType': 'microphone', | ||
| 'tools:replace': 'android:foregroundServiceType', | ||
| }, | ||
| }); | ||
| }; | ||
| mainApplication['service'] = mainApplication['service'].filter((service) => service?.$?.['android:name'] !== SERVICE_NAME); | ||
| mainApplication['service'].push(serviceEntry); | ||
|
Comment on lines
+20
to
+32
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. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify the requested Notifee/LiveKit foreground-service types and manifest policy agree.
rg -n -C 10 --glob '*.{ts,tsx,js}' \
'foregroundServiceTypes|FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE|FOREGROUND_SERVICE_CONNECTED_DEVICE|app\.notifee\.core\.ForegroundService' \
src app.config.ts customManifest.plugin.jsRepository: Resgrid/IC Length of output: 4572 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- repository knowledge scopes ---'
find /tmp/coderabbit-repo-knowledge/resgrid-ic-2b2f7643 -maxdepth 2 -type f -name '*.md' -print \
| sort
printf '%s\n' '--- likely scoped conventions and learnings ---'
for f in $(find /tmp/coderabbit-repo-knowledge/resgrid-ic-2b2f7643 -maxdepth 2 -type f -name '*.md' | sort); do
case "$f" in
*/learnings/*|*/architecture/*) ;;
*) printf '\n### %s\n' "$f"; head -80 "$f" ;;
esac
done
printf '%s\n' '--- changed manifest plugin ---'
cat -n customManifest.plugin.js | sed -n '1,60p'
printf '%s\n' '--- Android configuration block ---'
cat -n app.config.ts | sed -n '75,130p'
printf '%s\n' '--- LiveKit Notifee call and imports ---'
cat -n src/stores/app/livekit-store.ts | sed -n '1,45p'
cat -n src/stores/app/livekit-store.ts | sed -n '675,730p'
printf '%s\n' '--- Notifee dependency metadata ---'
rg -n -C 3 '"`@notifee`|notifee|foregroundServiceTypes|AndroidForegroundServiceType' \
package.json package-lock.json yarn.lock pnpm-lock.yaml bun.lockb 2>/dev/null || trueRepository: Resgrid/IC Length of output: 23911 🌐 Web query:
💡 Result: In Notifee 9.1.8, Android foreground service types are a strict requirement for apps targeting Android 14 (API level 34) or higher [1]. To implement this, you must declare the necessary foreground service types in your AndroidManifest.xml and optionally specify them dynamically when creating the notification [2][3]. 1. Manifest Configuration You must declare Notifee's foreground service in your AndroidManifest.xml within the application tag [2][3]. Because Notifee includes a default service definition, you must use tools:replace to override it with your required types [2][4]. Ensure your manifest includes the tools namespace and the service definition: If your service requires multiple types, separate them with the pipe (|) character (e.g., location|camera|microphone) [2][5]. 2. Dynamic Specification When displaying a notification that runs as a foreground service, you can provide the foregroundServiceTypes property to specify the types used for that specific instance [2][6]. These types must be a subset of those declared in your manifest [7]. import notifee, { AndroidForegroundServiceType } from ' Citations:
🌐 Web query:
💡 Result: In Android development, when using foreground services, you must declare the appropriate foregroundServiceType in your Android manifest and, for apps targeting Android 14 (API level 34) or higher, request specific permissions associated with those types [1][2][3]. Connected Device Type (connectedDevice) This type is used for interaction with external devices, including data transfer via Bluetooth, NFC, IR, USB, or network connections [1][4]. - Manifest Permission: You must declare FOREGROUND_SERVICE_CONNECTED_DEVICE in your manifest [1][2]. - Prerequisites: To use this type, your app must meet at least one of these conditions: - Declare at least one of several hardware-related permissions in your manifest, such as CHANGE_NETWORK_STATE, CHANGE_WIFI_STATE, NFC, or TRANSMIT_IR [1][2]. - Be granted at least one of the following runtime permissions: BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE, BLUETOOTH_SCAN, or UWB_RANGING [1][2]. Microphone Type (microphone) This type is used for background audio capture, such as voice recorders or communication apps [1][2]. - Manifest Permission: You must declare FOREGROUND_SERVICE_MICROPHONE in your manifest [1][2]. - Prerequisites: Your app must be granted the RECORD_AUDIO runtime permission [1][2]. Important Implementation Notes - Multiple Types: If a service performs multiple tasks, you can declare multiple types in the manifest by separating them with the pipe (|) operator (e.g., android:foregroundServiceType="connectedDevice|microphone") [5][2][6]. - Runtime Enforcement: For apps targeting Android 14+, if you attempt to start a foreground service without the required runtime permissions for the specified type, the system will throw a SecurityException [7][3]. - Background Start Restrictions: If your service requires "while-in-use" permissions (like microphone), you must generally start the service while your app has a visible activity to avoid restrictions on starting foreground services from the background [7]. Always check the latest official documentation for specific exemptions [1][7]. Citations:
Align the Notifee foreground-service types. When 📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| return config; | ||
| }); | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| import { api } from '../common/client'; | ||
|
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. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win Use the configured API alias. Replace the relative As per coding guidelines, use configured path aliases ( 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
|
|
||
| const DATA_PROTECTION = '/DataProtection'; | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Advanced Data Protection (ADP) — capability report, MFA step-up, and the | ||
| // exemption path. | ||
| // | ||
| // The step-up window is ABSOLUTE: the server returns its expiry once and never | ||
| // slides it. Clients conceal protected values at expiry and ask again on the | ||
| // next reveal. | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| export interface DataProtectionCapabilitiesData { | ||
| State: number; | ||
| StateName?: string | null; | ||
| IsProtectionEnabled: boolean; | ||
| CatalogVersion: number; | ||
| CurrentCatalogVersion: number; | ||
| PolicyEpoch: number; | ||
| StepUpWindowMinutes: number; | ||
| IsDepartmentLocked: boolean; | ||
| LockReason?: string | null; | ||
| LockProjectedEndUtc?: string | null; | ||
| } | ||
|
|
||
| export interface DataProtectionCapabilitiesResult { | ||
| Data?: DataProtectionCapabilitiesData; | ||
| } | ||
|
|
||
| export interface StepUpResult { | ||
| /** Grant id (jti) for display/audit correlation; null when grants are not configured. */ | ||
| GrantId?: string | null; | ||
| /** Signed Protected Data Grant. MEMORY ONLY — never persisted, never logged. */ | ||
| GrantToken?: string | null; | ||
| /** Absolute UTC expiry of the step-up window (ISO 8601). */ | ||
| StepUpExpiresOnUtc?: string | null; | ||
| StepUpWindowMinutes?: number; | ||
| } | ||
|
|
||
| /** Value-free ADP capability report for the caller's department. */ | ||
| export const getDataProtectionCapabilities = async (signal?: AbortSignal) => { | ||
|
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. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win Use the shared API endpoint abstraction. Define these endpoints through As per coding guidelines, define API endpoints through Also applies to: 58-58, 68-68 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| const response = await api.get<DataProtectionCapabilitiesResult>(`${DATA_PROTECTION}/Capabilities`, { signal }); | ||
| return response.data; | ||
| }; | ||
|
|
||
| /** | ||
| * Asks for a grant WITHOUT a second factor. | ||
| * | ||
| * A department may release named apps from the step-up prompt (ADP plan 3.3) — a dispatcher on a | ||
| * live incident cannot stop to read a code off a phone. The server answers with a grant when this | ||
| * department has exempted THIS app, and with `step_up_required` otherwise. The client never makes | ||
| * that decision; it only asks and reacts. | ||
| * | ||
| * Nothing is weakened by asking: the caller is still authenticated, and the grant that comes back | ||
| * is still tenant-bound, epoch-bound, short-lived and audited on every read it authorizes. | ||
| */ | ||
| export const requestProtectedGrant = async () => { | ||
| const response = await api.post<StepUpResult>(`${DATA_PROTECTION}/RequestGrant`, {}); | ||
| return response.data; | ||
| }; | ||
|
|
||
| /** | ||
| * Verifies the user's authenticator (TOTP) code for the ADP step-up. | ||
| * Server problem types: invalid_totp (400/401), mfa_not_enrolled (409), | ||
| * too_many_attempts (429). The code is never logged anywhere. | ||
| */ | ||
| export const verifyStepUp = async (code: string) => { | ||
| const response = await api.post<StepUpResult>(`${DATA_PROTECTION}/VerifyStepUp`, { Code: code }); | ||
| return response.data; | ||
| }; | ||
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.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: Resgrid/IC
Length of output: 196
🏁 Script executed:
Repository: Resgrid/IC
Length of output: 31956
🏁 Script executed:
Repository: Resgrid/IC
Length of output: 21666
🌐 Web query:
Expo SDK 56 expo-location config plugin supported options taskManager locationTaskName locationTaskOptions expo-task-manager app.json💡 Result:
In Expo SDK 56, the
expo-locationconfig plugin allows you to configure native permissions and background location settings in yourapp.jsonorapp.config.jsfile [1]. This is required if you are using Continuous Native Generation (CNG) and need to modify theInfo.plist(iOS) orAndroidManifest.xml(Android) files [1]. Theexpo-locationplugin does not have direct options forlocationTaskNameorlocationTaskOptions, as these are runtime parameters used by theexpo-task-managerlibrary when callingstartLocationUpdatesAsync[1][2]. The config plugin specifically focuses on build-time native configuration [1]. Supported options for theexpo-locationconfig plugin include [1]: iOS Options: - locationAlwaysAndWhenInUsePermission (string): Sets the NSLocationAlwaysAndWhenInUseUsageDescription [1]. - locationAlwaysPermission (string): Sets the NSLocationAlwaysUsageDescription (deprecated) [1]. - locationWhenInUsePermission (string): Sets the NSLocationWhenInUseUsageDescription [1]. - isIosBackgroundLocationEnabled (boolean): Enables location in UIBackgroundModes in Info.plist (default: false) [1]. Android Options: - isAndroidBackgroundLocationEnabled (boolean): Enables the ACCESS_BACKGROUND_LOCATION permission (default: false) [1]. - isAndroidForegroundServiceEnabled (boolean): Enables FOREGROUND_SERVICE and FOREGROUND_SERVICE_LOCATION permissions (default: true if isAndroidBackgroundLocationEnabled is true, otherwise false) [1]. - androidForegroundServiceIcon (string): Local path to a 96x96 all-white PNG with transparency to use as the icon for the foreground service [1]. Example configuration inapp.json: { "expo": { "plugins": [ [ "expo-location", { "locationAlwaysAndWhenInUsePermission": "Allow $(PRODUCT_NAME) to use your location.", "isIosBackgroundLocationEnabled": true, "isAndroidBackgroundLocationEnabled": true } ] ] } } To implement background tasks, you must define your tasks usingTaskManager.defineTaskin your JavaScript/TypeScript code at the top level of your file, not within a component [2][3]. ThelocationTaskNameyou use inTaskManager.defineTaskmust match the string passed tostartLocationUpdatesAsyncat runtime, rather than being defined in the config plugin [2].Citations:
Remove the inert background-task configuration.
The Expo SDK 56
expo-locationplugin does not supporttaskManager,locationTaskName, orlocationTaskOptions; these entries do not registerlocation-updates.src/services/location.tsuses foregroundwatchPositionAsync()and stops tracking when the app backgrounds. Remove both task-manager blocks and the background-location flags, unless the app implements deliberate runtime background tracking.🤖 Prompt for AI Agents