PHP项目APP推送消息如何对接实现

wen PHP项目 24

本文目录导读:

PHP项目APP推送消息如何对接实现

  1. 主流推送方案对比
  2. 使用极光推送示例
  3. 使用FCM(Firebase Cloud Messaging)
  4. 使用个推
  5. APNs原生推送(iOS)
  6. 使用场景示例(控制器)
  7. 注意事项

我来详细介绍PHP项目对接APP推送消息的完整实现方案。

主流推送方案对比

第三方推送服务(推荐)

  • 极光推送:支持Android和iOS
  • 个推:国内主流选择
  • 友盟+:阿里系产品
  • 腾讯移动推送:TPNS

原生推送

  • Android:Firebase Cloud Messaging (FCM)
  • iOS:Apple Push Notification Service (APNs)

使用极光推送示例

安装SDK

composer require jpush/jpush

基础推送实现

<?php
namespace App\Services;
use JPush\Client;
class PushService
{
    private $client;
    public function __construct()
    {
        $appKey = 'your_app_key';
        $masterSecret = 'your_master_secret';
        $this->client = new Client($appKey, $masterSecret);
    }
    /**
     * 推送给所有用户
     */
    public function pushToAll($title, $content, $extras = [])
    {
        try {
            $response = $this->client->push()
                ->setPlatform('all') // 全平台推送
                ->addAllAudience()   // 所有用户
                ->setNotificationAlert($content)
                ->androidNotification($title, [
                    'title' => $title,
                    'extras' => $extras
                ])
                ->iosNotification($title, [
                    'title' => $title,
                    'extras' => $extras
                ])
                ->send();
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('推送失败: ' . $e->getMessage());
        }
    }
    /**
     * 推送给指定用户
     */
    public function pushToUser($userId, $title, $content, $extras = [])
    {
        try {
            $response = $this->client->push()
                ->setPlatform('all')
                ->addAlias($userId) // 使用别名推送给特定用户
                ->setNotificationAlert($content)
                ->androidNotification($title, [
                    'title' => $title,
                    'extras' => $extras
                ])
                ->iosNotification($title, [
                    'title' => $title,
                    'extras' => $extras
                ])
                ->send();
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('推送失败: ' . $e->getMessage());
        }
    }
    /**
     * 推送给标签用户
     */
    public function pushByTag($tag, $title, $content, $extras = [])
    {
        try {
            $response = $this->client->push()
                ->setPlatform('all')
                ->addTag($tag)
                ->setNotificationAlert($content)
                ->androidNotification($title, [
                    'title' => $title,
                    'extras' => $extras
                ])
                ->iosNotification($title, [
                    'title' => $title,
                    'extras' => $extras
                ])
                ->send();
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('推送失败: ' . $e->getMessage());
        }
    }
}

用户注册设备

<?php
namespace App\Http\Controllers;
use App\Models\UserDevice;
use Illuminate\Http\Request;
class DeviceController extends Controller
{
    /**
     * 注册设备token
     */
    public function registerDevice(Request $request)
    {
        $validated = $request->validate([
            'user_id' => 'required|integer',
            'device_token' => 'required|string',
            'platform' => 'required|in:ios,android',
            'app_version' => 'nullable|string'
        ]);
        // 保存设备信息
        UserDevice::updateOrCreate(
            ['user_id' => $validated['user_id'], 'device_token' => $validated['device_token']],
            [
                'platform' => $validated['platform'],
                'app_version' => $validated['app_version'] ?? null,
                'last_active_at' => now()
            ]
        );
        return response()->json(['message' => '设备注册成功']);
    }
}

使用FCM(Firebase Cloud Messaging)

安装SDK

composer require kreait/firebase-php

FCM推送实现

<?php
namespace App\Services;
use Kreait\Firebase\Factory;
use Kreait\Firebase\Messaging\CloudMessage;
use Kreait\Firebase\Messaging\Notification;
class FcmService
{
    private $messaging;
    public function __construct()
    {
        $factory = (new Factory)
            ->withServiceAccount('/path/to/firebase_credentials.json');
        $this->messaging = $factory->createMessaging();
    }
    /**
     * 推送给指定设备
     */
    public function sendToDevice($deviceToken, $title, $body, $data = [])
    {
        $message = CloudMessage::withTarget('token', $deviceToken)
            ->withNotification(Notification::create($title, $body))
            ->withData($data);
        try {
            $response = $this->messaging->send($message);
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('FCM推送失败: ' . $e->getMessage());
        }
    }
    /**
     * 推送给多个设备
     */
    public function sendToMultipleDevices($deviceTokens, $title, $body, $data = [])
    {
        $messages = [];
        foreach ($deviceTokens as $token) {
            $messages[] = CloudMessage::withTarget('token', $token)
                ->withNotification(Notification::create($title, $body))
                ->withData($data);
        }
        try {
            $response = $this->messaging->sendAll($messages);
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('批量推送失败: ' . $e->getMessage());
        }
    }
    /**
     * 推送给主题订阅者
     */
    public function sendToTopic($topic, $title, $body, $data = [])
    {
        $message = CloudMessage::withTarget('topic', $topic)
            ->withNotification(Notification::create($title, $body))
            ->withData($data);
        try {
            $response = $this->messaging->send($message);
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('主题推送失败: ' . $e->getMessage());
        }
    }
}

使用个推

安装SDK

composer require getui/getui

个推推送实现

<?php
namespace App\Services;
use getui\Client\PushAPI;
use getui\Client\PushMessage;
use getui\Client\Target;
class GeTuiService
{
    private $pushApi;
    public function __construct()
    {
        $appId = 'your_app_id';
        $appKey = 'your_app_key';
        $masterSecret = 'your_master_secret';
        $this->pushApi = new PushAPI($appId, $appKey, $masterSecret);
    }
    /**
     * 推送给单个用户
     */
    public function pushToSingle($cid, $title, $content, $payload = [])
    {
        $message = new PushMessage();
        $message->setMsgType(PushMessage::MSG_TYPE_NOTIFICATION);
        $message->setTitle($title);
        $message->setContent($content);
        $message->setPayload($payload);
        $target = new Target();
        $target->setCid($cid);
        try {
            $response = $this->pushApi->pushToSingle($target, $message);
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('个推推送失败: ' . $e->getMessage());
        }
    }
    /**
     * 推送给所有用户
     */
    public function pushToAll($title, $content, $payload = [])
    {
        $message = new PushMessage();
        $message->setMsgType(PushMessage::MSG_TYPE_NOTIFICATION);
        $message->setTitle($title);
        $message->setContent($content);
        $message->setPayload($payload);
        try {
            $response = $this->pushApi->pushToAll($message);
            return $response;
        } catch (\Exception $e) {
            throw new \Exception('群推失败: ' . $e->getMessage());
        }
    }
}

APNs原生推送(iOS)

<?php
namespace App\Services;
class ApnsService
{
    private $pemFile;
    private $topic;
    public function __construct()
    {
        $this->pemFile = storage_path('app/apns.pem');
        $this->topic = 'com.yourcompany.app';
    }
    /**
     * 发送iOS推送
     */
    public function send($deviceToken, $title, $body, $badge = 0, $sound = 'default')
    {
        $payload = json_encode([
            'aps' => [
                'alert' => [
                    'title' => $title,
                    'body' => $body
                ],
                'badge' => $badge,
                'sound' => $sound,
                'content-available' => 1
            ]
        ]);
        $url = 'https://api.push.apple.com/3/device/' . $deviceToken;
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $payload,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'apns-topic: ' . $this->topic
            ],
            CURLOPT_SSLCERT => $this->pemFile,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if ($httpCode !== 200) {
            throw new \Exception('APNs推送失败,HTTP状态码: ' . $httpCode);
        }
        return $response;
    }
}

使用场景示例(控制器)

<?php
namespace App\Http\Controllers;
use App\Services\PushService;
use App\Models\User;
use Illuminate\Http\Request;
class NotificationController extends Controller
{
    private $pushService;
    public function __construct(PushService $pushService)
    {
        $this->pushService = $pushService;
    }
    /**
     * 发送订单通知
     */
    public function sendOrderNotification(Request $request)
    {
        $validated = $request->validate([
            'user_id' => 'required|integer',
            'order_id' => 'required|integer',
            'status' => 'required|string'
        ]);
        $user = User::findOrFail($validated['user_id']);
        $title = '订单通知';
        $content = "您的订单 ({$validated['order_id']}) 状态已更新为:{$validated['status']}";
        $extras = [
            'type' => 'order_status',
            'order_id' => $validated['order_id'],
            'status' => $validated['status']
        ];
        try {
            $response = $this->pushService->pushToUser(
                $user->id,
                $title,
                $content,
                $extras
            );
            return response()->json([
                'success' => true,
                'message' => '推送成功',
                'data' => $response
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage()
            ], 500);
        }
    }
    /**
     * 发送活动通知(所有用户)
     */
    public function sendActivityNotification(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|string',
            'content' => 'required|string',
            'activity_id' => 'required|integer'
        ]);
        try {
            $extras = [
                'type' => 'activity',
                'activity_id' => $validated['activity_id']
            ];
            $response = $this->pushService->pushToAll(
                $validated['title'],
                $validated['content'],
                $extras
            );
            return response()->json([
                'success' => true,
                'message' => '群发推送成功'
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage()
            ], 500);
        }
    }
}

注意事项

性能优化

  • 使用消息队列处理推送(Redis、RabbitMQ)
  • 批量推送时注意速率限制
  • 缓存设备token信息

错误处理

// 处理无效token
public function handleInvalidToken($response)
{
    if (isset($response['error'])) {
        // 标记设备token无效
        UserDevice::where('device_token', $response['failed_token'])
            ->update(['is_valid' => false]);
    }
}

安全建议

  • 使用HTTPS连接
  • 证书定期更新
  • 密钥存储在环境变量中
  • 实现访问令牌验证

选择哪种方案取决于你的具体需求、预算和技术栈,对于国内项目,推荐使用极光或个推;国际项目则推荐FCM。

抱歉,评论功能暂时关闭!