Laravel 的 Expo 通知通道

v2.0.0 2024-03-18 07:49 UTC

This package is auto-updated.

Last update: 2024-09-15 02:09:09 UTC


README

Social Card of Laravel Expo Channel

Expo 通知通道

Latest Version on Packagist GitHub Tests Action Status Total Downloads

Expo 为推送通知到您的 React Native 应用提供的通道。

内容

安装

您可以通过 Composer 安装此包

composer require laravel-notification-channels/expo

额外安全(可选)

您可以在 Expo 将它们发送给用户之前,要求任何推送通知都要发送一个额外的 访问令牌

如果您想使用此额外的安全层,请在您的 config/services.php 文件中添加以下内容

'expo' => [
    'access_token' => env('EXPO_ACCESS_TOKEN'),
],

使用

现在您可以在 Notificationvia() 方法中使用 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()

注意

该值必须是 defaultnormalhigh

副标题(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)。有关更多信息,请参阅 许可文件