Tech 4 min read

Implementing Firebase FCM Push Notifications (WebView + Android)

This is something I implemented around summer 2025 for a separate project. Since this was before I migrated my blog, I never wrote it up. Writing it down now before I forget.

This covers how I added push notifications to a WebView-based Android app.

FCM Basics

What Is an FCM Token?

An identifier that Firebase automatically generates per device. It’s not derived from a user ID — it’s specific to the device. It can change when the app is reinstalled or after a certain period.

What You Need

All you need for push notifications is “user ID + FCM token.” An email address is only for personalizing notification content and isn’t required.

Overall Architecture

1. Web side creates user → issues user ID
2. Pass user ID to the app (via JavaScript Interface)
3. App retrieves FCM token
4. Send user ID + FCM token to server → save to DB

Division of Responsibilities

RoleHandled by
User management & authenticationWeb side
Business logicWeb side
Deciding when/who/what to notifyWeb side (server)
FCM token retrievalApp side
Receiving & displaying notificationsApp side

The app is just “a WebView container + notification capability.” The real work happens on the web side.

Server-Side Implementation (PHP)

Saving FCM Tokens

No need to store these in Firebase — your own DB works fine.

CREATE TABLE user_fcm_tokens (
  user_id VARCHAR(255),
  fcm_token VARCHAR(500),
  created_at TIMESTAMP
);

Installing the Library

composer require kreait/firebase-php

Sending Individual Notifications

use Kreait\Firebase\Factory;
use Kreait\Firebase\Messaging\CloudMessage;

class NotificationService
{
    private $messaging;

    public function __construct() {
        $factory = (new Factory)
            ->withServiceAccount('/path/to/service-account.json');
        $this->messaging = $factory->createMessaging();
    }

    public function sendToUser($userId, $title, $body) {
        $fcmToken = $this->getUserFcmToken($userId);

        if (!$fcmToken) {
            throw new Exception('FCM token not found');
        }

        $message = CloudMessage::withTarget('token', $fcmToken)
            ->withNotification([
                'title' => $title,
                'body' => $body,
            ])
            ->withData([
                'userId' => $userId,
                'type' => 'message'
            ]);

        return $this->messaging->send($message);
    }
}

Broadcast Notifications (Topics)

Send to all users in a single API call.

// Subscribe to topic when registering token
public function registerToken($userId, $fcmToken) {
    $this->saveUserToken($userId, $fcmToken);
    $this->messaging->subscribeToTopic('all_users', [$fcmToken]);
}

// Send broadcast notification
public function sendToAllUsers($title, $body) {
    $message = CloudMessage::withTarget('topic', 'all_users')
        ->withNotification([
            'title' => $title,
            'body' => $body
        ]);

    return $this->messaging->send($message);
}

Android Implementation

Firebase Console Setup

  1. Create a project in the Firebase Console
  2. Download google-services.json and place it in app/

Gradle Configuration

// app/build.gradle
dependencies {
    implementation 'com.google.firebase:firebase-messaging:23.0.0'
}

MainActivity Implementation

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupWebView()
    }

    // JavaScript Interface called from the web side
    @JavascriptInterface
    fun registerUser(userId: String) {
        FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val fcmToken = task.result

                // Send to server
                sendToServer(userId, fcmToken)

                // Subscribe to topic for broadcast notifications
                FirebaseMessaging.getInstance().subscribeToTopic("all_users")
            }
        }
    }

    private fun sendToServer(userId: String, fcmToken: String) {
        // HTTP POST to server (using OkHttp or similar)
    }

    private fun setupWebView() {
        webView.settings.javaScriptEnabled = true
        webView.addJavascriptInterface(this, "Android")
        webView.loadUrl("https://yourwebapp.com")
    }
}

Calling from the Web Side

// Notify the app when user registration is complete
if (window.Android) {
    window.Android.registerUser(userId);
}

Things to Watch Out For

  • Token refresh: FCM tokens are periodically refreshed, so implement a refresh handler
  • Native implementation recommended: FCM via WebView has limitations; implementing FCM on the native side is more reliable
  • Request permission: You need to request push notification permission from the user
  • Topic name format: Must match /topics/[a-zA-Z0-9-_.~%]+
  • Topic limit: Up to 20 million topics per app

Rough Time Estimates

TaskTime
Create project in Firebase Console5 min
Download google-services.json1 min
Gradle configuration2 min
Code implementation30 min
Total~1 hour

Basic push notifications can be implemented in about an hour.