Migracja ze starszych interfejsów API FCM na HTTP w wersji 1

W przypadku aplikacji wykorzystujących wycofane starsze interfejsy API FCM dla HTTP i XMPP należy jak najszybciej przejść na interfejs HTTP v1 API. Wysyłanie wiadomości (w tym wiadomości nadrzędnych) za pomocą tych interfejsów API zostało wycofane 20 czerwca 2023 r., a wyłączanie rozpocznie się 22 lipca 2024 r.

Dowiedz się więcej o konkretnych funkcjach, których dotyczy problem.

Oprócz zapewniania stałego wsparcia i nowych funkcji interfejs HTTP w wersji 1 ma te zalety w porównaniu ze starszymi interfejsami:

  • Większe bezpieczeństwo dzięki tokenom dostępu Interfejs HTTP w wersji 1 używa tokenów dostępu o krótkim czasie ważności zgodnie z modelem zabezpieczeń OAuth2. Jeśli token dostępu stanie się publiczny, można go złośliwie użyć tylko przez około godzinę, zanim wygaśnie. Tokeny odświeżania nie są przesyłane tak często jak klucze bezpieczeństwa używane w starszym interfejsie API, więc prawdopodobieństwo ich przechwycenia jest mniejsze.

  • Bardziej efektywne dostosowywanie wiadomości na różnych platformach W przypadku treści wiadomości interfejs API HTTP w wersji 1 ma wspólne klucze, które kierują do wszystkich docelowych instancji, oraz klucze specyficzne dla platformy, które umożliwiają dostosowywanie wiadomości na różnych platformach. Pozwala to tworzyć „nadpisania”, które wysyłają nieco inne ładunki do różnych platform klientów w jednej wiadomości.

  • Większa możliwość rozbudowy i przyszłości na potrzeby nowych wersji platform klienckich Interfejs HTTP v1 API w pełni obsługuje opcje przesyłania wiadomości dostępne na platformach Apple oraz w przeglądarkach i na urządzeniach z Androidem. Ponieważ każda platforma ma własny zdefiniowany blok w ładunku JSON, FCM może w razie potrzeby rozszerzyć interfejs API na nowe wersje i platformy.

Zaktualizuj punkt końcowy serwera

Adres URL punktu końcowego interfejsu API HTTP w wersji 1 różni się od starszego punktu końcowego w następujący sposób:

  • Ma ona różne wersje, a w ścieżce znajduje się /v1.
  • Ścieżka zawiera identyfikator projektu Firebase dla aplikacji w formacie /projects/myproject-ID/. Ten identyfikator jest dostępny na karcie Ogólne ustawienia projektu w konsoli Firebase.
  • Jednoznacznie określa metodę send jako :send.

Aby zaktualizować punkt końcowy serwera dla HTTP w wersji 1, dodaj te elementy do punktu końcowego w nagłówku żądań wysyłanych.

Żądania HTTP przed

POST https://fcm.googleapis.com/fcm/send

Żądania XMPP przed

Starsze komunikaty XMPP są wysyłane przez połączenie do następującego punktu końcowego:

fcm-xmpp.googleapis.com:5235

Po

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send

Aktualizacja autoryzacji żądań wysyłania

Zamiast ciągu klucza serwera używanego w starszych żądaniach żądania wysyłania HTTP w wersji 1 wymagają tokena dostępu OAuth 2.0. Jeśli do wysyłania wiadomości używasz pakietu Admin SDK, biblioteka zajmuje się tokenem za Ciebie. Jeśli używasz nieprzetworzonego protokołu, uzyskaj token w sposób opisany w tej sekcji i dodaj go do nagłówka jako Authorization: Bearer <valid Oauth 2.0 token>.

Przed

Authorization: key=AIzaSyZ-1u...0GBYzPu7Udno5aA

Po

Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA

W zależności od szczegółów środowiska serwera użyj kombinacji tych strategii, aby autoryzować żądania serwera do usług Firebase:

  • Domyślne uwierzytelnianie aplikacji Google (ADC)
  • Plik JSON konta usługi
  • Krótkotrwały token dostępu OAuth 2.0 pozyskany z konta usługi

Jeśli Twoja aplikacja działa w Compute Engine, Google Kubernetes Engine, App Engine lub Cloud Functions (w tym Cloud Functions dla Firebase), użyj domyślnego uwierzytelniania aplikacji (ADC). ADC używa Twojego obecnego domyślnego konta usługi do uzyskiwania danych logowania do autoryzowania żądań, a ADC umożliwia elastyczne testowanie lokalne za pomocą zmiennej środowiskowej GOOGLE_APPLICATION_CREDENTIALS. Aby w pełni zautomatyzować proces autoryzacji, używaj ADC razem z bibliotekami serwera pakietu Admin SDK.

Jeśli Twoja aplikacja działa w środowisku serwera innym niż Google, musisz pobrać plik JSON konta usługi ze swojego projektu Firebase. Jeśli masz dostęp do systemu plików zawierającego plik klucza prywatnego, możesz używać zmiennej środowiskowej GOOGLE_APPLICATION_CREDENTIALS do autoryzowania żądań z użyciem tych danych uzyskanych ręcznie. Jeśli nie masz takiego dostępu, musisz odwołać się do pliku konta usługi w swoim kodzie. Należy to robić z dużą ostrożnością ze względu na ryzyko ujawnienia danych logowania.

Podaj dane logowania za pomocą ADC

Funkcja domyślnego uwierzytelniania aplikacji Google (ADC) sprawdza Twoje dane logowania w tej kolejności:

  1. ADC sprawdza, czy zmienna środowiskowa GOOGLE_APPLICATION_CREDENTIALS jest ustawiona. Jeśli zmienna jest ustawiona, ADC używa pliku konta usługi, na który wskazuje zmienna.

  2. Jeśli zmienna środowiskowa nie jest ustawiona, ADC używa domyślnego konta usługi udostępnianego przez Compute Engine, Google Kubernetes Engine, App Engine i Cloud Functions dla aplikacji działających w tych usługach.

  3. Jeśli ADC nie może użyć tych danych, system zgłasza błąd.

Poniższy przykładowy kod pakietu Admin SDK ilustruje tę strategię. W przykładzie nie określono bezpośrednio danych logowania do aplikacji. ADC może jednak domyślnie znajdować dane logowania, o ile skonfigurowana jest zmienna środowiskowa lub aplikacja działa w Compute Engine, Google Kubernetes Engine, App Engine lub Cloud Functions.

Node.js

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
});

Java

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
    .build();

FirebaseApp.initializeApp(options);

Python

default_app = firebase_admin.initialize_app()

Go

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
});

Podaj dane logowania ręcznie

Projekty Firebase obsługują konta usługi Google, których możesz używać do wywoływania interfejsów API serwera Firebase z serwera aplikacji lub zaufanego środowiska. Jeśli programujesz kod lokalnie lub wdrażasz aplikację lokalnie, możesz autoryzować żądania do serwera za pomocą danych logowania uzyskanych z tego konta usługi.

Aby uwierzytelnić konto usługi i autoryzować je do dostępu do usług Firebase, musisz wygenerować plik klucza prywatnego w formacie JSON.

Aby wygenerować plik klucza prywatnego dla konta usługi:

  1. W konsoli Firebase otwórz Ustawienia > Konta usługi.

  2. Kliknij Wygeneruj nowy klucz prywatny, a następnie potwierdź, klikając Wygeneruj klucz.

  3. Bezpiecznie przechowuj plik JSON zawierający klucz.

Podczas autoryzacji za pomocą konta usługi masz 2 opcje udostępniania danych logowania do aplikacji. Możesz ustawić zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS lub bezpośrednio przekazać ścieżkę do klucza konta usługi w kodzie. Pierwsza opcja jest bezpieczniejsza i zdecydowanie zalecana.

Aby ustawić zmienną środowiskową:

Ustaw zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS na ścieżkę pliku JSON zawierającego klucz konta usługi. Ta zmienna ma zastosowanie tylko do bieżącej sesji powłoki, więc jeśli otworzysz nową sesję, ustaw ją ponownie.

Linux lub macOS

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

Windows

Za pomocą PowerShell:

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

Gdy wykonasz powyższe czynności, domyślne dane uwierzytelniające aplikacji (ADC) będą mogły niejawnie określić Twoje dane logowania. Dzięki temu możesz używać danych logowania do konta usługi podczas testowania lub uruchamiania aplikacji w środowiskach innych niż Google.

Używanie danych logowania do tworzenia tokenów dostępu

Użyj danych logowania Firebase w połączeniu z biblioteką uwierzytelniania Google w wybranym języku, aby pobrać token dostępu OAuth 2.0 o krótkim czasie ważności:

Node.js

 function getAccessToken() {
  return new Promise(function(resolve, reject) {
    const key = require('../placeholders/service-account.json');
    const jwtClient = new google.auth.JWT(
      key.client_email,
      null,
      key.private_key,
      SCOPES,
      null
    );
    jwtClient.authorize(function(err, tokens) {
      if (err) {
        reject(err);
        return;
      }
      resolve(tokens.access_token);
    });
  });
}

W tym przykładzie biblioteka klienta interfejsu API Google uwierzytelnia żądanie za pomocą tokena sieciowego JSON (JWT). Więcej informacji znajdziesz w artykule o tokenach sieciowych JSON.

Python

def _get_access_token():
  """Retrieve a valid access token that can be used to authorize requests.

  :return: Access token.
  """
  credentials = service_account.Credentials.from_service_account_file(
    'service-account.json', scopes=SCOPES)
  request = google.auth.transport.requests.Request()
  credentials.refresh(request)
  return credentials.token

Java

private static String getAccessToken() throws IOException {
  GoogleCredentials googleCredentials = GoogleCredentials
          .fromStream(new FileInputStream("service-account.json"))
          .createScoped(Arrays.asList(SCOPES));
  googleCredentials.refresh();
  return googleCredentials.getAccessToken().getTokenValue();
}

Po wygaśnięciu tokena dostępu metoda odświeżania tokena jest wywoływana automatycznie w celu pobrania zaktualizowanego tokena dostępu.

Aby autoryzować dostęp do FCM, poproś o zakres https://www.googleapis.com/auth/firebase.messaging.

Aby dodać token dostępu do nagłówka żądania HTTP:

Dodaj token jako wartość nagłówka Authorization w formacie Authorization: Bearer <access_token>:

Node.js

headers: {
  'Authorization': 'Bearer ' + accessToken
}

Python

headers = {
  'Authorization': 'Bearer ' + _get_access_token(),
  'Content-Type': 'application/json; UTF-8',
}

Java

URL url = new URL(BASE_URL + FCM_SEND_ENDPOINT);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Bearer " + getServiceAccountAccessToken());
httpURLConnection.setRequestProperty("Content-Type", "application/json; UTF-8");
return httpURLConnection;

Aktualizowanie ładunku żądań wysyłania

FCM HTTP w wersji 1 wprowadza istotną zmianę w strukturze ładunku wiadomości JSON. Przede wszystkim mają pewność, że wiadomości są obsługiwane prawidłowo, gdy są odbierane z różnych platform klienckich. Dodatkowo zmiany dają Ci dodatkową elastyczność w dostosowywaniu, czyli „zastępowaniu” pól wiadomości na poszczególnych platformach.

Zapoznaj się z przykładami podanymi w tej sekcji, zapoznając się z artykułem Dostosowywanie wiadomości na różnych platformach oraz dokumentacją interfejsu API, aby zapoznać się z HTTP w wersji 1.

Przykład: prosta wiadomość z powiadomieniem

Oto porównanie bardzo prostego ładunku powiadomień – zawierającego tylko pola title, body i data – prezentuje podstawowe różnice w ładunkach starszych i HTTP w wersji 1.

Przed

{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available."
  },
  "data": {
    "story_id": "story_12345"
  }
}

Po

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    }
  }
}

Przykład: zagnieżdżone dane JSON

W przeciwieństwie do starszej wersji interfejsu API do przesyłania wiadomości interfejs API HTTP w wersji 1 nie obsługuje zagnieżdżonych wartości JSON w polu data. Wymagana jest konwersja z JSON na ciąg znaków.

Przed

{
  ...
  "data": {
    "keysandvalues": {"key1": "value1", "key2": 123}
  }
}

Po

{
  "message": {
   ...
    "data": {
      "keysandvalues": "{\"key1\": \"value1\", \"key2\": 123}"
    }
  }
}

Przykład: kierowanie na wiele platform

Aby można było włączyć kierowanie na wiele platform, starsza wersja interfejsu API wprowadziła zastąpienia w backendzie. Protokół HTTP w wersji 1 udostępnia natomiast bloki kluczy właściwe dla danej platformy, które sprawiają, że wszelkie różnice między platformami są w sposób wyraźny i widoczny dla dewelopera. Dzięki temu możesz zawsze kierować 1 żądanie na wiele platform, jak pokazano w tym przykładzie.

Przed

// Android
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "TOP_STORY_ACTIVITY"
  },
  "data": {
    "story_id": "story_12345"
  }
}
// Apple
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "HANDLE_BREAKING_NEWS"
  },
  "data": {
    "story_id": "story_12345"
  }
}

Po

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    },
    "android": {
      "notification": {
        "click_action": "TOP_STORY_ACTIVITY"
      }
    },
    "apns": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

Przykład: dostosowywanie za pomocą zastąpień platformy

Nie tylko upraszcza kierowanie wiadomości na wiele platform, ale też zapewnia elastyczność w dostosowywaniu wiadomości do poszczególnych platform.

Przed

// Android
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "Check out the Top Story.",
    "click_action": "TOP_STORY_ACTIVITY"
  },
  "data": {
    "story_id": "story_12345"
  }
}
// Apple
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "HANDLE_BREAKING_NEWS"
  },
  "data": {
    "story_id": "story_12345"
  }
}

Po

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    },
    "android": {
      "notification": {
        "click_action": "TOP_STORY_ACTIVITY",
        "body": "Check out the Top Story"
      }
    },
    "apns": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

Przykład: kierowanie na określone urządzenia

Aby za pomocą interfejsu API HTTP w wersji 1 kierować reklamy na konkretne urządzenia, podaj w kluczu token aktualny token rejestracji urządzenia zamiast w kluczu to.

Przed

  { "notification": {
      "body": "This is an FCM notification message!",
      "time": "FCM Message"
    },
    "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
  }

Po

{
   "message":{
      "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
      "notification":{
        "body":"This is an FCM notification message!",
        "title":"FCM Message"
      }
   }
}

Więcej przykładów i informacji o interfejsie API FCM HTTP w wersji 1 znajdziesz w tych artykułach: