Device Token هو معرف فريد يخصصه APNS لكل جهاز iOS لتوجيه إشعارات الدفع. يتم إنشاء الرمز بواسطة النظام عند تسجيل التطبيق لتلقي الإشعارات ويجب إرساله إلى الخادم لإرسال الإشعارات إلى هذا الجهاز تحديداً. وفقاً لوثائق مطوري Apple، 2026، قد يتغير Device Token عند إعادة تثبيت التطبيق أو استعادة الجهاز من نسخة احتياطية أو تحديث iOS، لذلك يجب على الخادم تحديث الرموز بانتظام لضمان التوصيل.
النقاط الرئيسية
Device Token (رمز الجهاز) هو معرف فريد على شكل سلسلة hex ينشئه APNS (خدمة الإشعارات الفورية من Apple) لكل تطبيق على جهاز iOS. الرمز هو المفتاح الذي يرسل به الخادم إشعارات الدفع إلى جهاز معين. بدون Device Token صالح، لا يمكن للخادم توصيل إشعارات الدفع — يرفض APNS الطلب مع خطأ 400 BadRequest.
يتم إنشاء Device Token بواسطة نظام iOS عند أول اتصال للتطبيق بـ APNS بعد التثبيت. عملية الإنشاء تتضمن ربطاً تشفيرياً مع معرف الحزمة (bundle ID) للتطبيق والمعرف الفريد للجهاز (UID)، ثم يعيد APNS رمزاً بحجم 32 بايت بتنسيق hex (64 حرفاً) إلى التطبيق. الرمز ليس دائماً — قد يُنشئ النظام رمزاً جديداً في ظروف معينة.
عندما يرسل الخادم إشعار دفع، يضمّن Device Token في طلب HTTP/2 إلى APNS. يتحقق APNS من صحة الرمز: إذا كان الرمز ينتمي إلى بيئة أخرى (sandbox بدلاً من production)، أو منتهي الصلاحية، أو ملغى، يعيد خادم Apple خطأ 410 Gone أو 400 BadRequest. فقط بعد التحقق الناجح من الرمز، يبدأ APNS في توصيل الإشعار إلى الجهاز.
لا ينبغي الخلط بين Device Token و IDFA (معرف المعلنين) أو IDFV (معرف البائع) أو UID (معرف الجهاز الفريد). IDFA و IDFV يُستخدمان للإعلانات والتحليلات، UID هو رقم تسلسلي للجهاز. Device Token موجود حصرياً لإشعارات الدفع ولا يكشف معلومات عن المستخدم أو الجهاز خارج APNS.
| المعرف | الغرض | الثبات |
|---|---|---|
| Device Token | توجيه إشعارات الدفع APNS | قد يتغير |
| IDFA | الإعلانات والتتبع | يمكن إعادة تعيينه من قبل المستخدم |
| IDFV | تعريف البائع (التحليلات) | ثابت لتطبيقات نفس المطور |
| Bundle ID | معرف فريد للتطبيق | ثابت |
تتكون عملية الحصول على Device Token من عدة خطوات إلزامية، بدءاً من طلب إذن المستخدم وانتهاءً بإرسال الرمز إلى الخادم. كل خطوة حاسمة — تخطي أي منها يؤدي إلى عدم القدرة على إرسال إشعارات الدفع إلى الجهاز.
الخطوة الأولى هي أن يطلب التطبيق إذن المستخدم لإرسال الإشعارات عبر UNUserNotificationCenter.current().requestAuthorization. يمكن للمستخدم الموافقة أو الرفض أو اختيار خيارات اختيارية (تنبيه، شارة، صوت). بدون موافقة صريحة من المستخدم، لن يصدر النظام Device Token، حتى إذا استدعى التطبيق registerForRemoteNotifications. بعد الحصول على الإذن، يستدعي التطبيق UIApplication.shared.registerForRemoteNotifications()، مما يبدأ عملية التسجيل في APNS.
بعد التسجيل، يعيد APNS الرمز عبر مفوض AppDelegate: application(_:didRegisterForRemoteNotificationsWithDeviceToken:). الاستدعاء الناجح يحتوي على كائن Data مع الرمز، الذي يجب تحويله إلى سلسلة hex لإرساله إلى الخادم. في حالة الخطأ، يستدعي النظام application(_:didFailToRegisterForRemoteNotificationsWithError:) مع وصف المشكلة: تكوين شهادة غير صحيح، عدم وجود شبكة، أو تكوين مشروع غير صحيح.
بعد استلام الرمز، يجب على التطبيق إرساله فوراً إلى خادمه لتخزينه في قاعدة البيانات. طلب API يتضمن الرمز، معرف الجهاز (للتطابق)، البيئة (sandbox/production)، واختيارياً بيانات إضافية: إصدار نظام التشغيل، طراز الجهاز، اللغة. يُوصى بإعادة إرسال الرمز عند كل تشغيل للتطبيق ليكون لدى الخادم دائماً رمز محدث.
// طلب الإذن والتسجيل في APNS
func registerForPushNotifications() {
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] granted, error in
guard granted else {
print("لم يتم منح الإذن")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
// الحصول على Device Token من APNS
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenString = deviceToken
.map { String(format: "%02.2hhx", $0) }
.joined()
print("Device Token: \(tokenString)")
// إرسال الرمز إلى الخادم
PushTokenService.shared
.sendTokenToServer(tokenString) { success in
if success {
UserDefaults.standard.set(tokenString,
forKey: "lastDeviceToken")
}
}
}
جانب الخادم لنظام الدفع يجب أن يخزن Device Token في قاعدة البيانات، مرتبطاً بالمستخدم والبيئة. عند إرسال إشعار، يُشكل الخادم طلباً إلى APNS، متضمناً الرمز في URL ورمز JWT (أو شهادة) للتفويض. الإدارة الصحيحة للرموز تؤثر بشكل حاسم على نسبة توصيل إشعارات الدفع.
يجب أن يحتوي جدول الرموز على الخادم على الأقل على: Device Token (فريد)، معرف المستخدم، البيئة (sandbox/production)، تاريخ آخر تحديث، والحالة (نشط/غير نشط). يُوصى بإضافة فهرس على الرمز للبحث السريع عند الإرسال وعلى المستخدم للحصول على قائمة جميع أجهزة المستخدم. تسمح العديد من التطبيقات لمستخدم واحد بامتلاك أجهزة متعددة — كل منها برمز خاص به.
لإرسال إشعار دفع، يجب على الخادم تفويض الطلب إلى APNS بطريقتين. المعتمدة على الشهادة تستخدم شهادة SSL مولدة في Apple Developer Console. المعتمدة على الرمز تستخدم JWT (رمز ويب JSON) مع مفتاح .p8 صالح لمدة تصل إلى 30 يوماً دون الحاجة لتجديد الشهادة. التفويض المعتمد على الرمز يعتبر أكثر حداثة وتوصي به Apple للمشاريع الجديدة.
يتضمن الطلب إلى APNS طريقة HTTP/2 POST، URL مع المسار /3/device/{device_token}، رؤوس التفويض، وجسم JSON مع المحتوى. رأس apns-topic يجب أن يحتوي على معرف حزمة التطبيق. apns-priority يحدد أولوية التوصيل (5 — فوراً، 10 — مع توفير البطارية). apns-expiration يحدد الوقت بالثواني من الحقبة الذي سيحاول APNS خلاله توصيل الإشعار.
// مثال لإرسال push على Node.js عبر APNS HTTP/2
const http2 = require('http2');
const client = http2.connect('https://api.push.apple.com');
const deviceToken = 'abcdef0123456789...';
const payload = JSON.stringify({
"aps": { "alert": "Hello!", "sound": "default" }
});
const req = client.request({
':method': 'POST',
':path': `/3/device/${deviceToken}`,
'apns-topic': 'com.example.app',
'apns-priority': '10',
'apns-expiration': '0',
'authorization': `bearer ${jwtToken}`
});
req.write(payload);
req.end();
req.on('response', (headers) => {
if (headers[':status'] === '200') {
console.log('تم إرسال الإشعار بنجاح');
}
});
عند إرسال إشعارات الدفع لعدد كبير من الأجهزة، استخدم الإرسال بالدفعات مع التحكم في السرعة. توصي APNS بعدم تجاوز 1500 طلب في الثانية لكل اتصال. عند تجاوز الحد، يعيد خادم Apple خطأ 429 Too Many Requests. للحملات الواسعة النطاق، استخدم اتصالات متعددة ووزع الحمل بالتساوي على الأجهزة.
Device Token ليس دائماً وقد يتغير في عدة سيناريوهات، مما يتطلب آلية تحديث على الخادم. إذا استمر الخادم في إرسال الإشعارات إلى رمز قديم، يعيد APNS خطأ 410 Gone، مشيراً إلى أن الرمز لم يعد صالحاً للبيئة المعطاة.
توثق Apple عدة سيناريوهات يتغير فيها Device Token: يعيد المستخدم تثبيت التطبيق، يستعيد الجهاز من نسخة iCloud الاحتياطية، يُثبت إصداراً جديداً من iOS، أو يعيد ضبط إعدادات الشبكة أو الخصوصية. في كل حالة، سيستلم التطبيق رمزاً جديداً من APNS عند تشغيله التالي. يجب على الخادم تحديث الرمز في قاعدة البيانات، بإزالة القديم وحفظ الجديد.
عندما يرسل الخادم إشعاراً إلى رمز قديم، يعيد APNS HTTP 410 مع رأس apns-unless-timestamp. هذا الرأس يشير إلى الوقت الذي أصبح بعده الرمز غير صالح. يجب على الخادم حذف أو إلغاء تنشيط هذا الرمز فوراً في قاعدة البيانات لتجنب الإرسال إليه مرة أخرى. تجاهل خطأ 410 يهدر الموارد ويقلل من نسبة التوصيل.
للحفاظ على قاعدة بيانات الرموز محدثة، يُوصى بتشغيل تنظيف دوري. سكريبت التنظيف يحلل سجلات APNS لآخر N يوم، ويعثر على جميع الرموز التي تلقت خطأ 410، ويعطلها في قاعدة البيانات. بالإضافة، يمكن إزالة الرموز التي لا يوجد بها نشاط مستخدم لأكثر من 90 يوماً — هذه سجلات غير مفيدة تزيد فقط من حجم قاعدة البيانات.
قبل الإرسال الجماعي لإشعارات الدفع (النشرات الإخبارية، الحملات الترويجية)، يُوصى بالتحقق المسبق من الرموز. APNS لا يوفر API مباشر للتحقق الجماعي من الرموز، لذلك تُستخدم استراتيجية إرسال إشعار اختبار بأولوية منخفضة وتحليل الأخطاء. الرموز التي تعيد خطأ 410 تُستثنى من الإرسال الرئيسي.
دعنا نستعرض الدورة الكاملة للحصول على Device Token في Swift، بما في ذلك معالجة الأخطاء والإرسال إلى الخادم. الكود يغطي طلب الإذن، التسجيل في APNS، تحويل Data إلى سلسلة hex، معالجة الأخطاء، وإرسال الرمز إلى الخادم الخاص بك مع محاولات إعادة عند الفشل.
import UIKit
import UserNotifications
final class PushNotificationManager: NSObject {
static let shared = PushNotificationManager()
private let apiClient = APIClient()
private var currentToken: String?
func register() {
UNUserNotificationCenter.current()
.requestAuthorization(
options: [.alert, .badge, .sound]) {
[weak self] granted, error in
guard granted else {
Analytics.log(
"Push permission denied")
return
}
DispatchQueue.main.async {
UIApplication.shared
.registerForRemoteNotifications()
}
}
}
func handleDeviceToken(_ tokenData: Data) {
let token = tokenData
.map { String(format: "%02.2hhx", $0) }
.joined()
guard token != currentToken else { return }
currentToken = token
sendTokenToServer(token)
}
func handleRegistrationError(_ error: Error) {
Analytics.log(
"Push registration failed: \(error)")
// إعادة المحاولة بعد تأخير عند أخطاء الشبكة
if let urlError = error as? URLError,
urlError.code == .notConnectedToInternet {
DispatchQueue.main.asyncAfter(
deadline: .now() + 10) { [weak self] in
self?.register()
}
}
}
private func sendTokenToServer(_ token: String) {
let body = PushTokenRequest(
token: token,
environment: Environment.current == .debug
? "sandbox" : "production",
osVersion: UIDevice.current.systemVersion,
locale: Locale.current.identifier
)
apiClient.sendToken(body) { [weak self] result in
if case .success = result {
self?.currentToken = token
}
}
}
}
يمكن أن تحدث أخطاء أثناء التسجيل في APNS لأسباب متنوعة. الأكثر شيوعاً تشمل عدم توفر الشبكة، تكوين شهادة غير صحيح في Xcode (مثل تعطيل إمكانية Push Notifications)، استخدام المحاكي (الذي لا يدعم الدفع)، أو ملف تعريف تزويد غير صحيح. في الإنتاج، من المهم تسجيل الأخطاء وإذا أمكن، إعادة محاولة التسجيل عند تشغيل التطبيق التالي.
محاكي iOS لا يدعم استلام Device Token حقيقي. لاختبار التسجيل على المحاكي، استخدم فحوصات بنية i386: في بناء التصحيح، يمكن محاكاة استلام الرمز أو استخدام اختبارات UI بكائنات وهمية. اختبار إشعارات الدفع الحقيقي يتم دائماً على جهاز فعلي متصل بـ Xcode.
الأسئلة الشائعة
نعم، قد يتغير Device Token عند إعادة تثبيت التطبيق أو استعادة الجهاز من نسخة احتياطية أو تحديث iOS. يجب على الخادم معالجة تحديثات الرموز: عند استلام رمز جديد من جهاز معروف — استبدال القديم، عند حدوث خطأ 410 — إزالة الرمز من قاعدة البيانات.
Device Token هو سلسلة hex بحجم 32 بايت من 64 حرفاً بأحرف صغيرة (0–9, a–f). مثال: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2". يتم تمرير الرمز كـ Data من APNS وتحويله إلى سلسلة في جانب التطبيق.
يُصدر رمز sandbox للتطبيقات المبنية بملف تعريف تزويد تطويري ويعمل فقط مع api.sandbox.push.apple.com. رمز production مخصص لـ App Store و TestFlight ويعمل مع api.push.apple.com. يجب على الخادم التمييز بين البيئات وإرسال الإشعارات إلى نقطة نهاية APNS المناسبة.
خطأ 410 Gone يعني أن Device Token غير صالح. يجب على الخادم إزالة هذا الرمز فوراً من قاعدة البيانات والتوقف عن محاولة الإرسال إليه. يشير رأس apns-unless-timestamp في الاستجابة إلى الوقت الذي توقف فيه الرمز عن العمل.
تحقق من استدعاء المفوض application(_:didRegisterForRemoteNotificationsWithDeviceToken:) في AppDelegate. إذا تم استدعاء الطريقة — تم استلام الرمز. استخدم سجلات التصحيح أو OSLog لعرض الرمز في وحدة تحكم Xcode. على جهاز فعلي، تحقق من إرسال الرمز إلى الخادم باستخدام Network Link Conditioner.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا