Laravel Notification Channels FCM (Firebase Cloud Messaging) 初始化專案 laravel new fcm_test
使用 laravel/ui 創建身分認證 使用Laravel Breeze 也可以
composer require laravel/ui
創建 auth php artisan ui bootstrap --auth
npm install
npm run dev
新增 user 欄位,儲存要發送裝置 token php artisan make:migration add_column_device_token_to_users
<?php use Illuminate \Database \Migrations \Migration ;use Illuminate \Database \Schema \Blueprint ;use Illuminate \Support \Facades \Schema ;class AddColumnDeviceTokenToUsers extends Migration { public function up ( ) { Schema::table('users' , function (Blueprint $table ) { $table ->string('device_token' )->nullable(); }); } public function down ( ) { Schema::table('users' , function (Blueprint $table ) { $table ->dropColumn('device_token' ); }); } }
更改 user model 將 device_token 欄位設成可更新
<?php namespace App \Models ;use Illuminate \Contracts \Auth \MustVerifyEmail ;use Illuminate \Database \Eloquent \Factories \HasFactory ;use Illuminate \Foundation \Auth \User as Authenticatable ;use Illuminate \Notifications \Notifiable ;use Laravel \Sanctum \HasApiTokens ;class User extends Authenticatable { use HasApiTokens , HasFactory , Notifiable ; protected $fillable = [ 'name' , 'email' , 'password' , 'device_token' , ]; protected $hidden = [ 'password' , 'remember_token' , ]; protected $casts = [ 'email_verified_at' => 'datetime' , ]; }
遷移 php artisan migrate
安裝 laravel-notification-channels/fcm composer require laravel-notification-channels/fcm:~2.0
申請 Firebase 專案 到firebase
申請專案
點選專案設定
選擇網頁應用
初始化的 SDK
產生 json 檔案
配置 下載服務帳戶 JSON 文件後,您可以通過在.env 文件中指定以 FIREBASE_開頭的環境變量來配置包。通常,包的工作需要以下條件
# 服務帳戶 JSON 文件的相對或完整路徑 FIREBASE_CREDENTIALS= # 您可以在以下位置找到項目的數據庫 URL # https://console.firebase.google.com/project/_/database FIREBASE_DATABASE_URL=https://<your-project>.firebaseio.com
以剛剛創建的專案為例
將 JOSN 檔案放在專案根目錄 \填入專案 ID
.env
檔案配置
FIREBASE_CREDENTIALS=firebase-adminsdk.json FIREBASE_DATABASE_URL=https://laravel-test-974f3.firebaseio.com
配置查看laravel-firebase#configuration
創建通知 php artisan make:notification HelloNotification
每個通知類別都有一個 via 方法用於判別要將通知寄送哪個頻道。
toFcm 會接收一個 $notifiable 實體並且返回一個 NotificationChannels\Fcm\FcmMessage 實例
<?php namespace App \Notifications ;use Illuminate \Notifications \Notification ;use NotificationChannels \Fcm \FcmChannel ;use NotificationChannels \Fcm \FcmMessage ;use NotificationChannels \Fcm \Resources \AndroidConfig ;use NotificationChannels \Fcm \Resources \AndroidFcmOptions ;use NotificationChannels \Fcm \Resources \AndroidNotification ;use NotificationChannels \Fcm \Resources \ApnsConfig ;use NotificationChannels \Fcm \Resources \ApnsFcmOptions ;class HelloNotification extends Notification { public function via ($notifiable ) { return [FcmChannel::class]; } public function toFcm ($notifiable ) { return FcmMessage::create() ->setData(['data1' => 'value' , 'data2' => 'value2' ]) ->setNotification(\NotificationChannels\Fcm\Resources\Notification::create() ->setTitle('你好' ) ->setBody('測試通知.' ) ->setImage('https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Laravel.svg/1200px-Laravel.svg.png' )) ->setAndroid( AndroidConfig::create() ->setFcmOptions(AndroidFcmOptions::create()->setAnalyticsLabel('analytics' )) ->setNotification(AndroidNotification::create()->setColor('#0A0A0A' )) )->setApns( ApnsConfig::create() ->setFcmOptions(ApnsFcmOptions::create()->setAnalyticsLabel('analytics_ios' )) ); } public function fcmProject ($notifiable , $message ) { return 'app' ; } }
創建推播的 controller php artisan make:controller PushController
<?php namespace App \Http \Controllers ;use Illuminate \Http \Request ;use App \Notifications \HelloNotification ;use Illuminate \Support \Facades \Auth ;class PushController extends Controller { public function push ( ) { $user = Auth::user(); $user ->notify(new HelloNotification()); return redirect()->back(); } public function fcmToken (Request $request ) { try { if (Auth::user()->device_token == $request ->token) { return response()->json(['success' => true ], 200 ); } else { Auth::user()->update(['device_token' => $request ->token]); return response()->json(['success' => true ], 200 ); } } catch (\Throwable $th ) { throw $th ; } } }
新增路由 web.php
新增路由
Route::get('/push' , [App\Http\Controllers\PushController::class, 'push' ])->name('push' )->middleware('auth' ); Route::post('/fcm-token' , [App\Http\Controllers\PushController::class, 'fcmToken' ])->name('fcm.token' )->middleware('auth' );
在通知模型中設置一個方法 class User extends Authenticatable { use Notifiable ; .... public function routeNotificationForFcm ( ) { return $this ->device_token; } }
更新home.blade.php
@extends('layouts.app') @section('content') <div class ="container" > <div class ="row justify-content-center" > <div class ="col-md-8" > <div class ="card" > <div class ="card-header" > {{ __('Dashboard') }}</div > <div class ="card-body" > @if (session('status')) <div class ="alert alert-success" role ="alert" > {{ session('status') }} </div > @endif {{ __('You are logged in!') }} <a href ="{{route('push')}}" > 測試通知!</a > </div > </div > </div > </div > </div > <script src ="https://code.jquery.com/jquery-3.6.0.min.js" integrity ="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin ="anonymous" > </script > <script src ="https://www.gstatic.com/firebasejs/8.3.2/firebase.js" > </script > <script > var firebaseConfig = { apiKey : "XXXX" , authDomain : "XXXX.firebaseapp.com" , projectId : "XXXX" , storageBucket : "XXXX" , messagingSenderId : "XXXX" , appId : "XXXX" , }; firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); function notifyMe ( ) { if (!("Notification" in window )) { console .log("This browser does not support desktop notification" ); } else if (Notification.permission === "granted" ) { startFCM(); } else if ( Notification.permission !== "denied" || Notification.permission === "default" ) { Notification.requestPermission(function (permission ) { if (permission === "granted" ) { startFCM(); } }); } } function startFCM ( ) { messaging .requestPermission() .then(function ( ) { return messaging.getToken(); }) .then(function (request ) { $.ajaxSetup({ headers : { "X-CSRF-TOKEN" : $('meta[name="csrf-token"]' ).attr("content" ), }, }); $.ajax({ url : '{{ route("fcm.token") }}' , type : "POST" , data : { token : request, }, dataType : "JSON" , success : function (request ) { console .log("取得token成功" ); }, error : function (error ) { console .log(error); }, }); }) .catch(function (error ) { console .log(error); }); } messaging.onMessage(function (payload ) { const title = payload.notification.title; const options = { body : payload.notification.body, icon : payload.notification.image, }; new Notification(title, options); }); notifyMe(); </script > @endsection
創建firebase-messaging-sw.js
為 Web 推送通知設置 firebase 配置文件,並將提供的代碼放在public/firebase-messaging-sw.js
importScripts("https://www.gstatic.com/firebasejs/8.3.2/firebase-app.js" ); importScripts("https://www.gstatic.com/firebasejs/8.3.2/firebase-messaging.js" ); firebase.initializeApp({ apiKey : "XXXX" , authDomain : "XXXX.firebaseapp.com" , projectId : "XXXX" , storageBucket : "XXXX" , messagingSenderId : "XXXX" , appId : "XXXX" , }); const messaging = firebase.messaging();messaging.setBackgroundMessageHandler(function (payload ) { console .log("Message received." , payload); const title = "Hello world is awesome" ; const options = { body : "Your notificaiton message ." , icon : "/firebase-logo.png" , }; return self.registration.showNotification(title, options); });
展示 cURL error 60: SSL certificate: unable to get local issuer certificate
如在本地端運行發生cURL error 60: SSL certificate: unable to get local issuer certificate
請至caextract 下載證書包
更改php.ini
,找到curl.cainfo
取消註解,並指向剛剛下載的檔案C:/cacert.pem
如還是有誤請參考stackoverflow