Share Extension — افزونه iOS است که برنامه شما را به منوی سیستمی «اشتراک» (Share Sheet) اضافه میکند. کاربر میتواند محتوا را از Safari، Photos، Files یا هر برنامه دیگری مستقیماً به برنامه شما ارسال کند — بدون کپیکردن و جابجایی بین پنجرهها. طبق دادههای Apple (2024)، برنامههای دارای Share Extension 35% بیشتر محتوای کاربری دریافت میکنند نسبت به برنامههای بدون امکان اشتراک. افزونه متن، تصاویر، ویدئو، URL و فایلها را از طریق رابط یکپارچه NSExtensionItem پردازش میکند.
نکات اصلی
Share Extension — نوعی افزونه iOS app extension است که در منوی سیستمی «اشتراک» هنگام انتخاب محتوا در هر برنامهای ظاهر میشود. کاربر متنی را در Safari انتخاب میکند، دکمه «اشتراک» را میزند و برنامه شما را در لیست اقدامات موجود میبیند. پس از انتخاب، محتوا برای پردازش به افزونه ارسال میشود: ذخیره، انتشار، ارسال یا تبدیل.
برخلاف Action Extension، Share Extension در دریافت محتوا از برنامههای خارجی تخصص دارد. Action Extension برعکس، دادهها را از برنامه شما به بیرون ارسال میکند. Share Extension نقطه ورود محتوای کاربری است، عنصر کلیدی جذب کاربر: کاربر برنامه را از طریق Share Extension امتحان میکند، بدون نصب کامل. App Store برنامههایی که تنها عملکردشان نمایش تبلیغات از طریق Share Extension است را ممنوع میکند (App Store Review Guideline 4.2).
Share Extension سد ورود را کاهش میدهد: کاربر محتوا را به برنامه شما از زمینه آشنا — مرورگر، گالری، مدیر فایل — ارسال میکند. طبق دادههای Branch (2024)، برنامههای دارای Share Extension در روز هفتم 28% retention بالاتر نشان میدهند. اثر اضافی — ویروسی بودن: هر بار که کاربر برنامه شما را در Share Sheet میبیند، برندینگ غیرفعال بدون هزینه تبلیغات رخ میدهد.
مکانیزم Share Extension بر اساس انتقال محتوا از طریق ظروف سیستمی NSExtensionItem است. برنامه میزبان (Safari، Photos) محتوای انتخابشده را با تعیین نوع (public.image، public.url، public.plain-text) در NSExtensionItem بستهبندی میکند. سیستم این ظرف را به افزونه منتقل میکند که دادهها را از طریق extensionContext.inputItems استخراج میکند.
Share Extension در فرآیندی جداگانه با زمان اجرای محدود — حدود 30 ثانیه برای پردازش — راهاندازی میشود. افزونه نباید عملیات طولانی را به صورت همزمان انجام دهد. برای بارگذاری فایلهای بزرگ از NSURLSession با پیکربندی پسزمینه استفاده کنید. SLComposeServiceViewController — کلاس پایه برای Share Extension با پیشنمایش محتوا و دکمه ارسال.
iOS از Uniform Type Identifiers (UTI) برای تعیین نوع محتوای منتقلشده استفاده میکند. UTIهای اصلی برای Share Extension: public.image (عکسها، اسکرینشاتها)، public.url (لینکها)، public.plain-text (متن)، public.video (فایلهای ویدئو) و public.file-url (فایلها). افزونه UTIهای پشتیبانیشده را در Info.plist از طریق کلید NSExtensionActivationRule ثبت میکند.
Share Extension از سه مؤلفه تشکیل شده است: target هدف در Xcode، SLComposeServiceViewController و پیکربندی Info.plist. معماری تعیین میکند که چه نوع محتوایی پردازش میشود، رابط چگونه نمایش داده میشود و دادهها کجا ذخیره میشوند.
| مؤلفه | هدف | ویژگیها |
|---|---|---|
| Target | هدف افزونه در Xcode | bundle جداگانه با شناسه |
| ViewController | رابط و منطق پردازش | SLComposeServiceViewController یا سفارشی |
| Info.plist | پیکربندی فعالسازی و UTI | NSExtensionActivationRule با گزارهها |
| App Groups | ذخیرهسازی مشترک با برنامه | UserDefaults suite برای انتقال داده |
عنصر کلیدی پیکربندی Share Extension — قانون فعالسازی. تعیین میکند که افزونه در چه شرایطی در Share Sheet ظاهر میشود. قانون در Info.plist به عنوان دیکشنری با محدودیتها تعریف میشود: حداکثر تعداد تصاویر، حداقل طول متن، وجود اجباری URL. قانون استاندارد افزونه را برای هر نوع محتوایی فعال میکند.
// Info.plist — NSExtensionActivationRule برای Share Extension
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>5</integer>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
بیایید یک مثال عملی از ایجاد Share Extension به زبان Swift برای یک برنامه نشانکگذاری بررسی کنیم. افزونه URL را از Safari دریافت میکند، رابطی با پیشنمایش نشان میدهد و لینک را در App Group ذخیره میکند. SLComposeServiceViewController رابط آماده با فیلد متنی و دکمه Post فراهم میکند.
import Social
import MobileCoreServices
class ShareViewController: SLComposeServiceViewController {
override func isContentValid() -> Bool {
return !(contentText?.isEmpty() ?? true)
}
override func didSelectPost() {
guard let item = extensionContext?.inputItems.first as? NSExtensionItem
else { return }
for attachment in item.attachments ?? [] {
attachment.loadItem(forTypeIdentifier: kUTTypeURL as String) {
[weak self] (item, error) in
if let url = item as? URL {
BookmarkService().save(url, title: self?.contentText)
}
self?.extensionContext?.completeRequest(
returningItems: [], completionHandler: nil)
}
}
}
}
پس از ارسال محتوا، افزونه با فراخوانی completeRequest کار خود را پایان میدهد — این یک مرحله اجباری است، بدون آن سیستم فرآیند افزونه را آزاد نمیکند. مهم: Share Extension در محیط محدودی با دسترسی محدود به شبکه و سیستم فایل کار میکند — از جلسات پسزمینه برای بارگذاری محتوا استفاده کنید.
Share Extension باید انواع مختلف دادههای ورودی را به درستی پردازش کند: متن، تصاویر، ویدئو، URL و فایلها. برای هر نوع از UTI و روش استخراج داده خاص خود استفاده میشود. پردازش جهانی — از طریق حلقه روی attachment.attachments با بررسی hasItemConformingToTypeIdentifier.
تصاویر به عنوان public.image با امکان دریافت از طریق UIImage یا Data منتقل میشوند. برای تصاویر بزرگ قبل از ذخیره از jpegData(compressionQuality:) استفاده کنید. Share Extension نباید تصویر اصلی را بدون اجازه صریح کاربر تغییر دهد. توصیه میشود اصل را در App Group ذخیره کرده و پیشنمایشی برای نمایش در رابط ایجاد کنید.
Safari و سایر مرورگرها URL را به عنوان public.url و متن انتخابشده را به عنوان public.plain-text ارسال میکنند. یک NSExtensionItem میتواند هر دو نوع را همزمان داشته باشد — URL صفحه و متن انتخابشده روی آن. Share Extension باید تمام attachmentها را بررسی کرده و دادههای مرتبط را استخراج کند. سناریوی ترکیبی: ذخیره URL به عنوان نشانک و متن به عنوان یادداشت برای آن.
Share Extension و برنامه اصلی در فرآیندهای مختلفی کار میکنند و دسترسی مشترکی به سیستم فایل ندارند. برای تبادل داده از مکانیزم App Groups استفاده میشود: ظرف مشترک با شناسه group.*. پس از ذخیره دادهها در App Group، افزونه برنامه را از طریق CFNotificationCenter یا Darwin Notify مطلع میکند.
App Groups در Capabilities target فعال میشود: «App Groups» را انتخاب کرده و شناسه اضافه کنید (مثلاً group.com.example.myapp). هر دو target — برنامه اصلی و افزونه — باید به یک گروه دسترسی داشته باشند. UserDefaults suite امکان خواندن و نوشتن دادهها در ذخیرهسازی مشترک با حداقل سربار را فراهم میکند.
// ذخیره دادهها در App Group از Share Extension
let sharedDefaults = UserDefaults(suiteName: "group.com.example.myapp")
let bookmark: [String: Any] = [
"url": url.absoluteString,
"title": contentText ?? "",
"date": Date().timeIntervalSince1970
]
sharedDefaults?.set(bookmark, forKey: "bookmark_\(Date().timeIntervalSince1970)")
sharedDefaults?.synchronize()
سؤالات متداول
Share Extension محتوا را از برنامههای دیگر به برنامه شما دریافت میکند. Action Extension برعکس، روی محتوا در داخل برنامه میزبان عمل میکند — ترجمه متن، تغییر تصویر. Share Extension — دریافت، Action Extension — تبدیل.
به نوع محتوای برنامه شما بستگی دارد. برای نشانکها — public.url. برای ویرایشگر عکس — public.image. برای یادداشتها — public.plain-text. برای چند نوع از NSExtensionActivationRule با ترکیب گزارههای AND/OR استفاده کنید.
علت رایج — NSExtensionActivationRule نادرست یا عدم تطابق UTI. در Info.plist بررسی کنید: قانون فعالسازی باید با نوع محتوای آزمایششده مطابقت داشته باشد. همچنین مطمئن شوید که افزونه در Settings → برنامه شما → Siri & Search فعال است. Xcode clean build اغلب مشکل را حل میکند.
سیستم حدود 30 ثانیه برای اجرا اختصاص میدهد. پس از آن iOS فرآیند افزونه را به اجبار پایان میدهد. برای عملیات طولانی از NSURLSession پسزمینه با پردازش نتیجه در راهاندازی بعدی برنامه استفاده کنید.
بله، به جای SLComposeServiceViewController میتوان از UIViewController معمولی استفاده کرد. در این صورت رابط را کاملاً کنترل میکنید. اما دکمههای ارسال و لغو باید خودتان پیادهسازی کنید. رابط سفارشی برای سناریوهای غیراستاندارد پردازش محتوا توصیه میشود.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید