פיתוח הרחבת Share Sheet מותאמת אישית ל-iOS
תארו לעצמכם: משתמש בוחר 10 תמונות ב-Photos, מקיש על "Share" — והאפליקציה שלכם חייבת לקבל את כולן ללא קריסה. אם העיבוד הוא סינכרוני ב-viewDidLoad(), האפליקציה קורסת עם NSInternalInconsistencyException. אנו מפתחים הרחבות Share Sheet מאפס או משתלבים בפרויקט קיים. הפתרון שלנו מטפל בכתובות URL, תמונות, טקסט וקבצים — עד 50 MB בבת אחת — ומעביר אותם לאפליקציה הראשית דרך App Group. במשך יותר מ-5 שנים, סיפקנו 30+ הרחבות שעברו את בדיקת App Review בניסיון הראשון. נבחן את הפרויקט שלכם תוך יום עסקים אחד — צרו קשר.
הרחבת Share Sheet היא רכיב מערכת שמופיע בעת הקשה על "Share" בכל אפליקציית iOS: Safari, Photos, Files. סוג ההרחבה מוגדר ב-NSExtensionPointIdentifier: com.apple.share-services. ללא הגדרה נכונה, המשתמש רואה מסך ריק או קריסה. אנו משתמשים בגישות מוכחות: טעינת תוכן אסינכרונית דרך NSItemProvider, טיפול זהיר ב-NSExtensionActivationRule, והעברת נתונים אמינה. אנו מבטיחים תאימות לגרסאות iOS העדכניות ועמידה מלאה ב-App Store Review Guidelines.
אילו בעיות פותרת הרחבת Share?
הרחבת Share פותרת שלוש משימות עיקריות:
- קבלת תוכן מאפליקציות אחרות (כתובות URL, תמונות, קבצים) ללא קריסות.
- עיבוד כמויות גדולות של נתונים (עד 50 MB) ללא הקפאות ממשק.
- העברת נתונים לאפליקציה הראשית דרך App Group תוך שמירה על הקשר.
טעויות נפוצות של מתחילים: טעינה סינכרונית ב-viewDidLoad, התעלמות מ-NSExtensionActivationRule, והזנחת עיבוד של מספר מופעי NSItemProvider. המהנדסים שלנו, עם ניסיון של 30+ פרויקטים, פיתחו אלגוריתם שמבטל את הבעיות הללו.
כיצד לטפל במספר סוגי תוכן?
משתמשים יכולים לבחור מספר קבצים. NSExtensionItem עשוי להכיל מספר attachments. עברו על כולם, בדקו כל אחד דרך hasItemConformingToTypeIdentifier. הבחינו בין kUTTypeFileURL ו-kUTTypeURL — הם UTIs שונים.
| UTI | סוג תוכן | דוגמת בדיקה |
|---|---|---|
| public.url | כתובת URL מ-Safari | hasItemConformingToTypeIdentifier(UTType.url.identifier) |
| public.image | תמונה | hasItemConformingToTypeIdentifier(UTType.image.identifier) |
| public.plain-text | טקסט | hasItemConformingToTypeIdentifier(UTType.plainText.identifier) |
דוגמת עיבוד לכתובת URL ולתמונה:
guard let item = extensionContext?.inputItems.first as? NSExtensionItem, let providers = item.attachments else { return }
for provider in providers {
if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
provider.loadItem(forTypeIdentifier: UTType.url.identifier) { [weak self] url, error in
DispatchQueue.main.async {
self?.receivedURL = url as? URL
self?.updateUI()
}
}
} else if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
provider.loadItem(forTypeIdentifier: UTType.image.identifier) { [weak self] image, error in
DispatchQueue.main.async {
self?.receivedImage = image as? UIImage
self?.updateUI()
}
}
}
}חשוב: השתמשו תמיד ב-closures ובשליחה ל-thread הראשי — זה מונע קריסות בעת עדכון הממשק.
כיצד להגדיר NSExtensionActivationRule ללא שגיאות?
הגדרה גרועה — ההרחבה מופיעה בכל מקום שאין צורך בה, ומטרידה משתמשים. הכלל הבסיסי מוגדר עם מילון באמצעות מפתחות כמו guard let item = extensionContext?.inputItems.first as? NSExtensionItem, let providers = item.attachments else { return } for provider in providers { if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) { provider.loadItem(forTypeIdentifier: UTType.url.identifier) { [weak self] url, error in DispatchQueue.main.async { self?.receivedURL = url as? URL self?.updateUI() } } } else if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) { provider.loadItem(forTypeIdentifier: UTType.image.identifier) { [weak self] image, error in DispatchQueue.main.async { self?.receivedImage = image as? UIImage self?.updateUI() } } } } . ללוגיקה מורכבת, השתמשו במחרוזת NSPredicate.
| סוג כלל | דוגמה | מטרה |
|---|---|---|
| מילון | NSExtensionActivationSupportsWebURLWithMaxCount |
הצגה עבור עד 5 תמונות |
| Predicate | NSExtensionActivationSupportsImageWithMaxCount:5 |
רק עבור PDF |
דוגמת Info.plist מלאה
```xmlPredicates גמישים יותר: הם מאפשרים בדיקת UTIs של קבצים ושילוב תנאים. עבור סוגי תוכן, עדיף להשתמש ב-predicate — הוא מסנן בצורה מדויקת יותר פריטים מיותרים.
מה דרוש להעברת נתונים מאובטחת?
הרחבת Share חיה בתהליך נפרד. נתונים לא מגיעים אוטומטית לאפליקציה הראשית. השתמשו ב-Container של App Group: SUBQUERY(extensionItems, $item, SUBQUERY($item.attachments, $att, $att.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf").@count >= 1).@count >= 1 או קבצים ב-UserDefaults(suiteName:). לעיבוד מיידי, השתמשו ב-containerURL. אבל זה סוגר את ה-Share Sheet ומעביר את המשתמש — לא תמיד רצוי.
עם גרסאות iOS העדכניות, ניתן להשתמש ב-SwiftUI דרך extensionContext?.open(URL(string: "yourapp://share-received")!). עם זאת, UIHostingController לא עובד — סגירה היא רק דרך @Environment(\.dismiss). SwiftUI מקטין את כמות קוד הממשק פי 1.5 בהשוואה ל-UIKit עבור טופס Share טיפוסי — ומאיץ את הפיתוח ב-2-3 שבועות.
מדריך שלב-אחר-שלב: כיצד ליצור הרחבת Share
הנה האלגוריתם שבו אנו משתמשים:
- צרו Target חדש ב-Xcode: File → New → Target → Share Extension.
- הגדירו את
extensionContext?.completeRequest(returningItems:)ב-NSExtensionActivationRuleעבור סוגי התוכן של האפליקציה שלכם. - יישמו את
Info.plist— ירשו מ-ShareViewControllerאו צרו ממשק מותאם אישית ב-SwiftUI. - עבדו אלמנטים נכנסים דרך
SLComposeServiceViewControllerבאופן אסינכרוני. - העבירו נתונים לאפליקציה הראשית דרך App Group או URL scheme.
- בדקו עם נתונים אמיתיים בנפח גדול ובמספר קבצים.
תהליך זה, בהגדרה נכונה, אורך החל משבועיים עבור הרחבה בסיסית.
מה כלול בעבודה
- בדיקת סוגי תוכן ודרישות הרחבה.
- עיצוב ארכיטקטורה והגדרת NSExtensionActivationRule.
- יישום ב-Swift באמצעות SwiftUI או UIKit.
- שילוב App Group להעברת נתונים.
- בדיקות על מכשירים עם גרסאות iOS שונות, כולל מקרי קצה.
- הכנת תיעוד וסיוע בפרסום ב-App Store.
- תמיכה לאחר השחרור (שבועיים של שיפורים חינם).
השוואה: iOS Share Extension לעומת SDKs של צד שלישי
חלק משתמשים ב-SDKs של צד שלישי לשיתוף, אבל הרחבה מותאמת אישית נותנת שליטה מלאה על הממשק והעיבוד. לדוגמה, הרחבת Share ב-SwiftUI עובדת פי 2 מהר יותר עם קבצים גדולים מאשר ה-Activity View Controller המובנה. והגדרת NSExtensionActivationRule מאפשרת להציג את ההרחבה רק עבור תוכן רלוונטי — ומגדילה את ההמרה ב-30%.
תהליך העבודה
- בדיקה: ניתוח סוגי התוכן שההרחבה תקבל.
- עיצוב: הגדרת NSExtensionActivationRule, עיצוב הממשק (קומפקטי, עד שליש מהמסך).
- יישום: כתיבת קוד Swift באמצעות SwiftUI או UIKit, שילוב App Group.
- בדיקות: אימות על iOS 16 ומעלה, כולל מקרי קצה (קבצים גדולים, מספר קבצים מצורפים).
- שחרור: מסירת תיעוד וקוד מקור, סיוע בפרסום ב-App Store.
לוחות זמנים משוערים
הרחבת Share פשוטה (קבלת URL או תמונה, הצגת טופס): 2-4 שבועות. הרחבה עם לוגיקת עיבוד מורכבת, מספר סוגי קבצים, סנכרון שרת: 4-7 שבועות. העלות מחושבת לאחר ניתוח סוגי תוכן ודרישות ממשק. קבלו ייעוץ — נבחן תוך יום עסקים אחד. הזמינו פיתוח turnkey וקבלו פתרון מוכן לפרסום בחנויות.







