Share Extension은 시스템 공유 시트에 앱을 추가하는 iOS 확장 기능입니다. 사용자는 Safari, 사진, 파일 또는 다른 앱에서 콘텐츠를 복사하거나 창 간 전환 없이 직접 앱으로 보낼 수 있습니다. Apple(2024)에 따르면, Share Extension이 있는 앱은 공유 기능이 없는 앱보다 35% 더 많은 사용자 콘텐츠를 받습니다. 확장은 통합된 NSExtensionItem 인터페이스를 통해 텍스트, 이미지, 비디오, URL 및 파일을 처리합니다.
핵심 사항
Share Extension은 앱에서 콘텐츠를 선택할 때 시스템 공유 시트에 나타나는 iOS 앱 확장 유형입니다. 사용자가 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이 있는 앱은 7일차 유지율이 28% 더 높습니다. 추가 효과는 바이럴성입니다. 사용자가 공유 시트에서 앱을 볼 때마다 광고 비용 없이 수동적 브랜딩이 발생합니다.
Share Extension 메커니즘은 시스템 NSExtensionItem 컨테이너를 통한 콘텐츠 전송을 기반으로 합니다. 호스트 앱(Safari, 사진)은 선택한 콘텐츠를 지정된 유형(public.image, public.url, public.plain-text)으로 NSExtensionItem에 패키징합니다. 시스템은 이 컨테이너를 확장에 전달하고, 확장은 extensionContext.inputItems를 통해 데이터를 추출합니다.
Share Extension은 제한된 실행 시간(약 30초)으로 별도 프로세스에서 실행됩니다. 확장은 긴 동기 작업을 수행해서는 안 됩니다. 큰 파일 업로드를 위해 백그라운드 구성으로 NSURLSession을 사용하세요. SLComposeServiceViewController는 콘텐츠 미리보기 및 게시 버튼이 있는 Share Extension의 기본 클래스입니다.
iOS는 전송되는 콘텐츠 유형을 결정하기 위해 Uniform Type Identifiers(UTI)를 사용합니다. Share Extension의 주요 UTI: public.image(사진, 스크린샷), public.url(링크), public.plain-text(텍스트), public.video(비디오 파일), public.file-url(파일). 확장은 NSExtensionActivationRule 키를 통해 Info.plist에서 지원되는 UTI를 등록합니다.
Share Extension은 Xcode의 타겟, SLComposeServiceViewController 및 Info.plist 구성의 세 가지 구성 요소로 이루어집니다. 아키텍처는 처리할 콘텐츠 유형, 인터페이스 표시 방식 및 데이터 저장 위치를 결정합니다.
| 구성 요소 | 목적 | 특징 |
|---|---|---|
| Target | Xcode의 확장 타겟 | 식별자가 있는 별도 번들 |
| ViewController | 인터페이스 및 처리 로직 | SLComposeServiceViewController 또는 사용자 정의 |
| Info.plist | 활성화 및 UTI 구성 | 술어가 있는 NSExtensionActivationRule |
| App Groups | 앱과의 공유 저장소 | 데이터 전송을 위한 UserDefaults 스위트 |
Share Extension 구성의 핵심 요소는 활성화 규칙입니다. 확장이 공유 시트에 나타나는 조건을 결정합니다. 규칙은 Info.plist에서 제약 조건이 있는 딕셔너리로 설정됩니다: 최대 이미지 수, 최소 텍스트 길이, 필수 URL 존재 여부. 표준 규칙은 단일 콘텐츠 유형에 대해 확장을 활성화합니다.
// Info.plist — Share Extension용 NSExtensionActivationRule
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>5</integer>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
북마킹 앱용 Swift로 Share Extension을 만드는 실제 예제를 살펴보겠습니다. 확장은 Safari에서 URL을 수신하고, 미리보기 인터페이스를 표시하며, 링크를 App Group에 저장합니다. SLComposeServiceViewController는 텍스트 필드와 게시 버튼이 있는 준비된 UI를 제공합니다.
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와 추출 방법을 사용합니다. 범용 처리 — hasItemConformingToTypeIdentifier 확인과 함께 attachment.attachments를 반복합니다.
이미지는 public.image로 전달되며 UIImage 또는 Data를 통해 검색할 수 있습니다. 큰 이미지의 경우 저장하기 전에 jpegData(compressionQuality:)를 사용하세요. Share Extension은 사용자의 명시적 허가 없이 원본 이미지를 수정해서는 안 됩니다. 원본을 App Group에 저장하고 인터페이스에 표시할 미리보기를 만드는 것이 좋습니다.
Safari 및 다른 브라우저는 URL을 public.url로, 선택한 텍스트를 public.plain-text로 전달합니다. 단일 NSExtensionItem에는 페이지 URL과 그 위에서 선택된 텍스트를 동시에 포함할 수 있습니다. Share Extension은 모든 첨부 파일을 확인하고 관련 데이터를 추출해야 합니다. 결합 시나리오: URL을 북마크로 저장하고 텍스트를 첨부 노트로 저장합니다.
Share Extension과 메인 앱은 별도 프로세스에서 실행되며 파일 시스템에 대한 공유 액세스 권한이 없습니다. 데이터 교환은 group.* 식별자가 있는 공유 컨테이너인 App Groups 메커니즘을 사용합니다. App Group에 데이터를 저장한 후 확장은 CFNotificationCenter 또는 Darwin Notify를 통해 앱에 알립니다.
App Groups은 타겟의 Capabilities에서 활성화됩니다. App Groups을 선택하고 식별자를 추가합니다(예: group.com.example.myapp). 메인 앱과 확장 모두 동일한 그룹에 액세스할 수 있어야 합니다. UserDefaults 스위트는 최소 오버헤드로 공유 저장소에서 데이터를 읽고 쓸 수 있게 합니다.
// Share Extension에서 App Group으로 데이터 저장
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입니다. 여러 유형의 경우 AND/OR 술어 조합과 함께 NSExtensionActivationRule을 사용하세요.
일반적인 원인은 잘못된 NSExtensionActivationRule 또는 UTI 불일치입니다. Info.plist에서 활성화 규칙이 테스트하는 콘텐츠 유형과 일치하는지 확인하세요. 또한 설정 → 앱 → Siri 및 검색에서 확장이 활성화되어 있는지 확인하세요. Xcode 클린 빌드가 문제를 해결하는 경우가 많습니다.
시스템은 실행에 약 30초를 할당합니다. 그 후 iOS는 강제로 확장 프로세스를 종료합니다. 장기 실행 작업의 경우 백그라운드 NSURLSession을 사용하고 다음 앱 실행 시 결과를 처리하세요.
네, SLComposeServiceViewController 대신 일반 UIViewController를 사용할 수 있습니다. 이 경우 인터페이스를 완전히 제어할 수 있습니다. 그러나 보내기 및 취소 버튼을 직접 구현해야 합니다. 사용자 정의 UI는 비표준 콘텐츠 처리 시나리오에 권장됩니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.