Przejście ze starszych interfejsów API FCM na HTTP v1

Aplikacje korzystające ze starszych interfejsów API FCM dla HTTP i XMPP powinny jak najszybciej przejść na interfejs HTTP w wersji 1. Wysyłanie wiadomości (w tym wiadomości przesyłanych dalej) za pomocą tych interfejsów API zostało wycofane 20 czerwca 2023 r., a wyłączenie rozpocznie się 22 lipca 2024 r..

Dowiedz się więcej o funkcjach, na które ma wpływ ta zmiana.

Oprócz ciągłego wsparcia i nowych funkcji interfejs HTTP v1 ma te zalety w porównaniu ze starszymi interfejsami API:

  • Lepsze zabezpieczenia dzięki tokenom dostępu Interfejs API HTTP w wersji 1 używa krótkotrwałych tokenów dostępu zgodnie z modelem zabezpieczeń OAuth 2. Jeśli token dostępu stanie się publiczny, może być użyty do celów szkodliwych tylko przez około godzinę przed wygaśnięciem. Tokeny odświeżania nie są przesyłane tak często jak klucze bezpieczeństwa używane w starszych wersjach interfejsu API, więc jest znacznie mniej prawdopodobne, że zostaną przechwycone.

  • Bardziej wydajne dostosowywanie wiadomości na różnych platformach W przypadku treści wiadomości interfejs HTTP w wersji 1 zawiera wspólne klucze, które są wysyłane do wszystkich docelowych instancji, oraz klucze specyficzne dla platformy, które umożliwiają dostosowywanie wiadomości na różnych platformach. Dzięki temu możesz tworzyć „zastąpienia”, które wysyłają nieco inne ładunki do różnych platform klienta w ramach jednej wiadomości.

  • Większa możliwość rozbudowy i przygotowanie na przyszłość w przypadku nowych wersji platformy klienta – interfejs HTTP w wersji 1 w pełni obsługuje opcje przesyłania wiadomości dostępne na platformach Apple, Android i w internecie. Każda platforma ma własny blok zdefiniowany w danych JSON, więc FCM może w razie potrzeby rozszerzać interfejs API o nowe wersje i nowe platformy.

Aktualizowanie punktu końcowego serwera

Adres URL punktu końcowego interfejsu HTTP w wersji 1 różni się od starszego punktu końcowego w tych aspektach:

  • Jest ona zweryfikowana i ma w ścieżce /v1.
  • Ścieżka zawiera identyfikator projektu Firebase Twojej aplikacji w formacie /projects/myproject-ID/. Ten identyfikator jest dostępny na karcie Ogólne ustawienia projektu w konsoli Firebase.
  • Wyraźnie określa metodę send jako :send.

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

Żądania HTTP przed

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

Żądania XMPP przed

Starsze wiadomości XMPP są wysyłane przez połączenie do tego 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 znaków klucza serwera używanego w starszych żądaniach żądania wysyłane w ramach HTTP w wersji 1 wymagają tokena dostępu OAuth 2.0. Jeśli do wysyłania wiadomości używasz pakietu Admin SDK, biblioteka sama poradzi sobie z tokenem. Jeśli używasz protokołu nieprzetworzonego, 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;
  • Ograniczony czasowo token dostępu OAuth 2.0 utworzony na podstawie konta usługi

Jeśli aplikacja działa w usłudze Compute Engine, Google Kubernetes Engine, App Engine lub Cloud Functions (w tym Cloud Functions for Firebase), użyj domyślnych poświadczeń aplikacji (ADC). ADC używa istniejącego domyślnego konta usługi do uzyskiwania danych logowania na potrzeby autoryzacji żądań. Pozwala też na elastyczne testowanie lokalne za pomocą zmiennej środowiskowej GOOGLE_APPLICATION_CREDENTIALS. Aby w pełni zautomatyzować proces autoryzacji, użyj ADC razem z bibliotekami serwera Admin SDK.

Jeśli aplikacja działa w środowisku serwera spoza Google, musisz pobrać plik JSON konta usługi z Twojego projektu Firebase. Jeśli masz dostęp do systemu plików zawierającego plik klucza prywatnego, możesz użyć zmiennej środowiskowej GOOGLE_APPLICATION_CREDENTIALS, aby autoryzować żądania za pomocą tych danych logowania uzyskanych ręcznie. Jeśli nie masz dostępu do takich plików, musisz w kodze odwoływać się do pliku konta usługi. Należy to robić bardzo ostrożnie, ponieważ istnieje ryzyko ujawnienia danych logowania.

Podawanie danych logowania za pomocą ADC

Domyślne uwierzytelnianie aplikacji Google (ADC) sprawdza Twoje poświadczenia w takim porządku:

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

  2. Jeśli zmienna środowiskowa nie jest ustawiona, ADC używa domyślnego konta usługi, które Compute Engine, Google Kubernetes Engine, App Engine i Cloud Functions udostępniają aplikacjom działającym w tych usługach.

  3. Jeśli ADC nie może użyć żadnego z tych danych logowania, system wyświetla błąd.

Przykładowy kod pakietu Admin SDK ilustruje tę strategię. Przykład nie zawiera wyraźnego określenia danych logowania aplikacji. Jednak ADC może znaleźć te dane logowania w sposób domyślny, o ile zmienna środowiskowa jest ustawiona lub aplikacja działa w kontekście Compute Engine, Google Kubernetes Engine, App Engine lub funkcji Cloud.

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(),
});

Ręczne podawanie danych logowania

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 z zaufanego środowiska. Jeśli kod tworzysz lokalnie lub wdrażasz aplikację lokalnie, możesz użyć danych logowania uzyskanych za pomocą tego konta usługi, aby autoryzować żądania serwera.

Aby uwierzytelnić konto usługi i zezwolić mu na dostęp 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 możliwości przekazania danych logowania do aplikacji. Możesz ustawić zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS lub w kodzie wyraźnie podać ścieżkę do klucza konta usługi. Pierwsza opcja jest bezpieczniejsza i zdecydowanie zalecana.

Aby ustawić zmienną środowiskową:

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

Linux lub macOS

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

Windows

W PowerShell:

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

Po wykonaniu powyższych czynności aplikacja może domyślnie określać Twoje dane logowania, co pozwala używać danych logowania konta usługi podczas testowania lub uruchamiania w środowiskach innych niż Google.

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

Aby pobrać krótkotrwały token dostępu OAuth 2.0, użyj danych logowania Firebase wraz z biblioteką Google Auth Library w preferowanym języku:

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 Google API uwierzytelnia żądanie za pomocą tokena sieciowego JSON (JWT). Więcej informacji znajdziesz w artykule Tokeny sieciowe 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();
}

Gdy token dostępu wygaśnie, metoda odświeżania tokena zostanie wywołana automatycznie, aby pobrać zaktualizowany token 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 przesyłanych żądań

W wersji 1 interfejsu FCM HTTP wprowadzono istotną zmianę w strukturze danych ładunku wiadomości JSON. Te zmiany mają na celu przede wszystkim zapewnienie prawidłowego obsługiwania wiadomości otrzymywanych na różnych platformach klientów. Dodatkowo dają Ci większą elastyczność w dostosowywaniu pól wiadomości lub ich „zastępowaniu” na poszczególnych platformach.

Oprócz zapoznania się z przykładami w tej sekcji przeczytaj też artykuł Dostosowywanie wiadomości na różnych platformach i przeczytaj dokumentację interfejsu API, aby poznać interfejs HTTP v1.

Przykład: prosty komunikat powiadomienia

Oto porównanie bardzo prostego ładunku powiadomienia zawierającego tylko pola title, bodydata, które pokazuje podstawowe różnice między starszym ładunkiem a ładunkiem 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 starszego interfejsu API wiadomości interfejs HTTP w wersji 1 nie obsługuje zagnieżdżonych wartości JSON w polu data. Wymagane jest przekształcenie z formatu 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 umożliwić kierowanie na wiele platform, starszy interfejs API wykonywał zastąpienia w backendzie. W przeciwieństwie do tego HTTP w wersji 1 udostępnia bloki kluczy dla poszczególnych platform, dzięki czemu wszelkie różnice między platformami są wyraźne i widoczne dla dewelopera. Dzięki temu możesz kierować reklamy na wiele platform za pomocą jednego żądania, 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

Oprócz uproszczenia kierowania wiadomości na różne platformy interfejs HTTP w wersji 1 zapewnia też 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 kierować reklamy na określone urządzenia za pomocą interfejsu HTTP w wersji 1, zamiast klucza to podaj w kluczu token bieżący token rejestracji urządzenia.

Przed

  { "notification": {
      "body": "This is an FCM notification message!",
      "title": "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: