###### tags: `第14屆IT邦鐵人賽文章` # 【在 iOS 開發路上的大小事2-Day19】Swift Framework 封裝 (基本款) Xcode 開新專案,選 Framework ![](https://i.imgur.com/LN0D7o9.png) 輸入 Framework 的名稱 ![](https://i.imgur.com/qaGyQis.png) 如果是 Xcode 13 以上的話 要先將隱藏的 Products 資料夾開啟,因為待會產生的 Framework 會出現在這裡 ``` Terminal 先切換到專案底下 => cd 專案路徑 => open 專案名稱.xcodeproj/pbxproj 找到 productRefGroup (請善用 Command+F,除非你眼力很好) 將 mainGroup 的值複製到 productRefGroup,存檔 神奇的 Products 資料夾就出現了 ``` 然後新增 Swift 檔案 ![](https://i.imgur.com/kKJKGsG.png) 輸入檔案名稱 ![](https://i.imgur.com/YM6dVYd.jpg) 接著在 class 前面加上 **public** 修飾字,像是下面這樣 ```swift // 原本長這樣 class Manager { } // 加完 public 後長這樣 public class Manager { } ``` 這是因為要封裝成 Framework,所以為了要讓外層檔案可以使用 (也就是要裝這套件的專案) 所以必須要設為 **public**,如果是要可以 override 或是繼承的話,則是要設為 **open** ```swift // 原本長這樣 class Manager { } // 加完 open 後長這樣 open class Manager { } ``` [Swift 的檔案存取層級參考](https://medium.com/@wuufone/swift-%E7%9A%84%E5%AD%98%E5%8F%96%E6%8E%A7%E5%88%B6%E6%A9%9F%E5%88%B6-access-control-e9f89bb73f2b) 接著就可以寫我們要的東西了 這邊用換背景色、輸入輸出的 func 做示範 ```swift import Foundation import UIKit public class Manager { /// 更換 ViewController 的背景色 /// - Parameters: /// - vc: UIViewController,放你想要改變的 UIViewController /// - color: UIColor,放你想要更換的顏色 public func changeVCBackgroundColor(vc: UIViewController, color: UIColor) { vc.view.backgroundColor = color } /// 你輸入什麼,我輸出什麼 /// - Parameters: /// - text: String?,輸入字串 public func inputAndOutPut(text: String?) { print("You Input: \(text), and I Output: \(text)") } } ``` 然後切到 專案名稱.xcodeproj 檔案 * 修改 SDK 最低支援的版本 (紅框處) ``` TARGETS → Framework 名稱 → General → Deployment Info → Deployment Target ``` ![](https://i.imgur.com/OB089Kx.png) * 修改 SDK 支援的裝置 (紅框處裡面的藍色那條) ``` TARGETS → Framework 名稱 → Build Settings → Architectures → Build Active Architecture Only 將 Debug 改成 Yes,是為了讓編譯當下,只編譯所選的裝置,而不是編譯所有的裝置,可以加快編譯效率 將 Release 改成 No,是為了讓每個裝置都可以用,而不會受限於只有編譯的那個裝置可以用 ``` ![](https://i.imgur.com/QaNirsp.png) * 修改 SDK 配置 (紅框處裡面的藍色那兩條) ``` TARGETS → Framework 名稱 → Build Settings → Linking 將 Dead Code Stripping 改成 No,是將對程式不會造成影響的 Code 移除,讓編譯最佳化 將 Mach-O Type 改成 Static Library,因為非官方的 Framework 貌似不能用動態庫 ``` ![](https://i.imgur.com/y9bPto1.png) * 添加要暴露出的標頭檔 (Header) ``` TARGETS → Framework 名稱 → Build Phases → Headers Swift 不用做但 Objective-C 要做的事 因為 Swift 在產生 Project 的時候已經預設產生並添加好了 Objective-C 的話,需要將要暴露出來的標頭檔放在 Public 裡面 ``` ![](https://i.imgur.com/iDeRBQr.png) * 修改 Scheme 裡面的 Build Configuration (紅框處) ``` 裝置旁邊的公事包 (target) → Edit Scheme → Build Configuration 將 Build Configuration 改為 Release ``` ![](https://i.imgur.com/lZXDpzi.png) 如果要讓 Objective-C 的專案可以用的話 要將 class 繼承 NSObject,並且要是 public 跟加上 @objc 如果用前面的範例來改寫的話,像下面這樣 ```swift import Foundation import UIKit @objc public class Manager: NSObject { /// 更換 ViewController 的背景色 /// - Parameters: /// - vc: UIViewController,放你想要改變的 UIViewController /// - color: UIColor,放你想要更換的顏色 @objc public func changeVCBackgroundColor(vc: UIViewController, color: UIColor) { vc.view.backgroundColor = color } /// 你輸入什麼,我輸出什麼 /// - Parameters: /// - text: String?,輸入字串 @objc public func inputAndOutPut(text: String?) { print("You Input: \(text), and I Output: \(text)") } } ``` ## 要注意的事情 **!!模擬器產生的 Framework 跟 實機產生的 Framework 是不能混用的!!** 所以我們要將模擬器跟實機各自產生的 Framework 進行合併,這樣兩者才能通用 ``` 先 Command+B 模擬器的 SDK 再 Command+B 實機的 SDK 打開 Terminal,切到 Framework 所在的資料夾路徑 Tips:點擊 Products 裡面的 Framework,選 Show in Finder (這邊的 Products 指的是 Xcode 專案裡面那個,也就是上面我們叫出來的隱藏資料夾) 這樣就可以開啟 Framework 所在的資料夾 下圖紅框處,就是剛才 Command+B 後的 模擬器的 SDK 和 實機的 SDK Release-iphoneos:實機的 SDK Release-iphonesimulator:模擬器的 SDK ``` ![](https://i.imgur.com/NoltYFW.png) ``` 在 Terminal 輸入指令 => cd Framework 所在的資料夾路徑 (也就是 Products) ``` ![](https://i.imgur.com/KuMcil5.png) ``` Framework名稱 要自行替換成實際自己設的名稱喔!!! 以下圖來說,Framework名稱 就是 SDK_Demo => lipo -create Release-iphoneos/Framework名稱.framework/Framework名稱 Release-iphonesimulator/Framework名稱.framework/Framework名稱 -output Framework名稱 這邊我不使用腳本的原因是因為每次用腳本合併,總是無法讓模擬器跟實機都可以用 ``` ![](https://i.imgur.com/4nPzbLu.png) ``` 輸入完上面的指令後,這樣就將 模擬器的 SDK 和 實機的 SDK 的二進制檔案合併完成了 下圖的紅框處就是合併後的二進制檔案 ``` ![](https://i.imgur.com/30K5gYe.png) ``` 要如何驗證有沒有合併成功的話,可以在 Terminal 輸入下面的指令 Framework名稱 要自行替換成實際自己設的名稱喔!!! 以下圖來說,Framework名稱 就是 SDK_Demo => lipo -info Framework名稱 看到下面這行的話就算合併成功了 「Architectures in the fat file: Framework名稱 are: x86_64 arm64」 ``` ![](https://i.imgur.com/4vwAZjw.png) ``` 接著複製一份實機的資料夾,並將他改名,名稱的話隨意~ 但為了要方便找的話,取名為「Release-iphoneUniversal」會比較好一點 像是下圖紅框處這樣 ``` ![](https://i.imgur.com/Jkbvr6v.png) ``` 然後將模擬器 SDK 裡面的 Modules/Framework名稱.swiftmodule 的 四個檔案跟 Project 資料夾裡面的兩個檔案 個別複製到 「Release-iphoneUniversal/Framework名稱.framework/Modules/Framework名稱.swiftmodule」 裡面對應的資料夾內 複製完成後,會長的像下圖一樣 Framework名稱.swiftmodule 資料夾裡面: 副檔名為 .swiftdoc 會有四個 (arm64、x86_64 各兩個) 副檔名為 .swiftmodule 會有四個 (arm64、x86_64 各兩個) Framework名稱.swiftmodule/Project 資料夾裡面: 副檔名為 .swiftsourceinfo 會有四個 (arm64、x86_64 各兩個) ``` ![](https://i.imgur.com/RA5o9Z2.png) 這樣就算完成 Swift Framework 封裝了 ## 補充 如果是 Apple Silicon 的 Mac 要用的話 要在使用 SDK 的專案改用 My Mac (Design with iPad) 或是接手機來燒,**不能用模擬器燒**!! 因為 Xcode 的模擬器似乎是 x86_64 架構的 ## 參考資料 (來自各路大神,讚嘆大神~) > 1. [iOS Swift Framework靜態庫製作與發佈](https://www.twblogs.net/a/5db39dbfbd9eee310da05b46) > 2. [iOS-SDK开发经验分享](https://www.jianshu.com/p/cbb1f54b89d2) > 3. [Framework 嵌套与依赖](https://www.jianshu.com/p/b03d617917d6) > 4. [swift framework中引入第三方的framework或者.a](https://www.jianshu.com/p/1eaa63388594) > 5. [iOS静态库SDK制作(包含第三方静态库)](https://juejin.cn/post/6844903521465139214) > 6. [iOS開發~製作同時支持armv7,armv7s,arm64,arm64e,i386,x86_64的靜態庫.a](https://www.twblogs.net/a/5c67a9f8bd9eee01cc9e1133) > 7. [xcode 13新建工程找不到product文件夾](https://juejin.cn/post/7036384854782509063) > 8. [swift封装Framework静态库SDK](https://michaellynx.github.io/swift-with-static-library-framework/) > 9. [关于Xcode12静态库打包的一些心得](https://www.cnblogs.com/wgb1234/p/14258036.html) > 10. [【iOS】SDK靜態庫的封裝](https://juejin.cn/post/6844904178762907661) > 11. [iOS封装SDK](https://juejin.cn/post/6844903878094225422) > 12. [Creating and Publishing Custom iOS Framework using Cocoapods | Swift 5, XCode 11](https://youtu.be/vSMmZxmKIA4) > 13. [How to Create a Swift Framework using Xcode 11](https://www.youtube.com/watch?v=iFi1QnKHFnM&t=372s) > 14. [Swift Framework - Create a Custom Framework in iOS](https://youtu.be/oZloIsF1H4g)