تخصيص iOS SDK
التكامل
Anchor link to- الروابط العميقة
- الروابط الشاملة
- تتبع عمليات الشراء داخل التطبيق
- إشعارات الدفع للمناطق الجغرافية (Geozones)
- إنشاء قائمة انتظار للوسائط الغنية (Rich Media)
- التشغيل التلقائي لفيديو مُرسل في إشعار غني (Rich Notification) باستخدام اللمس القوي (force touch)
- صوت إشعار دفع مخصص
- إشعارات الدفع المؤقتة لنظام iOS
الروابط العميقة
Anchor link toفي ملف Info.plist الخاص بك، أضف مصفوفة URL types مع URL Identifier و URL Scheme.
في المثال أدناه، URL Scheme هو com.pushwoosh و URL Identifier هو promotion.

في ملف App Delegate الخاص بك (عادةً AppDelegate.m لنظام iOS 12 والإصدارات الأقدم، أو SceneDelegate.m لنظام iOS 13 والإصدارات الأحدث)، أضف دالة التفويض openURL المناسبة كما هو موضح في المثال أدناه. يتحقق المثال من الصفحة الصحيحة، ويحلل قيمة “id” من عنوان URL، ويفتح PromoPageViewController استجابةً لذلك.
AppDelegate.swift
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let components = URLComponents(url: url, resolvingAgainstBaseURL: false) let page = components?.host var promotionId: String?
if page == "promotion" { return }
let items = components?.queryItems ?? []
for item in items { if item.name == "id" { promotionId = item.value } }
//show PromoPageViewController}- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; NSString *page = components.host; NSString *promotionId = nil;
//return if this is not a promotion deep link if(![page isEqualToString:@"promotion"]) return NO;
for(NSURLQueryItem *item in components.queryItems) { if([item.name isEqualToString:@"id"]) promotionId = item.value; }
PromoPageViewController *vc = [[PromoPageViewController alloc] init]; vc.promotionId = promotionId [self presentViewController:vc animated:YES completion:nil];}SceneDelegate.swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { guard let urlContext = URLContexts.first else { return }
let components = URLComponents(url: urlContext.url, resolvingAgainstBaseURL: false) let page = components?.host var promotionId: String?
guard page == "promotion" else { return }
let items = components?.queryItems ?? []
for item in items { if item.name == "id" { promotionId = item.value } }
//show PromoPageViewController}- (void)scene:(UIWindowScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts { UIOpenURLContext *urlContext = URLContexts.anyObject; if (!urlContext) { return; }
NSURLComponents *components = [NSURLComponents componentsWithURL:urlContext.URL resolvingAgainstBaseURL:NO]; NSString *page = components.host; NSString *promotionId = nil;
if (![page isEqualToString:@"promotion"]) { return; }
for (NSURLQueryItem *item in components.queryItems) { if ([item.name isEqualToString:@"id"]) { promotionId = item.value; } }
//show PromoPageViewController}الروابط الشاملة
Anchor link toتسمح الروابط الشاملة (Universal Links) للمستخدمين بفتح تطبيقك مباشرة عند النقر على رابط لموقعك الإلكتروني. على عكس مخططات URL المخصصة، تستخدم الروابط الشاملة عناوين URL القياسية https:// وتوفر تجربة مستخدم أكثر سلاسة.
كيف تعمل
Anchor link toعندما يحتوي إشعار الدفع على عنوان URL https:// (في المعلمة “url” أو “l”)، سيقوم SDK بما يلي:
- إنشاء
NSUserActivityمع عنوان URL - استدعاء معالج الروابط الشاملة في تطبيقك (
scene:continueUserActivity:أوapplication:continueUserActivity:restorationHandler:) - إذا لم يتعامل تطبيقك مع عنوان URL، فسيتم فتحه في Safari كحل بديل
الإعداد
Anchor link to- تكوين النطاقات المرتبطة في Xcode
أضف إمكانية النطاقات المرتبطة (Associated Domains) إلى تطبيقك وأضف نطاقك:
applinks:yourdomain.com- استضافة ملف Apple App Site Association
أنشئ ملف apple-app-site-association على خادم الويب الخاص بك في https://yourdomain.com/.well-known/apple-app-site-association:
{ "applinks": { "apps": [], "details": [ { "appID": "TEAM_ID.com.your.bundleid", "paths": ["/path/*", "/promotion/*"] } ] }}استبدل TEAM_ID بمعرف فريق مطوري Apple الخاص بك و com.your.bundleid بمعرف حزمة تطبيقك.
- تنفيذ معالج الروابط الشاملة
SceneDelegate.swift (iOS 13+)
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return }
// Handle the Universal Link URL let components = URLComponents(url: url, resolvingAgainstBaseURL: false) let path = components?.path
if path?.starts(with: "/promotion") == true { // Navigate to promotion screen let promotionId = components?.queryItems?.first(where: { $0.name == "id" })?.value // Show promotion with promotionId }}- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity { if (![userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { return; }
NSURL *url = userActivity.webpageURL; if (!url) { return; }
// Handle the Universal Link URL NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; NSString *path = components.path;
if ([path hasPrefix:@"/promotion"]) { // Navigate to promotion screen NSString *promotionId = nil; for (NSURLQueryItem *item in components.queryItems) { if ([item.name isEqualToString:@"id"]) { promotionId = item.value; break; } } // Show promotion with promotionId }}AppDelegate.swift (iOS 12 والإصدارات الأقدم، أو كحل بديل)
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return false }
// Handle the Universal Link URL let components = URLComponents(url: url, resolvingAgainstBaseURL: false) let path = components?.path
if path?.starts(with: "/promotion") == true { // Navigate to promotion screen return true }
return false}- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler {
if (![userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { return NO; }
NSURL *url = userActivity.webpageURL; if (!url) { return NO; }
// Handle the Universal Link URL NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; NSString *path = components.path;
if ([path hasPrefix:@"/promotion"]) { // Navigate to promotion screen return YES; }
return NO;}إرسال إشعار دفع برابط شامل
Anchor link toعند إنشاء إشعار دفع، استخدم عنوان URL لموقعك الإلكتروني في حقل الإجراء (Action):
https://yourdomain.com/promotion?id=123سيقوم SDK تلقائيًا بتوجيه عنوان URL هذا إلى معالج الروابط الشاملة الخاص بك، مما يسمح لك بتوجيه المستخدم إلى الشاشة المناسبة في تطبيقك.
تتبع عمليات الشراء داخل التطبيق
Anchor link toبشكل افتراضي، يتم تعطيل تتبع عمليات الشراء داخل التطبيق. إذا كنت ترغب في تتبع عمليات الشراء داخل التطبيق عند تكوين Customer Journeys، فقم بتعيين علامة Pushwoosh_PURCHASE_TRACKING_ENABLED إلى true في ملف info.plist. يمكنك العثور على قائمة بالعلامات المتاحة في الجدول.
إذا كنت ترغب في تتبع عمليات الشراء داخل التطبيق يدويًا، يمكنك استخدام الكود أدناه.
في دالة التفويض paymentQueue:updatedTransactions:، استدعِ دالة sendSKPaymentTransactions من PushManager
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { // In-Apps Tracking Pushwoosh code here Pushwoosh.sharedInstance().sendSKPaymentTransactions(transactions) // the rest of the code, consume transactions, etc }- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
[[PushNotificationManager pushManager] sendSKPaymentTransactions:transactions];
//the rest of the code, consume transactions, etc}
إشعارات الدفع للمناطق الجغرافية (Geozones)
Anchor link toيتم تغليف إشعارات الدفع للمناطق الجغرافية (Geozones) في إطار عمل منفصل PushwooshGeozones.
- أضف PushwooshGeozones.framework إلى مشروعك
لإضافة PushwooshGeozones.framework إلى مشروعك باستخدام مدير التبعيات، ضع الأسطر التالية
في podfile أو cartfile الخاص بك:
pod 'PushwooshXCFramework/Geozones'github "Pushwoosh/pushwoosh-ios-sdk"إذا كنت ترغب في استخدام PushwooshGeozones.xcframework، أدخل عنوان URL الحزمة التالي:
PushwooshGeozones-XCFramework
بدلاً من ذلك، يمكنك ببساطة سحب وإفلات إطار العمل في Link Binaries With Libraries في Build Phases الخاصة بمشروعك.
- أضف المفاتيح التالية إلى Info.plist الخاص بك:
- NSLocationWhenInUseUsageDescription – (مطلوب) لكي يتتبع التطبيق المناطق الجغرافية (Geozones) فقط أثناء تشغيله في المقدمة.
- NSLocationAlwaysAndWhenInUseUsageDescription – (مطلوب) لكي يتتبع التطبيق المناطق الجغرافية (Geozones) في كل من المقدمة والخلفية ولإظهار نافذة منبثقة لطلب الإذن.
- NSLocationAlwaysUsageDescription – (اختياري) لكي يتتبع التطبيق المناطق الجغرافية (Geozones) في جميع الأوقات؛ يجب استخدامه إذا كان تطبيقك يستهدف iOS 10 والإصدارات الأقدم.
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key><string>for app to track Geozones in both conditions and to show a permission request dialog</string><key>NSLocationWhenInUseUsageDescription</key><string>for app to track Geozones only while running in the foreground</string>- استيراد إطار العمل
import PushwooshGeozones#import <PushwooshGeozones/PWGeozonesManager.h>- بدء تتبع المناطق الجغرافية (Geozones)
PWGeozonesManager.shared()?.startLocationTracking()[[PWGeozonesManager sharedManager] startLocationTracking];مثال
Anchor link tooverride func viewDidLoad() { super.viewDidLoad()
// Start Geozones tracking when needed PWGeozonesManager.shared().startLocationTracking()}- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view.
// Start Geozones tracking when needed [[PWGeozonesManager sharedManager] startLocationTracking];}إنشاء قائمة انتظار للوسائط الغنية (Rich Media)
Anchor link toفي حال وجود عدة صفحات وسائط غنية (Rich Media) لعرضها في وقت واحد (على سبيل المثال، تحدث أحداث التشغيل لاثنين أو أكثر من الرسائل داخل التطبيق في لحظة واحدة، أو يتم عرض صفحة وسائط غنية بالفعل في اللحظة التي يحدث فيها حدث تشغيل مختلف)، يمكنك إعداد قائمة انتظار لعرض صفحات الوسائط الغنية. لإنشاء قائمة انتظار، اتبع الخطوات الموضحة أدناه.
- أنشئ فئة تنفذ PWRichMediaPresentingDelegate:
@interface ChainedRichMediaPresentingDelegate () <PWRichMediaPresentingDelegate>
@property (nonatomic) NSMutableArray *queue;
@property (nonatomic) BOOL inAppIsPresenting;
@end
@implementation ChainedRichMediaPresentingDelegate
- (instancetype)init { self = [super init];
if (self) { _queue = [NSMutableArray new]; }
return self;}
- (BOOL)richMediaManager:(PWRichMediaManager *)richMediaManager shouldPresentRichMedia:(PWRichMedia *)richMedia { [_queue addObject:richMedia]; return !_inAppIsPresenting;}
- (void)richMediaManager:(PWRichMediaManager *)richMediaManager didPresentRichMedia:(PWRichMedia *)richMedia { _inAppIsPresenting = YES;}
- (void)richMediaManager:(PWRichMediaManager *)richMediaManager didCloseRichMedia:(PWRichMedia *)richMedia { _inAppIsPresenting = NO;
[_queue removeObject:richMedia];
if (_queue.count) { [[PWRichMediaManager sharedManager] presentRichMedia:_queue.firstObject]; }}
- (void)richMediaManager:(PWRichMediaManager *)richMediaManager presentingDidFailForRichMedia:(PWRichMedia *)richMedia withError:(NSError *)error { [self richMediaManager:richMediaManager didCloseRichMedia:richMedia];}
@end2. قم بتعيين المفوّض:
[PWRichMediaManager sharedManager].delegate = [ChainedRichMediaPresentingDelegate new];التشغيل التلقائي لفيديو مُرسل في إشعار غني (Rich Notification) باستخدام اللمس القوي (force touch)
Anchor link toلجعل الفيديو المرسل كمرفق إشعار غني (Rich Notification) يعمل تلقائيًا عند توسيع الإشعار دون أي تفاعل من المستخدم، اتبع الخطوات أدناه:
- أضف ملحق محتوى الإشعارات (Notification Content Extension) إلى مشروعك:
- في Xcode، حدد File > New > Target.
- اختر Notification Content Extension.
- قم بتعيين اسم له وأكمل الإعداد.

إذا طُلب منك رسالة “تفعيل المخطط”، اختر إلغاء.

- اضبط الخصائص والأساليب في ملحق المحتوى على النحو التالي:
import UIKitimport UserNotificationsimport UserNotificationsUIimport AVKit
class NotificationViewController: UIViewController, UNNotificationContentExtension { var playerController: AVPlayerViewController! @IBOutlet weak var playerBackgroundView: UIView!
override func viewDidLoad() { super.viewDidLoad() // Do any required interface initialization here. }
func didReceive(_ notification: UNNotification) { let attachment = notification.request.content.attachments.first
playerController = AVPlayerViewController() // Set height programmatically // preferredContentSize.height = 250
if let url = attachment?.url { setupVideoPlayer(url: url) } else { print("No valid URL...") } }
private func setupVideoPlayer(url: URL) { guard let playerController = self.playerController else { return } let player = AVPlayer(url: url) playerController.player = player playerController.view.frame = self.playerBackgroundView.bounds playerBackgroundView.addSubview(playerController.view) addChild(playerController) playerController.didMove(toParent: self) player.play() }- أدرج UIView في MainInterface.storyboard:

- اربط playerBackgroundView IBOutlet بـ UIView الذي أضفته للتو:

- قم بتحديث ملف info.plist بالإدخال التالي:
UNNotificationExtensionUserInteractionEnabled = true
لإرفاق فيديو بإشعارك، أدخل عنوان URL للفيديو في حقل مرفق الوسائط (Media Attachment) في لوحة التحكم (Control Panel):

عند إرسال إشعار عبر طلب API /createMessage، قم بتضمين عنوان URL في المعلمة “ios_attachment” وتأكد من تعيين علامة “mutable-content” على `1`.
صوت إشعار دفع مخصص
Anchor link toلتشغيل صوت مخصص عند تلقي إشعار دفع، ضع أولاً الملف الصوتي في المجلد الجذر لمشروعك.

بعد ذلك، حدد اسم ملف الصوت في معلمات الدفع – املأ حقل الصوت (Sound) في الإعدادات الخاصة بـ iOS لرسالتك أو حدد اسم الملف كقيمة لمعلمة “ios_sound” في طلب createMessage API.
يجب أن يكون الملف الصوتي للصوت المخصص لنظام iOS بأحد التنسيقات التالية: .aif، .caf، .wav. تأكد من تحديد التنسيق في اسم الملف؛ وإلا، سيتم تجاهله بواسطة Pushwoosh iOS SDK.
إشعارات الدفع المؤقتة لنظام iOS
Anchor link toكيف تعمل
Anchor link toتظهر إشعارات الدفع المؤقتة بصمت في مركز إشعارات المستخدم ولكن ليس على شاشة القفل. لا يحتاج هذا النوع من الإشعارات إلى موافقة صريحة من المستخدم: يمكنك البدء في إرسالها بمجرد أن يقوم المستخدم بتثبيت وتشغيل تطبيقك.
ومع ذلك، لا يزال بإمكان المستخدمين الاشتراك في إشعارات الدفع البارزة الخاصة بك: عند فتح الإشعار المؤقت، لديهم خياران لاختيار تجربتهم – إما إبقاء الإشعارات في مركز الإشعارات بدون تنبيهات وأصوات أو السماح لك بإرسال الإشعارات بشكل بارز بحيث تظهر على شاشة القفل.
تم تصميم الإشعارات المؤقتة للسماح للمستخدمين باتخاذ قرارات مستنيرة حول ما إذا كانوا يرغبون في تلقي إشعارات من تطبيقك. نظرًا لأن طلب الاشتراك الأصلي من APN يُعرض للمستخدمين مرة واحدة فقط وللاشتراك لاحقًا، يجب عليهم الانتقال إلى إعدادات النظام في هواتفهم، وقد لا يشترك بعض المستخدمين لأنهم لا يدركون القيمة التي يحصلون عليها من إشعاراتك. تمنح الإشعارات المؤقتة المستخدمين هذا الفهم: يمكنهم رؤية المحتوى الذي تقدمه في إشعارات الدفع وتحديد ما إذا كانوا بحاجة إلى إعلامهم بهذا المحتوى بشكل بارز.
كيفية التنفيذ
Anchor link to1. قم بدمج Pushwoosh iOS SDK باتباع الدليل.
2. أضف السلسلة التالية إلى AppDelegate الخاص بمشروعك قبل استدعاء دالة registerForPushNotifications():
if #available(iOS 12.0, *) { Pushwoosh.sharedInstance().additionalAuthorizationOptions = UNAuthorizationOptions.provisional}if (@available(iOS 12.0, *)) { [Pushwoosh sharedInstance].additionalAuthorizationOptions = UNAuthorizationOptionProvisional;}هذا كل شيء! سيتلقى مستخدمو التطبيق الرسائل مباشرة إلى مركز الإشعارات الخاص بهم بمجرد تثبيت التطبيق.
شاركنا ملاحظاتك
Anchor link toتساعدنا ملاحظاتك في إنشاء تجربة أفضل، لذلك نود أن نسمع منك إذا كان لديك أي مشاكل أثناء عملية دمج SDK. إذا واجهت أي صعوبات، فلا تتردد في مشاركة أفكارك معنا عبر هذا النموذج.