一、動態庫的構建步驟
① 創建動態庫
創建一個動態庫 MyDynamicFramework:
在 MyDynamicFramework.h(默認生成,可統一暴露頭文件) 中 #import “Person.h”:
# import < Foundation/ Foundation. h> FOUNDATION_EXPORT
double MyDynamicFrameworkVersionNumber
; FOUNDATION_EXPORT
const unsigned char MyDynamicFrameworkVersionString
[ ] ; # import "Person.h"
點擊工程 -> Targets -> Build Phases -> Headers,動態庫中新建的文件會自動添加到 project 列表,MyDynamicFramework.h 文件是處于 Public 列表中。由于動態庫外部使用者需要調用 Person.h 中的方法,所以也需要將 Person.h 拖拽到 Public 列表,如下所示:
② 編譯動態庫
選擇動態庫對應的 Scheme,選擇 Generic iOS Device 或真機編譯出對應真機的動態庫,Command + B 編譯。 如果沒有連接真機,也可以,只要選擇Generic iOS Device選項也是可以編譯出對應真機的動態庫,如下圖所示:
在 Xcode 工程中的 Products(這個目錄不是工程源文件目錄,而是編譯后生成對應的沙盒目錄)找到 MyDynamicFramework.framework 文件,右鍵 show in finder:
利用 lipo -info 查看動態庫所支持的 CPU 指令集(在終端中,cd 進入 MyDynamicFramework.framework,這里需要注意進入的是 MyDynamicFramework.framework,而不是 MyDynamicFramework.framework 所在目錄, 然后輸入 $lipo -info MyDynamicFramework),如下:
lipo
- info
/ Users
/ ydw
/ Library
/ Developer
/ Xcode
/ DerivedData
/ MyDynamicFramework
- cnfmjshbkauwwshdqagjwrgypile
/ Build
/ Products
/ Debug
- iphoneos
/ MyDynamicFramework
. framework
/ MyDynamicFrameworkArchitectures in the fat file
: / Users
/ ydw
/ Library
/ Developer
/ Xcode
/ DerivedData
/ MyDynamicFramework
- cnfmjshbkauwwshdqagjwrgypile
/ Build
/ Products
/ Debug
- iphoneos
/ MyDynamicFramework
. framework
/ MyDynamicFramework are
: arm7、arm64
新建工程后所編譯出來的動態庫所支持的 CPU 指令集是 arm7、arm64。需要注意:lipo -info [文件] 后面跟的是文件路徑,而不是 .framework 路徑。
③ 指令集
指令集種類: armv7|armv7s|arm64 都是 ARM 處理器的指令集; i386|x86_64 是 iOS 模擬器的指令集。 指令集對應的機型:
arm64:iPhone6s
| iphone6s plus|iPhone6| iPhone6 plus|iPhone5S
| iPad
Air | iPad
mini2 ( iPad mini with
Retina Display )
armv7s:iPhone5|iPhone5C|
iPad4 ( iPad with
Retina Display )
armv7:iPhone4|iPhone4S|iPad|iPad2|
iPad3 ( The New iPad
) |iPad mini|iPod
Touch 3G|iPod
Touch4 i386
: iPhone5
| iPhone 4s
| iPhone
4 及前代產品的模擬器
x86_64
: iPhone5s
| iPhone
6 | . . . | iPhone8的模擬器
理論上指令集是向下兼容的,比如連接設備為 arm64,那么是有可能編譯出的動態庫所支持的指令集為 armv7s 或者是 armv7。但是向下兼容并不是說一個 armv7s 的動態庫可以用在 arm64 架構的設備上,如果連接的設備是 arm64 的,而導入的動態庫是沒有支持 arm64,那么在編譯階段即會報錯。
④ Xcode 指令集的編譯選項說明
Xcode 指令集的編譯選項,打開 Target -> Build Setting -> Architectures,如下所示:
說明: Architectures:指明選定 Target 要求被編譯生成的二進制包所支持的指令集; Build Active Architecture Only:指明是否只編譯當前連接設備所支持的指令集,如果為 YES,那么只編譯出連接設備所對應的指令集;如果為 NO,則編譯出所有其它有效的指令集(由 Architectures 和 Valid Architectures 決定); Valid Architectures:指明可能支持的指令集并非 Architectures 列表中指明的指令集都會被支持。 編譯產生的動態庫所支持的指令集將由上面三個編譯選項所影響,首先一個動態庫要成功編譯,則需要這三個編譯選項的交集不為空。如下所示:
示例
1 :
Architectures 為armv7、arm64
Valid Architectures 為armv7、armv7s、arm64
Build Active Architecture Only 為 debug
: YES release
: NO 鏈接設備
: iPhone 6s
( arm64架構的設備
) 編譯
( command
+ shift
+ B
, 保證
Build Active Architecture Only 為 debug
: YES 生效
) 結果:編譯成功,生成的動態庫支持的指令集為arm64示例
2 :
Architectures 為armv7、arm64
Valid Architectures 為 armv7s
Build Active Architecture Only 為 debug
: YES release
: NO 鏈接設備
: iPhone 6s
( arm64架構的設備
) 編譯
( command
+ shift
+ B
, 保證
Build Active Architecture Only 為 debug
: YES 生效
) 結果:編譯失敗,因為當前是debug模式,在該模式下
Build Active Architecture Only 為
YES ,表示只編譯支持該指令集的動態庫,但是由于
Architectures和Build Active Architecture Only的交集中并不存在arm64 ,故三者的交集為空,故編譯失敗,無法生成動態庫。示例
3 :
Architectures 為armv7、arm64
Valid Architectures 為armv7、armv7s、arm64
Build Active Architecture Only 為 debug
: NO release
: NO 鏈接設備
: iPhone 6s
( arm64架構的設備
) 編譯
( command
+ shift
+ B
, 保證
Build Active Architecture Only 為 debug
: YES 生效
) 結果:編譯成功,因為當前是debug模式,在該模式下
Build Active Architecture Only 為
NO ,表示可以編譯的結果可能為當前連接的設備所支持的指令集以及其向下兼容的指令集
( armv64、armv7s、armv7
) ,其和另外兩個編譯選項的交集為armv7,故所生成的動態庫支持的指令集為armv7
⑤ 制作支持各機型的動態庫
支持 iPhone 4 及以后機型的動態庫的意思是:生成的動態庫支持的指令集為 armv7、armv7s、arm64,因此 Architectures 的三個指令可以設置為: Build Active Architecture Only 統一為 NO; Architectures 和 Valid Architectures 都設置為 armv7、armv7s、arm64、arm64e; 真機 Command + B 則生成支持 armv7、armv7s、arm64 的動態庫,模擬器運行則生成支持 i386、x86_64 的動態庫。 合并模擬器和真機動態庫:使用 lipo -create -output 命令合動態庫,注意路徑是文件路徑,不是 .framework 的路徑,如下所示:
lipo
- create
/ Users
/ ydw
/ Library
/ Developer
/ Xcode
/ DerivedData
/ MyDynamicFramework
- cnfmjshbkauwwshdqagjwrgypile
/ Build
/ Products
/ Debug
- iphoneos
/ MyDynamicFramework
. framework
/ MyDynamicFramework
/ Users
/ ydw
/ Library
/ Developer
/ Xcode
/ DerivedData
/ MyDynamicFramework
- cnfmjshbkauwwshdqagjwrgypile
/ Build
/ Products
/ Debug
- iphonesimulator
/ MyDynamicFramework
. framework
/ MyDynamicFramework
- output MyDynamic
if [ "${ACTION}" = "build" ] thenINSTALL_DIR
= $
{ SRCROOT
} / Products
/ $
{ PROJECT_NAME
} . frameworkDEVICE_DIR
= $
{ BUILD_ROOT
} / $
{ CONFIGURATION
} - iphoneos
/ $
{ PROJECT_NAME
} . frameworkSIMULATOR_DIR
= $
{ BUILD_ROOT
} / $
{ CONFIGURATION
} - iphonesimulator
/ $
{ PROJECT_NAME
} . framework
if [ - d
"${INSTALL_DIR}" ] thenrm
- rf
"${INSTALL_DIR}" fimkdir
- p
"${INSTALL_DIR}" cp
- R
"${DEVICE_DIR}/" "${INSTALL_DIR}/" # ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers" # 使用lipo命令將其合并成一個通用framework # 最后將生成的通用framework放置在工程根目錄下新建的Products目錄下 lipo
- create
"${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" - output
"${INSTALL_DIR}/${PROJECT_NAME}" # open "${DEVICE_DIR}" # open "${SRCROOT}/Products" fi
編譯新 target,編譯完成后生成的 framework 位于工程源代碼根目錄下的 Products 文件夾下面,通過 lipo -info 可以看到動態庫已經支持 i386、x86_64、armv7、armv7s、arm64(注意:是工程目錄,不是沙盒目錄)。
lipo
- info
/ Users
/ ydw
/ Desktop
/ MyDynamicFramework
/ Products
/ MyDynamicFramework
. framework
/ MyDynamicFrameworkArchitectures in the fat file
: / Users
/ ydw
/ Desktop
/ Products
/ MyDynamicFramework
. framework
/ MyDynamicFramework are
: i386 x86_64 armv7 arm64
使用動態庫:在新工程的 target -> General -> Embedded Binaries 中添加 MyDynamicFramework.framework。
二、動態庫的使用
將上文中生成的動態庫拖入新工程中,在新工程的 AppDelegate.m 中鍵入如下代碼:
#
import < MyDynamicFramework / MyDynamicFramework . h
> @interface
AppDelegate ( )
@end@implementation
AppDelegate - ( BOOL ) application
: ( UIApplication * ) application didFinishLaunchingWithOptions
: ( NSDictionary * ) launchOptions
{ ViewController * vc
= [ [ ViewController alloc
] init ] ; self . window
= [ [ UIWindow alloc
] initWithFrame
: [ UIScreen mainScreen
] . bounds
] ; [ self . window makeKeyAndVisible
] ; self . window
. backgroundColor
= [ UIColor whiteColor
] ; self . window
. rootViewController
= vc
; [ Person logMessage
: @
"framework test" ] ; return YES ;
}
別使用真機和模擬器運行新工程,執行成功,控制臺輸出如下:
+ [ Person logMessage
: ] - framework test
UByjBj : 2021 - 08 - 28 12 : 39 : 52 + 0000
AORja ] : 2021 - 08 - 28 12 : 39 : 54 + 0000
① 使用別人提供的動態庫遇到的坑
提供的第三方庫所支持的 CPU 指令集不全,出現的錯誤信息,類似如下圖:
這里連接的設備是 iPhone 7 模擬器,其 CPU 架構為 x86_64,但是導入的 framework 是真機編譯出來的動態庫(支持的指令集為 armv7、armv7s、arm64,并沒有 x86_64),所以就報了這樣的類似的錯誤,進一步可以使用上文中的“編譯動態庫”查看別人提供的動態庫所支持的指令集,找出對應的動態庫,處理解決即可。 運行過程中出現 image not found 異常或者控制臺沒有異常輸出。原因:沒有往 Embedded Binaries 中添加 xxx.framework。
② 動態庫動態更新問題
能否用動態庫來動態更新 App Store 上的版本呢? framework 本來是蘋果專屬的內部提供的動態庫文件格式,但是自從 2014 年 WWDC 之后,開發者也可以自定義創建 framework 實現動態更新(繞過 App Store 審核,從服務器發布更新版本)的功能,這與蘋果限定的上架的 app 必須經過 App Store 的審核制度是沖突的,所以含有自定義的 framework 的 app 是無法在商店上架的,但是如果開發的是企業內部應用,就可以考慮嘗試使用動態更新技術來將多個獨立的 app 或者功能模塊集成在一個 app 上面。 企業內部使用的 app,將企業官網中的板塊開發成 4 個獨立的 app,然后將其改造為 framework 文件最終集成在一款平臺級的 app 當中進行使用,這樣就可以在一款 app 上面使用原本 4 個 app 的全部功能。 使用自定義的動態庫的方式來動態更新只能用在 in house(企業發布)和 develop 模式卻但不能在使用到 App Store,因為在上傳打包的時候,蘋果會對我們的代碼進行一次 Code Singing,包括 app 可執行文件和所有 Embedded 的動態庫。因此,只要你修改了某個動態庫的代碼,并重新簽名,那么 MD5 的哈希值就會不一樣,在加載動態庫的時候,蘋果會檢驗這個 hash 值,當蘋果監測到這個動態庫非法時,就會造成 Crash。
③ iOS 如何使用 framework 來進行動態更新?
目前 iOS 上的動態更新方案主要有以下四種: 前面三種都是通過在應用內搭建一個運行環境來實現動態更新(HTML 5 是原生支持),在用戶體驗、與系統交互上有一定的限制,對開發者的要求也更高(至少得熟悉 lua 或者 js)。 使用 framework 的方式來更新可以不依賴第三方庫,使用原生的 OC/Swift 來開發,體驗更好,開發成本也更低。 由于 Apple 不希望開發者繞過 App Store 來更新 app,因此只有對于不需要上架的應用,才能以 framework 的方式實現 app 的更新。 主要思路:將 app 中的某個模塊(比如一個 tab)的內容獨立成一個 framework 的形式動態加載,在 app 的 main bundle 中,當 app 啟動時從服務器上下載新版本的 framework 并加載即可達到動態更新的目的。 創建一個普通工程 DynamicUpdateDemo,其包含一個 framework 子工程 Module。也可以將 Module 創建為獨立的工程,創建工程的過程不再贅述。 依賴 :在主工程的 Build Phases > Target Dependencies 中添加 Module,并且添加一個 New Copy Files Phase,這樣打包時會將生成的 Module.framework 添加到 main bundle 的根目錄下。如下所示:
- ( UIViewController
* ) loadFrameworkNamed
: ( NSString
* ) bundleName
{ NSArray
* paths
= NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory
, NSUserDomainMask
, YES
) ; NSString
* documentDirectory
= nil
; if ( [ paths count
] != 0 ) { documentDirectory
= [ paths objectAtIndex
: 0 ] ; } NSFileManager
* manager
= [ NSFileManager defaultManager
] ; NSString
* bundlePath
= [ documentDirectory stringByAppendingPathComponent
: [ bundleName stringByAppendingString
: @".framework" ] ] ; if ( ! [ manager fileExistsAtPath
: bundlePath
] ) { NSLog ( @"No framework update" ) ; bundlePath
= [ [ NSBundle mainBundle
] pathForResource
: bundleName ofType
: @"framework" ] ; if ( ! [ manager fileExistsAtPath
: bundlePath
] ) { UIAlertView
* alertView
= [ [ UIAlertView alloc
] initWithTitle
: @"Oooops" message
: @"Framework not found" delegate
: nil cancelButtonTitle
: @"OK" otherButtonTitles
: nil
, nil
] ; [ alertView show
] ; return nil
; } } NSError
* error
= nil
; NSBundle
* frameworkBundle
= [ NSBundle bundleWithPath
: bundlePath
] ; if ( frameworkBundle
&& [ frameworkBundle loadAndReturnError
: & error
] ) { NSLog ( @"Load framework successfully" ) ; } else { NSLog ( @"Failed to load framework with err: %@" , error
) ; return nil
; } Class PublicAPIClass
= NSClassFromString ( @"PublicAPI" ) ; if ( ! PublicAPIClass
) { NSLog ( @"Unable to load class" ) ; return nil
; } NSObject
* publicAPIObject
= [ PublicAPIClass new
] ; return [ publicAPIObject performSelector
: @selector ( mainViewController
) ] ; }
代碼先嘗試在 Document 目錄下尋找更新后的 framework,如果沒有找到,再在 main bundle 中尋找默認的 framework。其中的關鍵是利用 OC 的動態特性 NSClassFromString 和 performSelector 加載 framework 的類并且執行其方法。 第三方庫 :
Class XXX is implemented
in both XXX and XXX
. One of the two will be used
. Which one is undefined
.
這是當 framework 工程和 host 工程鏈接了相同的第三方庫或者類造成的。為了讓打出的 framework 中不包含 host 工程中已包含的三方庫(如 cocoapods 工程編譯出的 .a 文件),可以這樣: 刪除 Build Phases > Link Binary With Libraries 中的內容(如有)。此時編譯會提示三方庫中包含的符號找不到; 在 framework 的 Build Settings > Other Linker Flags 添加 -undefined dynamic_lookup。必須保證 host 工程編譯出的二進制文件中包含這些符號。 類文件 : 嘗試過在 framework 中引用 host 工程中已有的文件,通過 Build Settings > Header Search Paths 中添加相應的目錄,Xcode 在編譯的時候可以成功(因為添加了 -undefined dynamic_lookup),并且 Debug 版本是可以正常運行的,但是 Release 版本動態加載時會提示找不到符號:
Error Domain
= NSCocoaErrorDomain Code
= 3588 "The bundle “YourFramework” couldn’t be loaded." ( dlopen ( / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9347 - BC7B90D343C1
/ YourApp
. app
/ YourFramework
. framework
/ YourFramework
, 265 ) : Symbol not found
: _OBJC_CLASS_$_BorderedViewReferenced from
: / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9347 - BC7B90D343C1
/ YourApp
. app
/ YourFramework
. framework
/ YourFrameworkExpected
in : flat namespace
in / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9347 - BC7B90D343C1
/ YourApp
. app
/ YourFramework
. framework
/ YourFramework
) UserInfo
= 0x174276900 { NSLocalizedFailureReason
= The bundle couldn’t be loaded
. , NSLocalizedRecoverySuggestion
= Try reinstalling the bundle
. , NSFilePath
= / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9347 - BC7B90D343C1
/ YourApp
. app
/ YourFramework
. framework
/ YourFramework
, NSDebugDescription
= dlopen ( / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9347 - BC7B90D343C1
/ YourApp
. app
/ YourFramework
. framework
/ YourFramework
, 265 ) : Symbol not found
: _OBJC_CLASS_$_BorderedViewReferenced from
: / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9347 - BC7B90D343C1
/ YourApp
. app
/ YourFramework
. framework
/ YourFrameworkExpected
in : flat namespace
in / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9347 - BC7B90D343C1
/ YourApp
. app
/ YourFramework
. framework
/ YourFramework
, NSBundlePath
= / var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5691F B75
- 408 A
- 4 D9A
- 9
因為 Debug 版本暴露了所有自定義類的符號以便于調試,因此你的 framework 可以找到相應的符號,而 Release 版本則不會。目前能想到的方法只有將相同的文件拷貝一份到 framework 工程里,并且更改類名。 訪問 Framework 中的圖片 : 在 storyboard/xib 中可以直接訪問圖片,代碼中訪問的方法如下:
UIImage
* image
= [ UIImage imageNamed
: @"YourFramework.framework/imageName" ]
注意:使用代碼方式訪問的圖片不可以放在 xcassets 中,否則得到的將是 nil。并且文件名必須以 @2x/@3x 結尾,大小寫敏感。因為 imageNamed: 默認在 main bundle 中查找圖片。
④ 談談 Mach-O
在制作 framework 的時候需要選擇這個 Mach-O Type,確定 static、dynamic 類型庫。 為 Mach Object 文件格式的縮寫,它是一種用于可執行文件,目標代碼、動態庫、內核轉儲的文件格式。作為 a.out 格式的替代,Mach-O 提供了更強的擴展性,并提升了符號表中信息的訪問速度。
⑤ 自己創建的動態庫
自建的動態庫和系統的動態庫有什么區別呢?我們創建的動態庫是在自己應用的 .app 目錄里面,只能自己的 App Extension 和 APP 使用,而系統的動態庫是在系統目錄里面,所有的程序都能使用。 可執行文件和自己創建的動態庫位置:一般得到的 iOS 程序包是 .ipa 文件。其實就是一個壓縮包,解壓縮 .ipa 后里面會有一個 payload 文件夾,文件夾里有一個 .app 文件,右鍵顯示包內容,然后找到一個一般體積最大的、與 .app 同名的文件,那個文件就是可執行文件。
在模擬器上運行的時候用 [[NSBundle mainBundle] bundlePath]; 就能得到 .app 的路徑,可執行文件就在 .app 里面。而我們自己創建的動態庫就在 .app 目錄下的 Framework 文件夾里。
我們可以看一下可執行文件中對動態庫的鏈接地址。用 MachOView 查看可執行文件,其中 @rpth 這個路徑表示的位置可以查看 Xcode 中的鏈接路徑問題,而現在表示的其實就是 .app 下的 Framework 文件夾。
三、常見錯誤
① Architecture
dlopen ( / path
/ to
/ framework
, 9 ) : no suitable image found
. Did find
:
/ path
/ to
/ framework
: mach
- o
, but wrong architecture
這是說 framework 不支持當前機器的架構。通過如下指令可以查看 framework 支持的 CPU 架構:
lipo
- info
/ path
/ to
/ MyFramework
. framework
/ MyFramework
碰到這種錯誤,一般是因為編譯 framework 的時候,scheme 選擇的是模擬器,應該選擇 iOS Device。 此外,如果沒有選擇 iOS Device,編譯完成后,Products 目錄下的 .framework 文件名會一直是紅色,只有在 Derived Data 目錄下才能找到編譯生成的 .framework 文件。
② 簽名
系統在加載動態庫時,會檢查 framework 的簽名,簽名中必須包含 TeamIdentifier 并且 framework 和 host app 的 TeamIdentifier 必須一致。 如果不一致,否則會報下面的錯誤:
Error loading
/ path
/ to
/ framework
: dlopen ( / path
/ to
/ framework
, 265 ) : no suitable image found
. Did find
: / path
/ to
/ framework
: mmap ( ) error
1
此外,如果用來打包的證書是 iOS 8 發布之前生成的,則打出的包驗證的時候會沒有 TeamIdentifier 這一項。這時在加載 framework 的時候會報下面的錯誤:
[ deny
- mmap
] mapped file has no team identifier and is not a platform binary
: / private
/ var
/ mobile
/ Containers
/ Bundle
/ Application
/ 5 D8FB2F7
- 1083 - 4564 - 94 B2
- 0 CB7DC75C9D1
/ YourAppNameHere
. app
/ Frameworks
/ YourFramework
. framework
/ YourFramework
codesign
- dv
/ path
/ to
/ YourApp
. app
Executable
= / path
/ to
/ YourApp
. app
/ YourAppIdentifier
= com
. company
. yourappFormat
= bundle with Mach
- O
thin ( armv7
) CodeDirectory v
= 20100 size
= 221748 flags
= 0 x0 ( none
) hashes
= 11079 + 5 location
= embeddedSignature size
= 4321 Signed Time
= 2018 年
10 月
21 日 下午
10 : 18 : 36 Info
. plist entries
= 42 TeamIdentifier
= not setSealed Resources version
= 2 rules
= 12 files
= 2451 Internal requirements count
= 1 size
= 188
注意其中的 TeamIdentifier=not set。 采用 swift 加載 libswiftCore.dylib 這個動態庫的時候也會遇到這個問題,對此Apple 官方的解釋是:
To correct this problem
, you will need to sign your app using code signing certificates with the Subject Organizational
Unit ( OU
) set to your Team ID
. All Enterprise and standard iOS developer certificates that are created after iOS
8 was released have the new Team ID field
in the proper place to allow Swift language apps to run
. If you are an
in - house Enterprise developer you will need to be careful that you
do not revoke a distribution certificate that was used to sign an app any one of your Enterprise employees is still using as any apps that were
signed with that enterprise distribution certificate will stop working immediately
.
只能通過重新生成證書來解決這個問題。但是 revoke 舊的證書會使所有用戶已經安裝的,用該證書打包的 app 無法運行,這該怎么解決呢? 現在企業證書的有效期是三年,當證書過期時,其打包的應用就不能運行,那企業應用怎么來更替證書呢? Apple 為每個賬號提供了兩個證書,這兩個證書可以同時生效,這樣在正在使用的證書過期之前,可以使用另外一個證書打包發布,讓用戶升級到新版本。也就是說,可以使用另外一個證書來打包應用,并且可以覆蓋安裝使用舊證書打包的應用。詳情可以看 Apple 文檔:
You are responsible
for managing your team’s certificates and provisioning profiles
. Apple Developer Enterprise Program certificates expire after three years and provisioning profiles expire after one year
. Before a distribution certificate expires
, create an additional distribution certificate
, described
in Creating Additional Enterprise Distribution Certificates
. You cannot renew an expired certificate
. Instead
, replace the expired certificate with the new certificate
, described
in Replacing Expired Certificates
. If a distribution provisioning profile expires
, verify that you have a valid distribution certificate and renew the provisioning profile
, described
in Renewing Expired Provisioning Profiles
.
總結
以上是生活随笔 為你收集整理的iOS之深入解析如何构建动态库与framework动态更新 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。