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
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);
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');
}
}
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" />
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() {
/**
rendering of the component. */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(null) } override fun getMainComponentName(): String = "iWelCGMPal"
/**
// 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!');
} };
// 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();
}, []);
const requestPermissions = async () => { try { if (Platform.OS === 'android') { const apiLevel = await DeviceInfo.getApiLevel();
};
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); } };
}, [token, userid]); // Re-run when token changes
return (
); };
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",