Understanding Long Running Background Services There are services in Android which run for a long time in the background which are BLE scanning ,Data Synching, Location Update or Reminders. Challenges: These services tend to consume a lot of battery, can induce loads of CPU and become restricted due to Doze mode and background from Android 8.0 (Oreo) and above.
Requirements for handling:
This implementation provides a foreground service that continuously scans for BLE devices, even when the app is in the background, ensuring that the BLE scan is not interrupted by Doze mode or other background limitations in Android.
Android offers several libraries and tools to simplify and optimize network operations:
1. Service Class (FService.java)
The service class which binds the BleScanService is BleScanService.java Basically, the BlueScanService class is a foreground service that has the responsibility to implement the BLE scanning in the background. It uses a notification to help keep the service active during its operation and allow it to survive.
class FService : Service() {
companion object {
private const val TAG = "FService"
private const val CHANNEL_ID = "RefactoredServiceChannel"
private const val NOTIFICATION_ID = 10
private const val SCANNING_INTERVAL_MS = 15000 // 15 seconds
}
private lateinit var handler: Handler
private var wakeLock: PowerManager.WakeLock? = null
private var isServiceRunning = false
private lateinit var bleInteractor: BLEConnectionManager
override fun onCreate() {
super.onCreate()
handler = Handler(Looper.getMainLooper())
bleInteractor = BLEConnectionManager(this)
initializeLeManager()
createNotificationChannel()
startForeground(NOTIFICATION_ID, createNotification())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (!isServiceRunning) {
isServiceRunning = true
acquireWakeLock()
startPeriodicScanning()
startServerLoggingTask()
}
return START_STICKY
}
private fun initializeLeManager() {
// Initialize BLE manager here
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
CHANNEL_ID,
"Refactored Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(NotificationManager::class.java)
manager?.createNotificationChannel(serviceChannel)
}
}
private fun createNotification(): Notification {
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
0,
notificationIntent,
PendingIntent.FLAG_IMMUTABLE
)
return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Service Running")
.setContentText("Your service is running in the foreground.")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pendingIntent)
.build()
}
private fun acquireWakeLock() {
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "$TAG:WakeLock")
wakeLock?.acquire()
}
private fun startPeriodicScanning() {
handler.postDelayed(object : Runnable {
override fun run() {
bleInteractor.scanForDevices()
handler.postDelayed(this, SCANNING_INTERVAL_MS.toLong())
}
}, SCANNING_INTERVAL_MS.toLong())
}
private fun startServerLoggingTask() {
// Start any background logging or server task here
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
wakeLock?.release()
isServiceRunning = false
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
Foreground Service: The startForeground() method starts the service in foregrounds meaning BLE scanning and notification is active.
Notification Channel: For Android 8.0+ (API level 26) a notification channel is created for the foreground service. BLE Scanning: The startBleScanning() method must contain the BLE scanning code either using BluetoothLeScanner or your preferred BLE scanning library.
2. Include the Service in a file called AndroidManifest.xml Make sure that the service you have created is declared in the AndroidManifest.xml so that their applications could use it.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name="com.asterinet.react.bgactions.BackgroundActionsTask"
android:foregroundServiceType="connectedDevice|location|dataSync"
android:exported="false"
android:stopWithTask="false" />
<service
android:name=".ServiceLocationDataSync"
android:foregroundServiceType="connectedDevice|location"
android:exported="false"
android:stopWithTask="false" />
<service android:name="native.module.fallDetection.BackgroundFallDetection" />
<service
android:name=".native.module.speech.SpeechServiceNew"
android:foregroundServiceType="microphone"
android:exported="false"
android:stopWithTask="false" />
</application>
</manifest>
3. Native Module design and Generate ( BNBModule: BleServiceModule.java) There is developed a native module that may interact with React Native and the foreground service is started or stopped via JavaScript.
public class BLEConnectionManager {
private static final long SCAN_PERIOD = 45000; // Scan duration in milliseconds
private final Handler scanHandler = new Handler(Looper.getMainLooper());
private boolean isReceiverRegistered = false;
private Context context;
private BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
// Constructor
public BLEConnectionManager(Context context) {
this.context = context;
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
// Register receiver for Bluetooth state changes
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
if (!isReceiverRegistered) {
// Register the receiver
context.registerReceiver(bluetoothStateReceiver, filter);
isReceiverRegistered = true;
}
}
// Define the BluetoothReceiver here (if not already defined elsewhere)
private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Handle Bluetooth state changes here
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_ON:
// Bluetooth is ON
break;
case BluetoothAdapter.STATE_OFF:
// Bluetooth is OFF
break;
default:
// Handle other states
break;
}
}
};
// Don't forget to unregister the receiver in the appropriate lifecycle method (e.g., onStop)
public void unregisterReceiver() {
if (isReceiverRegistered) {
context.unregisterReceiver(bluetoothStateReceiver);
isReceiverRegistered = false;
}
}
}
startBleScanning(): Launches the BleScanService to start the BLE scan process Stocks stopBleScanning(): Called by the service to stop the bleach BleScanService to terminate BLE scanning.
4. The Native Module should be registered in MainApplication.java In the android end, in MainApplication.java, make the native module accessible to your JavaScript code in React Native.
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.react.PackageList;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG; // Correct the typo 'DEUUO' to 'DEBUG'
}
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Add custom packages
packages.add(new MyPackage());
packages.add(new FallDetectionPackage()); // Add custom packages
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index"; // Main entry point for JS
}
};
private final ReactNativeHost mNewArchitectureNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new MyPackage());
packages.add(new FallDetectionPackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
// Return the appropriate ReactNativeHost based on the build config for the new architecture
return BuildConfig.TS_NEW_ARCHITECTURE_ENABLED ? mNewArchitectureNativeHost : mReactNativeHost;
}
}
5. Application of Native Module in React Native In the present days, the native module can be utilized in the React Native JavaScript code for the execution of the foreground service for BLE scanning.
import { NativeModules } from 'react-native';
const { BleService } = NativeModules; // Start BLE scanning in the foreground BleService.startBleScanning(); // Stop BLE scanning when no longer needed BleService.stopBleScanning();
6. Permissions
Ensure you have the necessary permissions declared in the AndroidManifest.xml file to access Bluetooth and location services:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Permissions -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.BLUETOOTH" />
</manifest>
1. Transparency and Consent
Clearly outline data collection practices in the app's privacy policy.
Use consent mechanisms to obtain user approval for data processing.
2. Data Minimization
Collect only the data necessary for the app’s operation. Avoid storing excessive user information.
3. Right to Access and Erasure
Implement mechanisms to allow users to view and delete their data, ensuring compliance with GDPR and similar laws.
4. Data Breach Management
Establish a protocol for detecting, reporting and addressing data breaches promptly.
Security and data privacy are fundamental to the success of Android applications. By implementing robust security measures and adhering to global data protection regulations, developers can build trustworthy apps that respect user privacy and operate securely in an increasingly interconnected world. Stay proactive in adapting to emerging threats and evolving legal requirements to maintain a strong security posture.
Ready to transform your business with our technology solutions? Contact Us today to Leverage Our Android Expertise.
0