如何使用php与FCM HTTP v1 API

15

我以前使用过FCM的旧协议,但是找不到任何关于如何在php中使用新的FCM HTTP v1 API的具体文档。

我已成功将Google API Client Library导入到我的项目中,但是找不到有关如何获取FCM消息所需范围的访问令牌的文档或教程。


我不知道你现在的情况如何,因为你没有编码。如果要通过 FCM 发送消息,你需要在 Firebase 控制台中的项目配置中拥有 API 密钥。另外,我在一个仓库中留下了一个使用 Firebase 发送通知的表单,你可以查看一下,看看是否有帮助。REPOSITORY - Carlos Quintero
3
@CarlosQuintero 我看了你的代码,你正在使用旧的遗留方式发送 fcm 请求,而我已经掌握了这种方式,我想知道如何使用 PHP 编写新的 HTTP v1 API。 - Jude Fernandes
请查看此代码库 - Carlos Quintero
@CarlosQuintero 谢谢,看起来应该会有帮助,我会尝试一下并在完成后将您的答案标记为正确答案。 - Jude Fernandes
4个回答

14
也许有点晚了,但以下是如何检索 oath 令牌以与 FCM HTTP v1 API 一起使用的方法。
  • 下载Google 库以在您的 php 代码中使用。
  • Firebase 控制台生成并下载新的私钥。
  • 将此密钥以 json 格式存储在服务器上的安全位置。

如何使用您的私钥配置 Google 客户端

public function configureClient()
{
    $client = new Google_Client();
    try {
        $client->setAuthConfig("include_your_private_json_key_path_here");
        $client->addScope(Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM);

        // retrieve the saved oauth token if it exists, you can save it on your database or in a secure place on your server
        $savedTokenJson = $this->readFile();

        if ($savedTokenJson != null) {
            // the token exists, set it to the client and check if it's still valid
            $client->setAccessToken($savedTokenJson);
            if ($client->isAccessTokenExpired()) {
                // the token is expired, generate a new token and set it to the client
                $accessToken = $this->generateToken($client);
                $client->setAccessToken($accessToken);
            }
        } else {
            // the token doesn't exist, generate a new token and set it to the client
            $accessToken = $this->generateToken($client);
            $client->setAccessToken($accessToken);
        }

        $oauthToken = $accessToken["access_token"];

        // the client is configured, now you can send the push notification using the $oauthToken.

    } catch (Google_Exception $e) {
        // handle exception
    }
}

如何请求新的OAuth令牌

private function generateToken($client)
{
    $client->fetchAccessTokenWithAssertion();
    $accessToken = $client->getAccessToken();

    // save the oauth token json on your database or in a secure place on your server
    $tokenJson = json_encode($accessToken);
    $this->saveFile($tokenJson);

    return $accessToken;
}

请注意,saveFile()readFile()方法应根据您的喜好实现以存储和检索oath token json。按照迁移指南中的有效负载结构操作。

3
如果您只是想向应用程序发送通知,请使用此方法。使用Laravel库将会是一个过度的操作,而这种方法更加容易使用。 - magicianiam
你好,你能解释一下 Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM 是什么吗? - Rifki Maulana
@RifkiMaulana 这定义了 Google 客户端的范围。要发送推送通知,这个范围就足够了:Google_Service_FirebaseCloudMessaging::FIREBASE_MESSAGING - lubilis

7

2023年7月更新

批量消息端点已被弃用,并将于2024年7月移除。建议通过迭代令牌使用标准的v1 API发送方法:https://firebase.google.com/docs/cloud-messaging/send-message#send-a-batch-of-messages

以下是向单个设备发送通知的示例:

<?php


require_once '<Path_to_google-api-php-client>/vendor/autoload.php'; 


function getOATHToken()
{
    $client = new Google_Client();
    try {
        $client->setAuthConfig("<path_to_your_private_json_key.json>");
        $client->addScope(Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM);

        $savedTokenJson = readSavedToken();

        if ($savedTokenJson) {
            // the token exists, set it to the client and check if it's still valid
            $client->setAccessToken($savedTokenJson);
            $accessToken = $savedTokenJson;
            if ($client->isAccessTokenExpired()) {
                // the token is expired, generate a new token and set it to the client
                $accessToken = generateToken($client);
                $client->setAccessToken($accessToken);
            }
        } else {
            // the token doesn't exist, generate a new token and set it to the client
            $accessToken = generateToken($client);
            $client->setAccessToken($accessToken);
        }
        

        $oauthToken = $accessToken["access_token"];

        return $oauthToken;

        
    } catch (Google_Exception $e) {}
   return false;
}

//Using a simple file to cache and read the toke, can store it in a databse also
function readSavedToken() {
  $tk = @file_get_contents('token.cache');
  if ($tk) return json_decode($tk, true); else return false;
}
function writeToken($tk) {
 file_put_contents("token.cache",$tk);
}

function generateToken($client)
{
    $client->fetchAccessTokenWithAssertion();
    $accessToken = $client->getAccessToken();

    $tokenJson = json_encode($accessToken);
    writeToken($tokenJson);

    return $accessToken;
}


// Finally
function sendNotification($token, $title, $body, $accessToken) {

    $payload = ["message" => ["token" => $token, "notification"=>["title" => $title, "body"=> $body]]];

    $postdata = json_encode($payload);
    
    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-Type: application/json' . "\r\nAuthorization: Bearer $accessToken",
            'content' => $postdata
        )
    );

    $context  = stream_context_create($opts);

    $result = file_get_contents('https://fcm.googleapis.com/v1/projects/<your_firebase_project_id>/messages:send', false, $context);

    echo "\n\n======RESPONSE======\n\n";
    echo $result;

}

$token = "token-1"; //FCM Device token

$title = "Test from PHP";
$body = "This is a test from PHP";

sendNotification($token, $title, $body, getOATHToken());

?>

批量发送示例(现已弃用)

以下是使用Google API PHP Client和FCM HTTP v1 api的完整示例,演示如何向多个令牌发送推送通知,具体步骤请参考FCM文档

(修改自lubilis在上面的回答中提到的内容

<?php


require_once '<Path_to_google-api-php-client>/vendor/autoload.php'; 


function getOATHToken()
{
    $client = new Google_Client();
    try {
        $client->setAuthConfig("<path_to_your_private_json_key.json>");
        $client->addScope(Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM);

        $savedTokenJson = readSavedToken();

        if ($savedTokenJson) {
            // the token exists, set it to the client and check if it's still valid
            $client->setAccessToken($savedTokenJson);
            $accessToken = $savedTokenJson;
            if ($client->isAccessTokenExpired()) {
                // the token is expired, generate a new token and set it to the client
                $accessToken = generateToken($client);
                $client->setAccessToken($accessToken);
            }
        } else {
            // the token doesn't exist, generate a new token and set it to the client
            $accessToken = generateToken($client);
            $client->setAccessToken($accessToken);
        }
        

        $oauthToken = $accessToken["access_token"];

        return $oauthToken;

        
    } catch (Google_Exception $e) {}
   return false;
}

//Using a simple file to cache and read the toke, can store it in a databse also
function readSavedToken() {
  $tk = @file_get_contents('token.cache');
  if ($tk) return json_decode($tk, true); else return false;
}
function writeToken($tk) {
 file_put_contents("token.cache",$tk);
}

function generateToken($client)
{
    $client->fetchAccessTokenWithAssertion();
    $accessToken = $client->getAccessToken();

    $tokenJson = json_encode($accessToken);
    writeToken($tokenJson);

    return $accessToken;
}


// Finally
function sendNotification($tokens, $title, $body, $accessToken) {

    $boundary = "--subrequest_boundary";
    $multiPayload = $boundary;

    foreach ($tokens as $token) {
        $head = "Content-Type: application/http\r\n".
                "Content-Transfer-Encoding: binary\r\n\r\n".
                "POST /v1/projects/<your_firebase_project_name>/messages:send\r\n".
                "Content-Type: application/json\r\n".
                "accept: application/json\r\n\r\n";
        
        $payload = ["message" => ["token" => $token, "notification"=>["title" => $title, "body"=> $body]]];

        $postdata = json_encode($payload);
        $multiPayload .= "\r\n".$head.$postdata."\r\n".$boundary;
        
    }
    
    $multiPayload .= "--";
    

    //Uncomment for debugging
    //echo "\n\n==== POST DATA====\n\n";
    //echo $multiPayload;


    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-Type: multipart/mixed; boundary="subrequest_boundary"' . "\r\nAuthorization: Bearer $accessToken",
            'content' => $multiPayload
        )
    );

    //Uncomment for debugging
    //echo "\n\n==== HTTP OPTIONS====\n\n";
    //var_dump($opts);

    $context  = stream_context_create($opts);


    // This is the path for sending push multiple tokens (upto 500 as per the docs)
    $result = file_get_contents('https://fcm.googleapis.com/batch', false, $context);

    echo "\n\n======RESPONSE======\n\n";
    echo $result;

}

$tokens = ["token-1","token-2"]; //FCM Device tokens as array

$title = "Test from PHP";
$body = "This is a test from PHP";

sendNotification($tokens, $title, $body, getOATHToken());

?>

1
我点赞了,因为这提供了完整的解决方案。 - Nana Ghartey

6

1
它目前还不支持,平台配置将在未来的版本中推出 - 我应该更清楚地表达 :) - jeromegamez
期待它,你是这个库的作者吗? - Jude Fernandes
1
是的 :)。当我引用它时,我通常会写这个,只是我忘记的另一件事。 - jeromegamez
酷,关于那些新功能有何预计时间? - Jude Fernandes
1
我在寻找其他内容时偶然发现了这个,想告诉你FCM现已在PHP SDK中完全实现 \o/ - jeromegamez
显示剩余2条评论

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接