ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ios-Swift] Share Extension 사용하기
    ios 2021. 1. 27. 10:49

     

     

    이번 글에서는 Share Extension을 커스텀 뷰로 꾸며 사용하는 글입니다.

     

     

     

    1. 설정

     

    ShareExtensionExample 프로젝트를 생성한 후

     

    File -> Target -> Share Extension을 추가해 주도록 합니다.

     

     

     

     

    Extension -> App 간 데이터 사용은 동일한 그룹을 사용해야 데이터를 공유할 수 있는 것으로 알고 있어 그룹 설정을 먼저 하도록 하겠습니다.

     

    프로젝트의 Capacapabilities -> App Grouops를 선택 후 그룹을 설정해 주도록 합니다.

     

    그룹명은  group.Bundle identifier.Share를 사용했습니다.

     

     

     

    TARGETS -> 프로젝트에서 추가한 그룹을  셰어 익스텐션에서 체크해주도록 합니다.

     

    이제 그룹 설정이 완료되었습니다. 

     

     

     

    이제 우리는 커스텀 뷰에서 어떤 데이터를 받을 것 인지를 설정해야 하는데 Extension의 info.plist 에서 설정하겠습니다.

     

     

    NSExtensionActivationRule -> Dictionary로 변경 후 키와 밸류를 설정합니다.

     

    NSExtensionActivationSupportsWebURLWithMaxCount : 허용할 HTTP URL  최대 수 

    NSExtensionActivationSupportsImageWithMaxCount : 허용할 IMAGE  최대 수

     

    NSExtensionActivationRule의 키 값은 이곳에서 확인해 보시면 됩니다.

     

     

     

     

     

     

    2. 소스

     

    MainInterface.stroryboard에서 오브젝트들을 추가 및 ShareViewController에서 SLComposeServiceViewController -> UIViewController로 변경했습니다.

     

    import UIKit
    import Social
    
    class ShareViewController: UIViewController {
    
        override func viewDidLoad() {
        
        }
    }

     

     

    이제 앱이 아닌 익스텐션을 실행시켜 사파리 브라우저를 실행시키면 아래와 같이 커스텀 뷰가 나타나는 것을 확인할 수 있습니다.

     

     

     

     

    커스텀 뷰의 버튼 및 동작을 추가하도록 하겠습니다.

     

    import UIKit
    import Social
    import MobileCoreServices
    
    class ShareViewController: UIViewController {
    
        @IBOutlet weak var imageView: UIImageView!
        @IBOutlet weak var textView: UITextView!
        
        override func viewDidLoad() {
            let extensionItems = extensionContext?.inputItems as! [NSExtensionItem]
            
            for extensionItem in extensionItems {
                if let itemProviders = extensionItem.attachments as? [NSItemProvider] {
                    for itemProvider in itemProviders {
                        // 해당 객체가 있는지 식별
                        if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
                            itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil, completionHandler: { result, error in
                                var image: UIImage?
                                if result is UIImage {
                                    image = result as? UIImage
                                }
                                
                                if result is URL {
                                    let data = try? Data(contentsOf: result as! URL)
                                    image = UIImage(data: data!)!
                                }
                                
                                if result is Data {
                                    image = UIImage(data: result as! Data)!
                                }
                                
                                DispatchQueue.main.async {
                                    if let image = image {
                                        self.imageView.image = image
                                    }
                                }
                            })
                        }
                        
                        if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
                            itemProvider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil, completionHandler: { result, error in
                                let data = NSData.init(contentsOf:result as! URL)
                                DispatchQueue.main.async {
                                    if let urlStr = result {
                                        self.textView.text = "\(urlStr)"
                                    }
                                }
                            })
                        }
                    }
                }
            }
        }
    }

    kUTTypeImage 외 다른 타입도 많으니 필요하신 걸 찾아서 변경 후 사용하면 됩니다.

     

    kUTTypeImage as string는 "public.image"와 동일합니다. 

     

    // 익스텐션의 버튼 이벤트
    
    @IBAction func btnSend(_ sender: UIButton) {
        // 처리후 종료
        if let userDefaults = UserDefaults(suiteName: "위에서 설정한 그룹") {
            if let image = imageView.image {
                userDefaults.set(image.pngData(), forKey: "image")
            }
            
            if let text = textView.text {
                userDefaults.set(text, forKey: "text")
            }
        }
        
        self.hideExtensionWithCompletionHandler(completion: { _ in
            self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
        })
    }
        
    @IBAction func btnDismiss(_ sender: UIButton) {
        self.hideExtensionWithCompletionHandler(completion: { _ in
            self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
        })
    }
    
    func hideExtensionWithCompletionHandler(completion: @escaping (Bool) -> Void) {
        UIView.animate(withDuration: 0.3, animations: {
            self.navigationController?.view.transform = CGAffineTransform(translationX: 0, y:self.navigationController!.view.frame.size.height)
        }, completion: completion)
    }

    익스텐션 뷰를 닫으려고 해도 그냥 dismiss를 사용하면 뷰가 사라지지 않아 hideExtensionWithCompletionHandler를 사용하도록 합니다.

     

     

     

    //앱 뷰 컨트롤러
    
    import UIKit
    
    class ViewController: UIViewController {
        override func viewDidLoad() {
            if let userDefaults = UserDefaults(suiteName: "group.com.fostep.Share") {
                if let data = userDefaults.data(forKey: "image") {
                imageView.image = UIImage(data: data)
            }
    
            if let text = userDefaults.string(forKey: "text") {
                textLabel.text = text
            }
        }
    }
    

     

     

    익스텐션과 앱과의 데이터 전송은 UserDefaults를 사용해 저장 후 앱을 실행 UserDefaults를 확인하는 방식을 사용합니다.

     

    UserDefaults를 사용하지 않아도 되며 익스텐션에서 서버에 전송 후 받는 방법을 사용하셔도 될 겁니다.

     

     

     

     

     

    댓글

Designed by Tistory.