###### tags: `第14屆IT邦鐵人賽文章` # 【在 iOS 開發路上的大小事2-Day17】Application Extension 簡介  ## 前情提要 Application Extension 是從 iOS 8 開始出現的一種使用者互動介面 Extension 顧名思義就是擴展的意思,而 Application Extension 就是 App 的擴展 所以說 Application Extension 本身並不是單獨一個 App,而是需要仰賴 App 才能運作的 而 Application Extension 本身的 LifeCycle (生命週期) 也跟一般 App 不同 有些是需要使用者手動啟動,有些則是可以在各個 App 中被啟動 像是鍵盤輸入法 (Custom Keyboard Extension)、密碼自動填入 (AutoFill Credential Provider) 等就是需要使用者手動去啟動 而 Share Extension、Action Extension 這兩個則是可以在各個 App 中被啟動 ## LifeCycle 生命週期 前面有說到 Application Extension 的 LifeCycle 跟一般 App 是不一樣的 讓我們來看一下 Application Extension 是怎麼運作的  ▲ 圖取自 [Apple Developer Documentation](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html) 1. 使用者啟動 Application Extension 2. 系統啟動 Application Extension 3. 執行 Application Extension 內的程式 4. 系統關閉 Application Extension ## 與 App 之間的溝通 開頭有說到 Application Extension 是需要依賴 App 本體才能運作 既然是這樣,那麼 Application Extension 跟 App 也是可以相互溝通的 讓我們來看一下 Application Extension 跟 App 之間是怎麼相互溝通 ### 簡單版  ▲ 圖取自 [Apple Developer Documentation](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html) ### 進階版  ▲ 圖取自 [Apple Developer Documentation](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html) ### 名詞解說 ``` Containing App:App 本體 App Extension:Containing App 的擴展,需依賴於 Containing App Host App:呼叫 App Extension 的 App ``` 在簡單版中,可以看到 Host App 呼叫的是 App Extension 而不是 Containing App App Extension 與 Host App兩者之間可以進行 Request 跟 Response 溝通 而 App Extension 與 Containing App 之間以虛線標示是因為 App Extension 執行的時候 Containing App 是可以不用執行的 也就是 App Extension 與 Containing App 之間是可以不用有溝通的 接著,我們來看進階版,App Extension 與 Host App 之間的溝通一樣 但與 Containing App 之間卻不一樣了,兩者之間多了 ```Open URL```、```Shared resources``` 互動 #### Open URL 首先是 Open URL,這個是只有 Widget Extension 才能使用 透過下面這個 Function 來實作,用於點擊 Widget 後,跳回 Containing App ```swift func open(_ URL: URL, completionHandler: ((Bool) -> Void)? = nil) ``` #### Shared resources Containing App 與 App Extension 之間有時候會需要有資料共用、傳輸的需求 那一般來說是做不到的,主要是因為 iOS 系統讓 App、App Extension 都是透過 Sandbox (沙盒) 運作的,所以兩者之間是八竿子打不著的 我們可以透過下面這個例子,來知道如果 App 中有使用 SQLite 的話,會在兩邊都建立一個 db 檔 ``` # Containing App 建立的 db 檔 /var/mobile/Containers/Data/Application/E5E6E516-0163-4754-9D10-A5F6C33A6261/Documents/app.db # App Extension 建立的 db 檔 /var/mobile/Containers/Data/PluginKitPlugin/0A99BB23-E261-4AB9-8DA1-29EFA6E2649E/Documents/app.db ``` 從上面路徑可以看到從「/var/mobile/Containers/Data/」後面兩者的路徑就不一樣了 Containing App 是建立在「Application/」下,而 App Extension 是建立在「PluginKitPlugin/」 難怪會在 Containing App 跟 App Extension 兩邊都各建立一個 db 檔 那該怎麼處理呢? 我們可以透過 **App Groups** 來讓 Containing App 跟 App Extension 共同讀寫同一個區域 ### App Groups 這裡就稍微說一下,App Groups 要如何開啟 (Containing App 跟 Extension 開啟方法都一樣) Containing App 跟 App Extension 兩邊都要開啟 App Groups 才行喔!  ``` 0. TARGETS -> <TARGETS NAME> -> Signing & Capabilities -> Signing 選 Apple 付費開發者帳號 1. TARGETS -> <TARGETS NAME> -> Signing & Capabilities -> App Groups 2. App Groups -> + -> 輸入 group.<你想取的名稱> ``` 接著有兩個方式可以讓 Containing App 跟 App Extension 共同存取資料 1. UserDefaults 2. FileManager #### UserDefaults ```swift UserDefaults(suiteName: "group.<你想取的名稱>") ``` #### FileManager ```swift FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.<你想取的名稱>") ``` ## 不能在 Application Extension 做的事情 從 Apple Developer Documentation 中可以知道 有些事情是不能在 Application Extension 做的,如下圖  ▲ 圖取自 [Apple Developer Documentation](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html) 不負責翻譯如下 1. 不能存取 sharedApplication 物件,所以不能使用 sharedApplication 物件中的任何 Methods 2. 不能使用任何被標記 NS_EXTENSION_UNAVAILABLE 的 API 或類似的標記, 以及 unavailable Framework 中的任何 API,像是 HealthKit、EventKit UI Framework 3. 不能在 iOS 裝置上使用相機與麥克風 (iMessage App 可以,只需要在 Info.plist 中新增 NSCameraUsageDescription、NSMicrophoneUsageDescription) 4. 執行長時間的背景任務 5. 透過 AirDrop 來接收資料 ## 總結 Application Extension 幫 App 新增許多可玩性 在下一篇會以 AutoFill Credential Provider 來當作範例實作 App Extension
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.