dive-be / laravel-expo-channel
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
重要
此通道已最终迁移到 其归属地(Laravel 通知通道项目),因此此存储库已被放弃。请从现在开始使用官方通道。
Expo 通知通道
Expo 通道用于向您的 React Native 应用推送通知。
内容
免责声明
此软件包目前不是 Laravel 通知通道 项目的部分,因为维护者似乎不活跃,且现有的 Expo 通道 从未完成,几乎已被放弃。此软件包遵守项目的所有约定(命名空间、消息创建等),因此未来可能的迁移只需替换 composer.json 中的软件包名称。
安装
您可以通过 composer 安装此软件包
composer require dive-be/laravel-expo-channel
额外安全(可选)
在 Expo 将它们发送给用户之前,您可以使用额外的 访问令牌 来要求发送任何推送通知。
如果您想使用此额外安全层,请将以下内容添加到您的 config/services.php 文件中
'expo' => [ 'access_token' => env('EXPO_ACCESS_TOKEN'), ],
使用
现在您可以在 Notification 的 via() 方法中使用 expo 通道。
通知 / ExpoMessage
首先,您需要有一个需要发送给某人的 通知。有关生成通知的更多信息,请参阅 Laravel 文档。
final 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(Carbon::now()->addHour()) ->priority('high') ->playSound(); } public function via($notifiable): array { return ['expo']; } }
注意有关 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。示例
final class User extends Authenticatable { use Notifiable; protected $casts = ['expo_token' => ExpoPushToken::class]; public function routeNotificationForExpo(): ?ExpoPushToken { return $this->expo_token; } }
警告如果返回
null,则不会发送任何通知。
注意有关模型转换的更多信息,请在此处找到。
多播(多个设备)
此方法 必须 返回一个 array<int, ExpoPushToken> 或 Collection<int, ExpoPushToken> 的实例,具体实现取决于您的用例。示例
final 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 类,您可以使用它来保护您的终端。示例
final 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 应用为自定义模型转换来实现这一点。示例
final class User extends Authenticatable { use Notifiable; protected $casts = ['expo_token' => AsExpoPushToken::class]; }
此自定义值对象保证了推送令牌的完整性。您应该确保仅保存 有效的令牌。
处理失败投递
不幸的是,Laravel 没有提供处理失败投递的 OOB 解决方案。然而,Laravel 提供了一个 NotificationFailed 事件,您可以通过此事件来挂钩失败的投递尝试。这在旧令牌不再有效且服务开始响应 DeviceNotRegistered 错误时尤其有用。
您可以注册一个事件监听器,该监听器监听此事件并处理相应的错误。示例
final readonly 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 实例,该实例具有以下属性
final readonly class ExpoError { private function __construct( public ExpoErrorType $type, public ExpoPushToken $token, public string $message, ) {} }
Expo 消息请求格式
ExpoMessage 类包含以下方法来定义消息有效载荷。所有这些方法都对应于 Expo Push 文档 中定义的可用的有效载荷。
徽章(iOS)
设置显示在应用程序图标上的徽章中的数字。
badge(int $value)
注意 该值必须大于或等于 0。
正文
设置要显示在通知中的消息正文。
body(string $value) text(string $value)
注意 该值不能为空。
类别 ID
设置与通知关联的通知类别 ID。
categoryId(string $value)
注意 该值不能为空。
频道 ID(Android)
设置通过该通知显示通知的通知频道 ID。
channelId(string $value)
注意 该值不能为空。
JSON 数据
设置消息的 JSON 数据。
data(Arrayable|Jsonable|JsonSerializable|array $value)
警告 我们使用 Gzip(如果
ext-zlib可用)压缩超过 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
变更日志
请参阅 变更日志 了解最近发生了哪些变化。
贡献
请参阅 贡献指南 了解详细信息。
安全
如果您发现任何与安全相关的问题,请通过电子邮件 oss@dive.be 而不是使用问题跟踪器。
致谢
许可
MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件。
