تخصيص iOS SDK
التكامل
Anchor link to- الروابط العميقة (Deep linking)
- الروابط الشاملة (Universal Links)
- تتبع عمليات الشراء داخل التطبيق
- إشعارات Geozones الفورية
- إنشاء قائمة انتظار للوسائط الغنية (Rich Media)
- التشغيل التلقائي لفيديو مُرسل في إشعار وسائط غنية مع اللمس القوي (force touch)
- صوت إشعار مخصص
- إشعارات iOS المؤقتة (Provisional Push)
الروابط العميقة (Deep linking)
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}الروابط الشاملة (Universal Links)
Anchor link toتسمح الروابط الشاملة للمستخدمين بفتح تطبيقك مباشرة عند النقر على رابط لموقعك الإلكتروني. على عكس مخططات URL المخصصة، تستخدم الروابط الشاملة عناوين URL قياسية https:// وتوفر تجربة مستخدم أكثر سلاسة.
كيف تعمل
Anchor link toعندما يحتوي إشعار فوري على عنوان URL https:// (في المعلمة “url” أو “l”)، سيقوم SDK بما يلي:
- إنشاء
NSUserActivityمع عنوان URL - استدعاء معالج الروابط الشاملة في تطبيقك (
scene:continueUserActivity:أوapplication:continueUserActivity:restorationHandler:) - إذا لم يتعامل تطبيقك مع عنوان URL، فسيتم فتحه في Safari كحل بديل
الإعداد
Anchor link to- تكوين النطاقات المرتبطة في Xcode
أضف قدرة النطاقات المرتبطة إلى تطبيقك وأضف نطاقك:
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في حالة وجود عدة صفحات وسائط غنية لعرضها في وقت واحد (على سبيل المثال، تحدث أحداث التشغيل لاثنين أو أكثر من In-Apps في لحظة واحدة، أو يتم عرض صفحة وسائط غنية بالفعل في اللحظة التي يحدث فيها حدث تشغيل مختلف)، يمكنك إعداد قائمة انتظار لعرض صفحات الوسائط الغنية. لإنشاء قائمة انتظار، اتبع الخطوات الموضحة أدناه.
- أنشئ فئة تنفذ 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];التشغيل التلقائي لفيديو مُرسل في إشعار وسائط غنية مع اللمس القوي (force touch)
Anchor link toلجعل الفيديو المرسل كمرفق إشعار وسائط غنية يتم تشغيله تلقائيًا عند توسيع الإشعار دون أي تفاعل من المستخدم، اتبع الخطوات أدناه:
- أضف ملحق محتوى الإشعارات (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 للفيديو في حقل مرفق الوسائط في لوحة التحكم:

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

بعد ذلك، حدد اسم ملف الصوت في معلمات الإشعار - املأ حقل الصوت في الإعدادات الخاصة بـ iOS لرسالتك أو حدد اسم الملف كقيمة لمعلمة “ios_sound” في طلب API createMessage.
يجب أن يكون الملف الصوتي للصوت المخصص لنظام iOS بأحد التنسيقات التالية: .aif، .caf، .wav. تأكد من تحديد التنسيق في اسم الملف؛ وإلا، سيتم تجاهله بواسطة Pushwoosh iOS SDK.
إشعارات iOS المؤقتة (Provisional Push)
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. إذا واجهت أي صعوبات، فلا تتردد في مشاركة أفكارك معنا عبر هذا النموذج.