I am developing an Android application that uses Firebase Cloud Messaging (FCM) to send notifications for incoming calls. I want to ensure that notifications are received even when the app is in the background. I have noticed that notifications only appear when the app is in the foreground. They do not show up when the app is running in the background
when android in backgorund . Logcat :
win=Window{f06d548 u0 com.example.tr/com.example.tr.MainActivity} destroySurfaces: appStopped=true cleanupOnResume=false win.mWindowRemovalAllowed=false win.mRemoveOnExit=false win.mViewVisibility=8 caller=com.android.server.wm.ActivityRecord.destroySurfaces:6862 com.android.server.wm.ActivityRecord.destroySurfaces:6843 com.android.server.wm.ActivityRecord.activityStopped:7528 com.android.server.wm.ActivityClientController.activityStopped:310 android.app.IActivityClientController$Stub.onTransact:702 com.android.server.wm.ActivityClientController.onTransact:175 android.os.Binder.execTransactInternal:1380
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<!-- Firebase Messaging Service -->
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="incoming_calls" />
<activity android:name=".IncomingCallActivity"></activity>
<!-- Main Activity -->
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- File Provider for handling file URIs -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/ic_launcher_round" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
</provider>
</application>
<!-- Permissions -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Incoming Call Permissions Start -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<permission
android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
android:protectionLevel="signature" />
<!-- Incoming Call Permissions End -->
</manifest>
MyFirebaseMessagingService.java
package com.example.tr;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.content.Context;
import android.os.Vibrator;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
private static final int NOTIFICATION_ID = 0;
private static final int MISSED_CALL_NOTIFICATION_ID = 1;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
if (remoteMessage.getData().size() > 0) {
sendNotification(remoteMessage);
}
if (remoteMessage.getNotification() != null) {
sendNotification(remoteMessage);
}
}
private void sendNotification(RemoteMessage remoteMessage) {
String title = "INCOMING CALL ";
String body = remoteMessage.getData().get("callerName") + "Sizi arıyor ";
//-->
Intent intent = new Intent(this, IncomingCallActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra("callerName", remoteMessage.getData().get("callerName"));
intent.putExtra("callId", remoteMessage.getData().get("callId"));
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Intent acceptIntent = new Intent(this, IncomingCallActivity.class);
acceptIntent.putExtra("callAction", "accept");
acceptIntent.putExtra("callerName", remoteMessage.getData().get("callerName"));
acceptIntent.putExtra("callId", remoteMessage.getData().get("callId"));
Intent declineIntent = new Intent(this, IncomingCallActivity.class);
declineIntent.putExtra("callAction", "decline");
declineIntent.putExtra("callerName", remoteMessage.getData().get("callerName"));
declineIntent.putExtra("callId", remoteMessage.getData().get("callId"));
PendingIntent acceptPendingIntent = PendingIntent.getActivity(this, 1, acceptIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
PendingIntent declinePendingIntent = PendingIntent.getActivity(this, 2, declineIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "incoming_calls")
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.addAction(R.drawable.ic_accept, "Answer", acceptPendingIntent)
.addAction(R.drawable.ic_decline, "Decline", declinePendingIntent)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setVibrate(new long[]{0, 1000, 800})
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setFullScreenIntent(pendingIntent, true);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("incoming_calls", "Incoming Calls", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
vibrator.vibrate(new long[]{0, 1000, 800}, 0);
}
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
notificationManager.cancel(NOTIFICATION_ID);
sendMissedCallNotification(remoteMessage.getData().get("callerName"));
if (vibrator != null) {
vibrator.cancel();
}
}
}, 3000);
}
private void sendMissedCallNotification(String callerName) {
String title = "Missed Call";
String body = "You missed a call from " + callerName;
NotificationCompat.Builder missedCallBuilder = new NotificationCompat.Builder(this, "missed_calls")
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("missed_calls", "Missed Calls", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(MISSED_CALL_NOTIFICATION_ID, missedCallBuilder.build());
}
}
package com.example.tr;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;
import android.os.Bundle;
import com.getcapacitor.BridgeActivity;
import com.google.firebase.FirebaseApp;
public class MainActivity extends BridgeActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirebaseApp.initializeApp(this);
createNotificationChannel();
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
"incoming_calls", // Channel ID
"Incoming Calls", // Channel name
NotificationManager.IMPORTANCE_HIGH
);
channel.setDescription("Channel for incoming call notifications");
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) {
manager.createNotificationChannel(channel);
}
}
}
}
IncomingCallActivity.java
package com.example.tr;
import android.widget.Button;
import android.widget.TextView;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Vibrator;
import android.util.Log;
public class IncomingCallActivity extends AppCompatActivity {
private Vibrator vibrator;
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_incoming_call);
Intent intent = getIntent();
String callerName = intent.getStringExtra("callerName");
String callId = intent.getStringExtra("callId");
String callAction = intent.getStringExtra("callAction");
TextView callerNameTextView = findViewById(R.id.caller_name);
callerNameTextView.setText(callerName);
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
Button acceptButton = findViewById(R.id.answer_button);
acceptButton.setOnClickListener(v -> {
Log.d("IncomingCallActivity", "Kabul butonuna tıklandı");
// finish();
if (vibrator != null) {
vibrator.cancel();
}
});
Button declineButton = findViewById(R.id.decline_button);
declineButton.setOnClickListener(v -> {
Log.d("IncomingCallActivity", "Reddet butonuna tıklandı");
// finish();
if (vibrator != null) {
vibrator.cancel();
}
});
}
}
api.service.ts:
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ApiService {
static sendNotification(deviceToken: string) {
throw new Error("Method not implemented.");
}
private apiUrl = '';
private accessToken =""
constructor(private http: HttpClient) {}
sendNotification(token: string ): Observable<any> {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.accessToken}`
});
console.log("send push noti token ->",token)
const notificationData = {
token: token,
// notification: {
// title: 'Incoming Calls',
// body: 'aramanız varr',
// },
data: {
title: 'Incoming Call',
body: 'Cevapsız aramanız var ',
callType: 'incoming',
callerName: 'John Doe',
callId: '12345',
priority: 'high'
},
android: {
priority: 'high',
notification: {
channel_id: 'incoming_calls',
sound: 'default',
// full_screen_intent: true,
},
},
};
const body = {
message: notificationData
};
return this.http.post<any>(this.apiUrl, body, { headers });
}
}```
`Home.page.ts`
``
import { Component } from "@angular/core";
import {
FirebaseMessaging,
GetTokenOptions,
} from "@capacitor-firebase/messaging";
import { Capacitor } from "@capacitor/core";
import { IonicModule } from "@ionic/angular";
import { environment } from "src/environments/environment";
import { NotificationService } from '../services/notification.service';
import { ApiService } from "../api/api.service";
@Component({
selector: "app-home",
templateUrl: "home.page.html",
styleUrls: ["home.page.scss"],
standalone: true,
imports: [IonicModule],
})
export class HomePage {
public token = "";
constructor(
private notificationService: NotificationService,
private apiService: ApiService
) {
FirebaseMessaging.addListener("notificationReceived", (event) => {
console.log("notificationReceived: ", { event });
});
FirebaseMessaging.addListener("notificationActionPerformed", (event) => {
console.log("notificationActionPerformed: ", { event });
});
if (Capacitor.getPlatform() === "web") {
navigator.serviceWorker.addEventListener("message", (event: any) => {
console.log("serviceWorker message: ", { event });
const notification = new Notification(event.data.notification.title, {
body: event.data.notification.body,
});
notification.onclick = (event) => {
console.log("notification clicked: ", { event });
};
});
}
}
public async requestPermissions(): Promise<void> {
const result = await FirebaseMessaging.requestPermissions();
if (result.receive === 'granted') {
console.log('Push notifications permission granted');
}
}
public async getToken(): Promise<void> {
const options: GetTokenOptions = {
vapidKey: environment.firebase.vapidKey,
};
if (Capacitor.getPlatform() === "web") {
options.serviceWorkerRegistration =
await navigator.serviceWorker.register("firebase-messaging-sw.js");
}
const { token } = await FirebaseMessaging.getToken(options);
this.token = token;
}
sendPushNotification() {
const deviceToken = "fIuEs9LlRwO6J06ahgWCtC:APA91bF5VnhsCYAyHxudm1de2s4sVYfUWkenKl8zvOxbjHa2_eOv5MlU2FNTogrPYu4bCJKKiNxM7LpQvc7w_iW59fKGoevE0OjYnYPrxHjj8x5T7uvqdW3_j3HXpTj3F_DrLYeBVpX4"
console.log("Device token is here -> : ", deviceToken);
if (!deviceToken) {
console.error('No device token available. Unable to send notification.');
return;
}
this.apiService.sendNotification(deviceToken).subscribe(
(response: any) => {
console.log('Push notification sent:', response);
},
(error: any) => {
console.error('Error sending notification:', error);
console.error('Full error response:', JSON.stringify(error.error));
}
);
}
}
```