Extension

IOS/공통 2017. 8. 31. 15:31

Introduction
: Extension은 앱과 다르다. Extension의 바이너리는 Extension포함 또는 배포하는 앱과는 별개로 실행된다. 


An App Extension's Life Cycle
: extension은 App이 아니기 때문에, App의 Life cycle과 다르다. 대부분의 경우 사용자가 사용중인 앱에서 Extension을 사용하려고 할때 Extension이 Launch 된다.
즉, App 에서 실행될 Extension에 request를 보내면 Extension이 Launch, Extension code가 실행되고 해당동작이 끝나면 시스템이 extension을 kill한다.


How an App Extension Communicates
: Host app(extension을 사용하는 앱)이 Extension에게 Request를 날리면, Extension이 해당 처리를 하고 Host app에게 response를 날리는 형식이다. 

<Containing app - Extension을 소유하고 있는 앱> 

containing app과 host app은 전혀 communication 하지 않는다. 심지어 대부분의 경우 extension이 실행 될때 containing app이 실행되지 않는다.

다만, Today widget과 같은 몇몇 extension은 NSExtensionContext의 openURL:completionHandler: 메서드를 통해 containing app을 열 수 있다. 그리고 containing app은 필요한 경우 app extension과 shared resource가 저장된 공통의 private한 저장소를 공유할 수 있다. 아래 그림을 보자.



Some APIs Are Unavailable to App Extensions
: 몇몇 API들은 extension에서 사용할 수 없다.

- sharedApplication 객체를 아예 사용 못함
- API의 헤더파일에 "NS_EXTENSION_UNAVAILABLE" 또는 비슷한 의미의 매크로가 붙은 것은 사용 불가. (ex- in iOS 8에서 HealthKit Framework, EventKit UI Framework)
- camera, microphone 을 접근할 수 없다. (다만, iMessage app은 camera, microphone을 사용할 수 있다. 그 대신 Info.plist에 NSCameraUsageDescription, NSMicrophoneUsageDescription을 세팅해야 한다.)
- 장시간 걸리는 background task는 수행할 수 없다. (limit 정책은 플랫폼에 따라 다양하다. 나중에 언급하도록 하겠다. 그리고 extension은 NSURLSession을 통해 upload, download 작업을 할 수 있다.)
- AirDrop을 통해서 data를 받을 수 없다. (다만, UIActivityViewController class를 통해서 AirDrop으로 data를 보내는 것은 가능하다.)
 UIBackgroundModes를 extension의 plist에 포함하면 reject 당한다.


Using an Embedded Framework to Share Code
: containing app 과 extension이 코드를 공유하기를 원한다면 embed framework에 해당 코드를 넣고 embed framework를 양쪽 타겟에 포함시키면 된다.
단, embed framework에는 extension에서 사용할 수 없는 API들을 포함 시키면 안된다. 
그리고 extension target의 "Require Only App-Extension-Safe API"를 YES로 세팅해야 한다. 
또한, build phase 탭의 Embed Frameworks의 Destination을 "Frameworks"로 지정해야 한다. "SharedFramework"로 지정할 경우 앱 심사에서 reject 당한다. 


Sharing Data with Your Containing App
: app extension과 containing app은 기본적으로 서로의 container에 접근하지 못한다. 그러나 서로의 데이터를 공유하기 위한 방법이 있다.

- xCode 또는 Developer portal에서 app groups을 enable 시킨다.
- appGroup을 등록하고, containing app이 appGroup을 사용하도록 지정한다.
- 위 두단계를 거치면, containing app과 extension은 NSUserDefaults를 사용하여 data를 공유할 수 있다. UserDefaults를 init할때 shared group의 identifier로 init 해야 한다. 

NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.example.domain.MyShareExtension"];

[mySharedDefaults setObject:theAccountName forKey:@"lastAccountName"];

* extension에서 NSURLSession을 사용하여 background upload, download를 하려면 shared container를 setup 해야한다. 그래야만 extension과 containing app 모두가 전송되는 data에 접근할 수 있다. (https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW2)

*Version Note
in IOS 8.2 and later, you can alternatively employ the UIDocument class to coordinate shared data access.

in IOS 9 and later, you can employ the NSFileCoordinator class directly for shared data access, but if you do this you must remove your NSFilePresenter objects when your app extension transitions into the background.


Accessing a Webpage
: Share extension, action extension에서 javaScript 파일을 통해서 web contents 들을 extension 으로 받아올 수 있다. 예를 들면, Share extension을 통해서 web content를 자신의 앱에 공유하는 기능을 추가할 수 있다는 것이다.(https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1)


Declaring Supported Data Types for a Share or Action Extension
: Share 또는 Action extension에서 host app이 extension에 data를 넘겨주는데, extension 에서 넘겨받기를 원하는 data type을 지정할 수 있다. extension의 Info.plist의 NSExtensionActivationRule key로 지정한다. 또한 해당 타입 data의 max, min 갯수도 지정할 수 있다. 

  1. <key>NSExtensionAttributes</key>
  2. <dict>
  3. <key>NSExtensionActivationRule</key>
  4. <dict>
  5. <key>NSExtensionActivationSupportsImageWithMaxCount</key>
  6. <integer>10</integer>
  7. <key>NSExtensionActivationSupportsMovieWithMaxCount</key>
  8. <integer>1</integer>
  9. <key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
  10. <integer>1</integer>
  11. </dict>
  12. </dict>
  13. 특정 data type을 지원하지 않으려면 0값을 세팅하거나 해당 데이터 타입의 key, value
  14. 를 삭제하면 된다.

* Share 또는 Action Extension에서 webpage에 접근하기를 원한다면 NSExtensionActivationSupportsWebPageWithMaxCount key의 값을 지정하면 된다.

위의 NSExtensionActivationRule dictionary에 값을 지정하는 것만으로도 충분히 타입지원을 할 수 있지만, 좀 더 세밀하게 컨트롤하고 싶을 경우 "predicate statement"(NSPredicate) 문법을 통해 지원할 수 있다.(https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1)



Deploying a Containing App to Older Versions of iOS
- https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1(맨 아래 참고)


* 각 extension type에 대한 설명
- https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Action.html#//apple_ref/doc/uid/TP40014214-CH13-SW1

'IOS > 공통' 카테고리의 다른 글

Bundle Programming Guide  (0) 2017.06.11
Event Handling Guide - Responders  (0) 2017.05.03
Event Handling Guide - Gesture  (0) 2017.04.07
Objective-C, Swift 기초  (0) 2017.03.26
Cocoa Pods  (0) 2017.02.19
Posted by 홍성곤
,