You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Swift新手求助:实现网站访问时iPhone接收通知的简易App方案

Hey Dave!作为有PHP和JS基础的开发者,你其实已经握有一半的优势了,咱们一步步拆解这个需求,绝对能轻松搞定~

整体实现核心逻辑

说白了就是三个关键环节:网站访问触发后端事件 → 后端调用苹果推送服务(APNs) → 你的iPhone接收通知,咱们拆分每个环节来落地:

1. Swift端:搞定iPhone的推送基础配置(新手友好)

这部分是入门级Swift操作,不用怕,跟着步骤来:

  • 先在Xcode新建一个iOS项目(选「Single View App」就足够,不用复杂模板)
  • 打开项目的Signing & Capabilities,添加Push Notifications能力,同时开启Background Modes里的Remote notifications(保证App后台也能收通知)
  • 复制这段带注释的基础代码到AppDelegate.swift,核心是获取你的iPhone在APNs中的唯一标识(设备令牌):
    import UIKit
    import UserNotifications
    
    @main
    class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // 向用户申请通知权限
            UNUserNotificationCenter.current().delegate = self
            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
                if granted {
                    DispatchQueue.main.async {
                        application.registerForRemoteNotifications()
                    }
                }
            }
            return true
        }
    
        // 获取设备令牌(一定要把这个令牌传给你的网站后端存起来!)
        func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
            let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
            let token = tokenParts.joined()
            print("你的设备令牌:\(token)")
            // 这里可以写个简单的网络请求,把token发送到你的网站后端接口存储
        }
    
        // 处理前台收到通知的提示逻辑
        func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
            completionHandler([.alert, .sound])
        }
    }
    
    运行项目后,控制台会打印出你的设备令牌,把它复制下来给后端用。

2. 后端端:用你熟悉的PHP/JS处理访问触发与推送

这部分是你的强项,分两个小步骤:

  • 检测网站访问:在网站入口文件(比如PHP的index.php,或JS后端的路由逻辑里)添加代码,每次有用户访问时触发推送逻辑(可以加个简单去重,比如同一IP 5分钟内重复访问不推送,避免被通知轰炸)
  • 调用APNs发送通知:苹果提供了HTTP/2接口,用PHP或JS都能轻松实现,给你两个示例:

PHP推送示例

<?php
// 替换成你自己的苹果开发者信息
$apnsKey = file_get_contents('你的APNs密钥文件.p8'); // 从苹果开发者后台下载的.p8文件
$apnsKeyId = '你的密钥ID'; // 苹果后台生成密钥时的ID
$teamId = '你的开发者团队ID'; // 苹果开发者账号的团队ID
$deviceToken = '刚才从Swift端拿到的设备令牌';
$topic = '你的App的Bundle ID'; // 比如 com.yourname.VisitorAlert

// 生成APNs需要的JWT身份令牌
$header = json_encode(['alg' => 'ES256', 'kid' => $apnsKeyId]);
$payload = json_encode(['iss' => $teamId, 'iat' => time()]);
$base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
$base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
$signature = '';
openssl_sign("$base64Header.$base64Payload", $signature, $apnsKey, 'SHA256');
$jwt = "$base64Header.$base64Payload." . str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

// 构建通知内容
$notification = json_encode([
    'aps' => [
        'alert' => [
            'title' => '网站有新访问!',
            'body' => '有人刚刚浏览了你的网站~'
        ],
        'sound' => 'default'
    ]
]);

// 发送请求到APNs
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.push.apple.com/3/device/$deviceToken");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $notification);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer $jwt",
    "apns-topic: $topic",
    "Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

// 可选:记录推送日志方便排查问题
file_put_contents('push_log.txt', date('Y-m-d H:i:s') . ' - ' . $response . PHP_EOL, FILE_APPEND);
?>

Node.js推送示例

const jwt = require('jsonwebtoken');
const https = require('https');
const fs = require('fs');

// 替换成你自己的信息
const apnsKey = fs.readFileSync('你的APNs密钥文件.p8');
const apnsKeyId = '你的密钥ID';
const teamId = '你的开发者团队ID';
const deviceToken = '刚才从Swift端拿到的设备令牌';
const topic = '你的App的Bundle ID';

// 生成JWT令牌
const token = jwt.sign({}, apnsKey, {
    algorithm: 'ES256',
    expiresIn: '1h',
    issuer: teamId,
    header: {
        alg: 'ES256',
        kid: apnsKeyId
    }
});

// 构建通知内容
const notification = JSON.stringify({
    aps: {
        alert: {
            title: '网站有新访问!',
            body: '有人刚刚浏览了你的网站~'
        },
        sound: 'default'
    }
});

// 发送请求到APNs
const options = {
    hostname: 'api.push.apple.com',
    port: 443,
    path: `/3/device/${deviceToken}`,
    method: 'POST',
    headers: {
        'Authorization': `Bearer ${token}`,
        'apns-topic': topic,
        'Content-Type': 'application/json',
        'Content-Length': notification.length
    }
};

const req = https.request(options, (res) => {
    res.on('data', (d) => {
        // 可选:记录推送结果
        fs.appendFileSync('push_log.txt', `${new Date().toISOString()} - ${d}\n`);
    });
});

req.on('error', (e) => {
    console.error('推送失败:', e);
});

req.write(notification);
req.end();

3. 测试与优化小建议

  • 优先用真机测试推送,模拟器偶尔会有推送延迟或接收不到的情况
  • 后端可以加个冷却机制,比如同一IP 5分钟内重复访问不触发推送,避免通知刷屏
  • 把设备令牌存在数据库里,以后换手机直接更新令牌就行,不用改后端代码
  • 苹果开发者后台的APNs密钥要妥善保存,别泄露出去

内容的提问来源于stack exchange,提问作者David Stančík

火山引擎 最新活动