Fatal Exception: java.lang.RuntimeException want to use foregroundServiceType="connectedDevice"
App crashes we want to use foregroundServiceType="connectedDevice"
Unable to start service com.asterinet.react.bgactions.RNBackgroundActionsTask@243c415 with Intent { cmp=com.iwelhealth.cgmpal/com.asterinet.react.bgactions.RNBackgroundActionsTask (has extras) mCallingUid=10388 }: android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() not allowed due to mAllowStartForeground false: service com.iwelhealth.cgmpal/com.asterinet.react.bgactions.RNBackgroundActionsTask android.app.ActivityThread.handleServiceArgs
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:extractNativeLibs="true" android:screenOrientation="portrait" android:theme="@style/AppTheme"> <service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" android:permission="android.permission.FOREGROUND_SERVICE" android:foregroundServiceType="connectedDevice" android:exported="false" />
<meta-data
android:name="com.auth0.client.android.scheme"
android:value="https://iwell.page.link?utm_campaign=banner&apn=com.iwell&ibi=com.clovahealth.clova&isi=6448808039&link=https%3A%2F%2Finvertase.io%2Fterralogin" />
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="app.clovahealth.com"
android:pathPrefix="/cgm/callback" />
<data android:scheme="https" android:host="iwell.page.link" />
<data android:scheme="https" android:host="iwell.page.link" />
</intent-filter>
</activity>
package com.iwelhealth.cgmpal
import com.facebook.react.ReactActivity import com.facebook.react.ReactActivityDelegate import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled import com.facebook.react.defaults.DefaultReactActivityDelegate import android.os.Bundle // here
class MainActivity : ReactActivity() {
/**
- Returns the name of the main component registered from JavaScript. This is used to schedule
- rendering of the component. */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(null) } override fun getMainComponentName(): String = "iWelCGMPal"
/**
- Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
- which allows you to enable New Architecture with a single boolean flags [fabricEnabled] */ override fun createReactActivityDelegate(): ReactActivityDelegate = DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) } import React, {useEffect, useState} from 'react'; import { StyleSheet, SafeAreaView, KeyboardAvoidingView, Platform, Alert, Linking, PermissionsAndroid, } from 'react-native'; import {Navigation} from './navigation/Navigation'; import {StatusBar} from 'expo-status-bar'; import {NavigationContainer} from '@react-navigation/native'; import BackgroundService from 'react-native-background-actions'; import CGMDataService from './services/cgmService'; import AsyncStorage from '@react-native-async-storage/async-storage'; import {PERMISSIONS, requestMultiple} from 'react-native-permissions'; import DeviceInfo from 'react-native-device-info';
// Define your background task function const veryIntensiveTask = async () => { const {getCGMData} = CGMDataService();
// While the background service is running while (BackgroundService.isRunning()) { console.log('Running background task!');
// Call the CGM data fetching function
await getCGMData();
// Simulate delay for continuous task running
} };
// Options for the background service const options = { taskName: 'iWelCGMPal', taskTitle: 'iWelCGMPal', taskDesc: 'CGM Glucose Data description', taskIcon: { name: 'ic_launcher_notification', type: 'mipmap', }, linkingURI: 'yourSchemeHere://chat/jane', parameters: { delay: 60000, }, };
const AppEntry = () => { // State for token const [token, setToken] = useState(null); const [userid, setUserid] = useState(null);
// Function to check AsyncStorage for token regularly const checkHexArray = async () => { const savedToken = await AsyncStorage.getItem('token'); const savedUserid = await AsyncStorage.getItem('userid'); if (savedToken !== token && savedUserid !== userid) { setToken(savedToken); setUserid(savedUserid); // Update state only if it has changed console.log('Device ID (token) updated:', savedToken, savedUserid); } };
useEffect(() => { // Fetch token on mount checkHexArray();
// Start a polling interval to check AsyncStorage for updates
const intervalId = setInterval(() => {
checkHexArray();
}, 5000); // Poll every 5 seconds (adjust as necessary)
// Cleanup interval on component unmount
return () => clearInterval(intervalId);
}, []);
const requestPermissions = async () => { try { if (Platform.OS === 'android') { const apiLevel = await DeviceInfo.getApiLevel();
if (apiLevel < 31) {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Location Permission',
message: 'Bluetooth Low Energy requires Location',
buttonNeutral: 'Ask Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
return true;
} else if (granted === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
Alert.alert(
'Permission Denied',
'Please go to settings and enable Location And Nearby Devices permissions.',
[
{
text: 'Go to Settings',
onPress: () => Linking.openSettings(),
},
{text: 'Cancel', style: 'cancel'},
],
);
}
return false;
} else {
const result = await requestMultiple([
PERMISSIONS.ANDROID.BLUETOOTH_SCAN,
PERMISSIONS.ANDROID.BLUETOOTH_CONNECT,
PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
]);
const isGranted =
result['android.permission.BLUETOOTH_CONNECT'] ===
PermissionsAndroid.RESULTS.GRANTED &&
result['android.permission.BLUETOOTH_SCAN'] ===
PermissionsAndroid.RESULTS.GRANTED &&
result['android.permission.ACCESS_FINE_LOCATION'] ===
PermissionsAndroid.RESULTS.GRANTED;
if (isGranted) {
return true;
} else {
const neverAskAgain =
result['android.permission.BLUETOOTH_CONNECT'] ===
PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN ||
result['android.permission.BLUETOOTH_SCAN'] ===
PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN ||
result['android.permission.ACCESS_FINE_LOCATION'] ===
PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN;
if (neverAskAgain) {
Alert.alert(
'Permission Denied',
'Please go to settings and enable Bluetooth and location permissions.',
[
{
text: 'Go to Settings',
onPress: () => Linking.openSettings(),
},
{text: 'Cancel', style: 'cancel'},
],
);
}
return false;
}
}
} else {
return true;
}
} catch (err) {
console.error(err);
return false;
}
};
useEffect(() => { if (token) { // Start background service when token is available const startBackgroundService = async () => { try { const isGrant = await requestPermissions(); if (isGrant) { if (!BackgroundService.isRunning()) { await BackgroundService.start(veryIntensiveTask, options); console.log('Background service started'); } } else { console.log('no permission granted '); } } catch (e) { console.error('Error starting background service:', e); } };
startBackgroundService();
} else {
// Stop background service when token is not available
if (BackgroundService.isRunning()) {
BackgroundService.stop();
console.log('Background service stopped due to missing token');
}
}
}, [token, userid]); // Re-run when token changes
return ( <NavigationContainer> <SafeAreaView style={styles.root}> <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={styles.root}> <StatusBar style="auto" /> <Navigation /> </KeyboardAvoidingView> </SafeAreaView> </NavigationContainer> ); };
export default AppEntry;
const styles = StyleSheet.create({ root: { flex: 1, }, }); "react": "18.2.0", "react-native": "0.73.6", "react-native-background-actions": "^4.0.1",
I can confirm this is a bug, it ended my prod build
It's fixed it was just we have to allow permission at the beginning only
@FaizyQadri @Faizan-Hurekatek @rakshitbharat How did you solve this? What are the additional permissions needed in the beginning? App Crashes for me.
@FaizyQadri @Faizan-Hurekatek @rakshitbharat How did you solve this? What are the additional permissions needed in the beginning? App Crashes for me.
U suggest have to add permission in service tag as well
@FaizyQadri @Faizan-Hurekatek @rakshitbharat How did you solve this? What are the additional permissions needed in the beginning? App Crashes for me.
<manifest ... > ... <application ... > ... <service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" android:foregroundServiceType="shortService" Add permissionexpored trueor false /> ... ...