Skip to content

Dostonlv/go-fcm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoFCM: Smart Firebase Cloud Messaging Wrapper

GoFCM is a production-ready, opinionated wrapper for the official Firebase Admin SDK (v4).

It is designed specifically for Cross-Platform Mobile Apps (Flutter, React Native) to solve the common "Double Notification" issue on Android while guaranteeing delivery on iOS.

🚀 Why use GoFCM?

If you send a standard Notification payload to a Flutter app, Android devices often display the notification twice: once from the System Tray and once from the App's local notification plugin.

GoFCM automatically handles this complexity:

Feature Standard Firebase SDK GoFCM (This Library)
Android Strategy Sends Notification (Causes Duplicates) Sends Data-Only (High Priority)
iOS Strategy Sends Notification Sends APNS Alert (Guarantees Delivery)
Data Mirroring Manual Automatic (Title/Body copied to Data)
Batch Sending Manual implementation Automatic Batching (500 tokens/req)
Bad Token Handling Manual cleanup Built-in Callback Handler

📦 Installation

go get github.com/Dostonlv/go-fcm

⚡ Quick Start

package main

import (
    "context"
    "log"
    "[github.com/your-username/gofcm](https://github.com/your-username/gofcm)"
)

func main() {
    ctx := context.Background()

    // 1. Initialize Client
    client, err := gofcm.New(ctx,
        gofcm.WithCredentialsFile("./serviceAccountKey.json"),
    )
    if err != nil {
        log.Fatal(err)
    }

    // 2. Create Message
    // You don't need to worry about platform specifics; the library handles it.
    msg := gofcm.Message{
        Title: "Order Updated 📦",
        Body:  "Your order #1234 is now shipping!",
        Data:  map[string]string{
            "order_id": "1234",
            "type":     "status_update",
        },
        Android: &gofcm.AndroidConfig{
            ChannelID: "orders_channel", // Required for Android 8+
        },
    }

    // 3. Send to Tokens
    tokens := []string{"fcm_token_1", "fcm_token_2"}
    
    err = client.Send(ctx, tokens, msg, func(badToken string) {
        // Callback for cleaning up invalid tokens
        log.Printf("Removing invalid token from DB: %s", badToken)
    })

    if err != nil {
        log.Printf("Error sending batch: %v", err)
    }
}

⚙️ Configuration & Options

GoFCM uses the Functional Options Pattern for flexible configuration.

1. Credentials

You can load credentials from a file path or a raw JSON byte slice (useful for environment variables in Docker/Kubernetes).

// Option A: From File (Standard)
gofcm.New(ctx, gofcm.WithCredentialsFile("path/to/key.json"))

// Option B: From JSON Bytes (Secure/Env Vars)
jsonKey := []byte(os.Getenv("FIREBASE_CREDENTIALS"))
gofcm.New(ctx, gofcm.WithCredentialsJSON(jsonKey))

2. Custom Logging (Zap, Logrus, etc.)

By default, GoFCM uses the standard log package. In production, you likely use a structured logger. You can inject any logger that satisfies the simple Logger interface.

Interface Definition:

type Logger interface {
    Printf(format string, v ...interface{})
}
// 1. Define an adapter
type ZapAdapter struct {
    Sugar *zap.SugaredLogger
}

func (z *ZapAdapter) Printf(format string, v ...interface{}) {
    z.Sugar.Infof(format, v...) // Redirect internal logs to Zap
}

// 2. Pass it to the client
func main() {
    logger, _ := zap.NewProduction()
    sugar := logger.Sugar()

    client, _ := gofcm.New(ctx,
        gofcm.WithCredentialsFile("key.json"),
        gofcm.WithLogger(&ZapAdapter{Sugar: sugar}),
    )
}

🌍 Regional Restrictions (Proxy)

If your server is located in Russia (Timeweb, Reg.ru, etc.), Google APIs are typically blocked. You must use a proxy from another region (e.g., Germany, Netherlands, or USA).

Why WithHTTP2Proxy?

  • Multiplexing: Sends multiple notifications over a single connection even through the proxy.
  • Smart Fallback: Automatically switches to HTTP/1.1 if the proxy doesn't support HTTP/2.

Basic Usage:

client, err := gofcm.New(ctx,
    gofcm.WithCredentialsFile("key.json"),
    // Format: http://user:password@ip:port
    gofcm.WithHTTP2Proxy("http://myuser:mypass@1.2.3.4:8080"),
)

# Example: load proxy from .env
proxy := os.Getenv("FCM_PROXY_URL") 

client, err := gofcm.New(ctx,
    gofcm.WithCredentialsFile("key.json"),
    gofcm.WithHTTP2Proxy(proxy),
)

📬 Topic Messaging (Pub/Sub)

Topic messaging allows you to broadcast a single message to a large number of devices that have opted into a specific interest group without needing to manage a list of individual tokens on your server.

// 1. Subscribe a list of tokens to a topic
// Note: Firebase supports up to 1000 tokens per single subscription call.
tokens := []string{"token_123", "token_456"}
err := client.SubscribeToTopic(ctx, tokens, "news_updates")

// 2. Broadcast a message to the entire topic
// The Hybrid Strategy applies here as well (Data-only for Android, Alert for iOS).
msg := gofcm.Message{
    Title: "Breaking News 🚨",
    Body:  "Something important happened!",
    Android: &gofcm.AndroidConfig{
        Priority: gofcm.DeliveryHigh,
    },
}

err = client.SendToTopic(ctx, "news_updates", msg)

// 3. Unsubscribe tokens from a topic
client.UnsubscribeFromTopic(ctx, []string{"token_123"}, "news_updates")

About

GoFCM: Simplified Firebase Cloud Messaging for Go.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages