Laravel 的 Expo 通知通道
Requires
- php: ~8.3
- ext-json: *
- guzzlehttp/guzzle: ^7.1
- illuminate/contracts: ^11.0
- illuminate/notifications: ^11.0
- illuminate/support: ^11.0
Requires (Dev)
- larastan/larastan: ^2.0
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0
Suggests
- ext-zlib: Required for compressing payloads exceeding 1 KiB in size.
README
Expo 通知通道
Expo 为推送通知到您的 React Native 应用提供的通道。
内容
安装
您可以通过 Composer 安装此包
composer require laravel-notification-channels/expo
额外安全(可选)
您可以在 Expo 将它们发送给用户之前,要求任何推送通知都要发送一个额外的 访问令牌。
如果您想使用此额外的安全层,请在您的 config/services.php
文件中添加以下内容
'expo' => [ 'access_token' => env('EXPO_ACCESS_TOKEN'), ],
使用
现在您可以在 Notification
的 via()
方法中使用 expo
通道。
通知 / ExpoMessage
首先,您需要一个需要发送给某人的 通知。有关生成通知的更多信息,请参阅 Laravel 文档。
use NotificationChannels\Expo\ExpoMessage; class SuspiciousActivityDetected extends Notification { public function toExpo($notifiable): ExpoMessage { return ExpoMessage::create('Suspicious Activity') ->body('Someone tried logging in to your account!') ->data($notifiable->only('email', 'id')) ->expiresAt(now()->addHour()) ->priority('high') ->playSound(); } public function via($notifiable): array { return ['expo']; } }
注意
有关 Expo 消息请求格式的详细说明可以在 这里 找到。
您还可以在 ExpoMessage
上应用条件,而不会破坏方法链
use NotificationChannels\Expo\ExpoMessage; public function toExpo($notifiable): ExpoMessage { return ExpoMessage::create('Suspicious Activity') ->body('Someone tried logging in to your account!') ->when($notifiable->wantsSound(), fn ($msg) => $msg->playSound()) ->unless($notifiable->isVip(), fn ($msg) => $msg->normal(), fn ($msg) => $msg->high()); }
可通知的 / ExpoPushToken
接下来,您必须在您的 Notifiable
模型中设置一个 routeNotificationForExpo()
方法。
单播(单个设备)
该方法 必须 返回 ExpoPushToken
的实例或 null
。示例
use NotificationChannels\Expo\ExpoPushToken; class User extends Authenticatable { use Notifiable; /** * Get the attributes that should be cast. * * @return array<string, string> */ protected function casts(): array { return [ 'expo_token' => ExpoPushToken::class ]; } public function routeNotificationForExpo(): ?ExpoPushToken { return $this->expo_token; } }
重要
如果返回 null
,则不会发送任何通知。
注意
有关模型转换的更多信息可以在 这里 找到。
多播(多个设备)
该方法 必须 返回一个 array<int, ExpoPushToken>
或 Collection<int, ExpoPushToken>
,具体实现取决于您的用例。示例
use Illuminate\Database\Eloquent\Collection; class User extends Authenticatable { use Notifiable; /** * @return Collection<int, ExpoPushToken> */ public function routeNotificationForExpo(): Collection { return $this->devices->pluck('expo_token'); } }
重要
如果 Collection
为空,则不会发送任何通知。
发送
一切准备就绪后,您可以通过调用
$user->notify(new SuspiciousActivityDetected());
验证
您应该有一个 HTTP 端点,该端点将给定的 ExpoPushToken
与经过身份验证的 User
关联起来,以便您可以将推送通知发送出去。因此,我们还提供了一个自定义验证 ExpoPushTokenRule
类,您可以使用它来保护您的端点。示例
use NotificationChannels\Expo\ExpoPushToken; class StoreDeviceRequest extends FormRequest { public function rules(): array { return [ 'device_id' => ['required', 'string', 'min:2', 'max:255'], 'token' => ['required', ExpoPushToken::rule()], ]; } }
模型转换
ExpoChannel
期望您从您的 Notifiable
返回 ExpoPushToken
的实例。您可以通过将 ExpoPushToken
作为自定义模型转换来实现这一点。示例
use NotificationChannels\Expo\ExpoPushToken; class User extends Authenticatable { use Notifiable; /** * Get the attributes that should be cast. * * @return array<string, string> */ protected function casts(): array { return [ 'expo_token' => ExpoPushToken::class ]; } }
此自定义值对象保证了推送令牌的完整性。您应该确保 仅保存有效的令牌。
处理失败的投递
遗憾的是,Laravel 并没有提供处理失败投递的 OOB(Out of the Box)解决方案。[查看详情](https://github.com/laravel-notification-channels/channels/issues/16)。然而,Laravel 提供了 NotificationFailed
事件,因此您可以挂钩到失败的投递尝试。这在旧令牌不再有效且服务开始响应 DeviceNotRegistered
错误时特别有用。
您可以注册一个事件监听器,监听此事件并处理适当的错误。以下是一个示例
use Illuminate\Notifications\Events\NotificationFailed; class HandleFailedExpoNotifications { public function handle(NotificationFailed $event) { if ($event->channel !== 'expo') return; /** @var ExpoError $error */ $error = $event->data; // Remove old token if ($error->type->isDeviceNotRegistered()) { $event->notifiable->update(['expo_token' => null]); } else { // do something else like logging... } } }
NotificationFailed::$data
属性将包含一个 ExpoError
实例,该实例具有以下属性
namespace NotificationChannels\Expo; final readonly class ExpoError { private function __construct( public ExpoErrorType $type, public ExpoPushToken $token, public string $message, ) {} }
Expo 消息请求格式
ExpoMessage
类包含以下方法来定义消息负载。所有这些方法都与 [Expo Push 文档](https://docs.expo.dev/push-notifications/sending-notifications/#message-request-format) 中定义的可用的负载相对应。
徽章(iOS)
设置应用图标上徽章中显示的数字。
badge(int $value)
注意
该值必须大于或等于 0。
正文
设置要在通知中显示的消息正文。
body(string $value) text(string $value)
注意
该值不能为空。
类别 ID
设置与通知关联的通知类别 ID。
categoryId(string $value)
注意
该值不能为空。
通道 ID(Android)
设置要通过其显示此通知的 Notification Channel ID。
channelId(string $value)
注意
该值不能为空。
JSON 数据
设置消息的 JSON 数据。
data(Arrayable|Jsonable|JsonSerializable|array $value)
警告
如果可用 ext-zlib
,我们将使用 Gzip 压缩超过 1 KiB 的 JSON 负载。虽然技术上可以发送超过 4 KiB 的数据,但此做法不推荐。
过期时间
设置消息的过期时间。与 TTL 具有相同的效果。
expiresAt(DateTimeInterface|int $value)
警告
如果两者都设置,则 TTL
优先。
注意
该值必须在将来。
可变内容(iOS)
设置通知是否可以被客户端应用程序拦截。
mutableContent(bool $value = true)
通知声音(iOS)
当收件人收到通知时播放默认通知声音。
playSound()
警告
不支持自定义声音。
优先级
设置消息的投递优先级。
priority(string $value) default() normal() high()
注意
该值必须是 default
、normal
或 high
。
副标题(iOS)
设置在通知标题下方显示的副标题。
subtitle(string $value)
注意
该值不能为空。
标题
设置在通知中显示的标题。
title(string $value)
注意
该值不能为空。
TTL(生存时间)
设置消息可以被保留以供重新投递的秒数。
ttl(int $value) expiresIn(int $value)
警告
如果两者都设置,则 expiration
优先。
注意
该值必须大于 0。
测试
composer test
更新日志
有关最近更改的更多信息,请参阅 CHANGELOG。
贡献
有关详细信息,请参阅 CONTRIBUTING。
安全
如果您发现任何安全相关的问题,请通过电子邮件 muhammed@dive.be 而不是使用问题跟踪器。
致谢
许可证
MIT 许可证(MIT)。有关更多信息,请参阅 许可文件。