App Extension Programming Guide-App Extension Essentials
AppExtension編程指南:擴(kuò)展基礎(chǔ)4
Handling Common Scenarios
常見問題的處理方案
翻譯自蘋果官方文檔 App Extension Programming Guide--Handling Common Scenarios
常見問題的處理方案
當(dāng)編寫自定義代碼以執(zhí)行app擴(kuò)展任務(wù)時专挪,你可能需要處理一些其他多種類型擴(kuò)展也會出現(xiàn)的情況。在這一章節(jié)中忆绰,我們將幫助你如何應(yīng)對和處理這些常見的問題恰力。
使用內(nèi)嵌框架共享代碼
你可以創(chuàng)建一個內(nèi)嵌框架,用于在應(yīng)用擴(kuò)展和它的主應(yīng)用程序(containing app)之間共享代碼陡蝇。比如痊臭,你在照片編輯擴(kuò)展中開發(fā)了圖片濾鏡功能,那么同時該擴(kuò)展的主應(yīng)用程序containing app也有這個功能登夫,那么你可以將實(shí)現(xiàn)該功能的代碼封裝成一個框架广匙,并在擴(kuò)展target和主應(yīng)用程序target中嵌入這個框架。
你要確保你創(chuàng)建的內(nèi)嵌框架不包含應(yīng)用擴(kuò)展不能使用的API恼策。這類API一般使用unavailability
宏來標(biāo)記鸦致,比如像 NS_EXTENSION_UNAVAILABLE
。
如果你創(chuàng)建的內(nèi)嵌框架中包含應(yīng)用擴(kuò)展不能使用的API涣楷,你可將其安全地Link到containing app分唾,它可以正常使用框架中的API,但是不能與應(yīng)用擴(kuò)展共享代碼(譯者注:也就是應(yīng)用擴(kuò)展不能使用該框架提供的所有API狮斗,繼而無法做到代碼共享)绽乔。如果你上傳App Store的應(yīng)用擴(kuò)展中有這種框架,或者其他部分使用了不可用的API情龄,那么審核時會被拒絕迄汛。
如果我們要想應(yīng)用擴(kuò)展使用內(nèi)嵌框架,那么首先要配置一下骤视。將target的Require Only App-Extension-Safe API
選項(xiàng)設(shè)置為Yes
鞍爱。如果你不這樣設(shè)置,那么Xcode會向你提示警告:linking against dylib not safe for use in application extensions
专酗。
重要提示:如果containing app要鏈接至內(nèi)嵌框架睹逃,那么必須要支持arm64架構(gòu),否則在上傳App Store時會被拒絕祷肯。(如“創(chuàng)建應(yīng)用擴(kuò)展”章節(jié)中介紹的沉填,所有應(yīng)用擴(kuò)展都要支持arm64架構(gòu)。)
在配置配置Xcode項(xiàng)目時佑笋,必須在Copy Files
編譯階段選擇“Frameworks”作為內(nèi)嵌框架的目標(biāo)翼闹。
重要提示:我們通常要選擇 Frameworks 作為 Copy Files 編譯階段目標(biāo)。如果你將其設(shè)置為 SharedFramework蒋纬,那么上傳App Store時會被拒絕的猎荠。
你可以讓containing app支持iOS7或更早的版本坚弱,但當(dāng)在iOS8或更新的版本中運(yùn)行時,要特別注意內(nèi)嵌框架的安全性关摇。詳細(xì)內(nèi)容可以參閱 Deploying a Containing App to Older Versions of iOS荒叶。
有關(guān)創(chuàng)建和使用內(nèi)嵌框架的更多內(nèi)容,請觀看WWDC 2014的視頻“Building Modern Frameworks”输虱。
與Containing App共享數(shù)據(jù)
應(yīng)用擴(kuò)展和它的containing app的安全域是有區(qū)別的些楣。即便擴(kuò)展包是嵌套在containing app包中的。默認(rèn)情況下宪睹,應(yīng)用擴(kuò)展和containing app是不能直接訪問對方的容器的愁茁。
BACKGROUND
要了解容器,閱讀 About the iOS File System 中的 File System Programming Guid.
不過你可以通過數(shù)據(jù)共享來實(shí)現(xiàn)這個愿望亭病。比如埋市,你希望應(yīng)用擴(kuò)展和它的containing app共享一個單一的大數(shù)據(jù)集。比如prerendered assets命贴。
要實(shí)現(xiàn)數(shù)據(jù)共享,我們要使用Xcode或者開發(fā)者門戶網(wǎng)站允許應(yīng)用擴(kuò)展和它的containing app成為一個應(yīng)用組食听,然后在開發(fā)者門戶網(wǎng)站中注冊應(yīng)用組胸蛛,并指明在containing app中使用該應(yīng)用組。關(guān)于應(yīng)用組的知識請查閱 Entitlement Key Reference 文檔的 Adding an App to an App Group 章節(jié)樱报。
當(dāng)你設(shè)置好應(yīng)用組后葬项,應(yīng)用擴(kuò)展和它的containing app就可以通過 NSUserDefaults API共享訪問用戶的信息。我們可以使用 initWithSuiteName: 方法實(shí)例化一個 NSUserDefaults 對象迹蛤,然后傳入共享組的標(biāo)示符民珍。比如一個共享擴(kuò)展,它或許會更新用戶最近經(jīng)常使用的共享賬號盗飒,那么我們可以這樣來寫:
// Create and share access to an NSUserDefaults object.
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.example.domain.MyShareExtension"];
// Use the shared user defaults object to update the user's account. [mySharedDefaults setObject:theAccountName forKey:@"lastAccountName"];
下圖向我們展示了應(yīng)用擴(kuò)展和它的containing app是如何通過共享容器實(shí)現(xiàn)數(shù)據(jù)共享的.
Figure 4-1應(yīng)用擴(kuò)展的容器與其containing app的容器是不同的嚷量。
重要提示:如果你的應(yīng)用擴(kuò)展使用NSURLSession類執(zhí)行后臺的上傳下載任務(wù)時,你必須要設(shè)置一個共享容器逆趣,這樣擴(kuò)展和containing app就可以訪問到轉(zhuǎn)換傳輸?shù)臄?shù)據(jù)蝶溶。后臺上傳下載的更多知識請參閱 Performing Uploads and Downloads。
如果你設(shè)置了共享容器宣渗,那么containing app和它包含的允許參與數(shù)據(jù)分享的擴(kuò)展就可以對共享容器里的內(nèi)容進(jìn)行讀寫操作了抖所。同時你還必須要對數(shù)據(jù)的操作進(jìn)行同步,以避免數(shù)據(jù)損壞或出錯痕囱。使用UIDocument類田轧、Core Data或者SQLite可以幫你可以讓用戶通過要求Safari運(yùn)行JS文件來訪問網(wǎng)絡(luò)內(nèi)容,并將結(jié)果返回到擴(kuò)展鞍恢。
版本說明
在iOS 8.2及更高版本中傻粘,您也可以使用UIDocument該類來協(xié)調(diào)共享數(shù)據(jù)訪問每窖。
在iOS 9及更高版本中,您可以NSFileCoordinator直接使用該類進(jìn)行共享數(shù)據(jù)訪問抹腿,但是如果您這樣做岛请,則必須NSFilePresenter在應(yīng)用擴(kuò)展轉(zhuǎn)換為后臺時刪除對象。
訪問網(wǎng)頁
在分享擴(kuò)展(iOS與OS X平臺)和Action擴(kuò)展(iOS平臺)中警绩,一般都允許用戶使用Safari瀏覽器訪問網(wǎng)頁并通過執(zhí)行JavaScript腳本崇败,并將結(jié)果返回到擴(kuò)展中。你也可以在你的擴(kuò)展運(yùn)行之前(適用于兩個平臺)或執(zhí)行完任務(wù)之后(僅適用于iOS平臺)通過JavaScript文件修改網(wǎng)頁內(nèi)容肩祥。比如分享擴(kuò)展后室,它可以幫助用戶分享網(wǎng)頁上的內(nèi)容,或者iOS上的Action擴(kuò)展可能會顯示當(dāng)前網(wǎng)頁的指定翻譯內(nèi)容混狠。
如果想添加網(wǎng)頁訪問和操作應(yīng)用擴(kuò)展岸霹,那么需要遵循下面幾個步驟:
1.創(chuàng)建一個JavaScript文件,并申明一個全局對象将饺,命名為 ExtensionPreprocessingJS
贡避,并為該對象分配一個新的自定義JavaScript類的實(shí)例。
2.在應(yīng)用擴(kuò)展的屬性列表文件中添加關(guān)鍵字 NSExtensionJavaScriptPreprocessingFile
予弧,給 Safari 瀏覽器指明使用哪個 JavaScript 文件刮吧。
3.在NSExtensionActivationRule
字典中,將NSExtensionActivationSupportsWebURLWithMaxCount
賦值一個非零的值掖蛤。(更多關(guān)于 NSExtensionActivationRule 字典的知識請參閱 Declaring Supported Data Types for a Share or Action Extension杀捻。)
4.當(dāng)你的應(yīng)用擴(kuò)展開始運(yùn)行時,使用NSItemProvider類獲得運(yùn)行JavaScript文件所返回的結(jié)果蚓庭。
5.在iOS系統(tǒng)的應(yīng)用擴(kuò)展中致讥,如果你希望Safari在擴(kuò)展執(zhí)行完任務(wù)后更新網(wǎng)頁,那么你要向JavaScript文件中傳入值器赞。(在這一步中也使用NSItemProvider
類垢袱。)
為了告知Safari你的應(yīng)用擴(kuò)展中包含一個JavaScript文件,你需要在應(yīng)用擴(kuò)展的Info.plist
文件中拳魁,向NSExtensionAttributes
字典添加NSExtensionJavaScriptPreprocessingFile
關(guān)鍵字來指明你的JavaScript文件惶桐。這個鍵的值就是你希望當(dāng)你的應(yīng)用擴(kuò)展運(yùn)行前,Safari要加載的JavaScript文件的名稱潘懊。比如:
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionJavaScriptPreprocessingFile</key>
<string>MyJavaScriptFile</string> <!-- Do not include the ".js" filename extension -->
</dict>
在iOS和OS X平臺中姚糊,在你自定義的JavaScript類中可以定義一個run()函數(shù),該函數(shù)就是Safari加載JavaScript文件的入口授舟。在run()函數(shù)中救恨,Safari提供了一個名為completionFunction的參數(shù),你可以使用鍵值對象的形式將結(jié)果傳給應(yīng)用擴(kuò)展释树。
在iOS平臺中肠槽,你還可以定義一個finalize()
函數(shù)擎淤,當(dāng)應(yīng)用擴(kuò)展在任務(wù)結(jié)束階段調(diào)用completeRequestReturningItems:expirationHandler:completion:
方法時Safari會調(diào)用finalize()
函數(shù)。在該函數(shù)中秸仙,可以通過向completeRequestReturningItems:expirationHandler:completion:
方法傳值官卡,來改變網(wǎng)頁內(nèi)容弟跑。
比如吨拍,你的iOS應(yīng)用擴(kuò)展需要基于一個網(wǎng)頁URI啟動夭织,并且當(dāng)它結(jié)束運(yùn)行時改變網(wǎng)頁的背景色,那么你需要這樣寫JavaScript代碼:
清單4-1示例run()和finalize()函數(shù)
var MyExtensionJavaScriptClass = function() {};
MyExtensionJavaScriptClass.prototype = {
run: function(arguments) {
// Pass the baseURI of the webpage to the extension.
arguments.completionFunction({"baseURI": document.baseURI});
},
// Note that the finalize function is only available in iOS.
finalize: function(arguments) {
// arguments contains the value the extension provides in [NSExtensionContext completeRequestReturningItems:completion:].
// In this example, the extension provides a color as a returning item.
document.body.style.backgroundColor = arguments["bgColor"];
}
};
// The JavaScript file must contain a global object named "ExtensionPreprocessingJS".
var ExtensionPreprocessingJS = new MyExtensionJavaScriptClass;
在iOS和OS X平臺中捞蛋,你需要編寫代碼來處理run()
函數(shù)返回的值孝冒,為獲取到字典中的值,我們需要指定kUTTypePropertyList
類型作為標(biāo)示符傳入NSItemProvider
類的 loadItemForTypeIdentifier:options:completionHandler:方法拟杉。在該字典中使用 NSExtensionJavaScriptPreprocessingResultsKey
作為key來取值庄涡。比如下面例子中我們想要獲取將 URI 傳入 run()
的返回值:
[imageProvider loadItemForTypeIdentifier:kUTTypePropertyList options:nil completionHandler:^(NSDictionary *item, NSError *error) {
NSDictionary *results = (NSDictionary *)item;
NSString *baseURI = [[results objectForKey:NSExtensionJavaScriptPreprocessingResultsKey] objectForKey:@"baseURI"];
}];
finalize()
函數(shù)是在當(dāng)應(yīng)用擴(kuò)展執(zhí)行完任務(wù)后傳參并調(diào)用的,創(chuàng)建一個含有我們需要處理的值的字典搬设,然后用NSItemProvider
的 initWithItem:typeIdentifier:
方法來封裝該字典穴店。比如當(dāng)擴(kuò)展執(zhí)行完任務(wù)后我們想讓網(wǎng)頁變?yōu)榧t色,我們可以這樣寫:
NSExtensionItem *extensionItem = [[NSExtensionItem alloc] init];
extensionItem.attachments = @[[[NSItemProvider alloc] initWithItem: @{NSExtensionJavaScriptFinalizeArgumentKey: @{@"bgColor":@"red"}} typeIdentifier:(NSString *)kUTTypePropertyList]];
[[self extensionContext] completeRequestReturningItems:@[extensionItem] completion:nil];
執(zhí)行上傳下載任務(wù)
用戶一般的操作習(xí)慣都傾向于當(dāng)使用你的應(yīng)用擴(kuò)展完成某個任務(wù)后拿穴,可以將結(jié)果立即反饋在使用擴(kuò)展的應(yīng)用中迹鹅。如果一個擴(kuò)展要處理的任務(wù)包含較長時間的上傳下載操作時,你要確保當(dāng)你的應(yīng)用擴(kuò)展關(guān)閉后能繼續(xù)完成該任務(wù)贞言。為實(shí)現(xiàn)這個功能,我們需要使用NSURLSession類創(chuàng)建一個URL會話并創(chuàng)建后臺的上傳下載任務(wù)阀蒂。
提示:你可以回想一下其他類型的后臺任務(wù)该窗,比如后臺支持VoIP、后臺播放音樂蚤霞,這些是不能用應(yīng)用擴(kuò)展去實(shí)現(xiàn)的酗失。更多信息請參閱Respond to the Host App’s Request。
當(dāng)你的應(yīng)用擴(kuò)展準(zhǔn)備好上傳下載任務(wù)后昧绣,擴(kuò)展會完成調(diào)用它的應(yīng)用發(fā)出的請求规肴,并在不影響上傳下載任務(wù)的前提下終止擴(kuò)展。更多關(guān)于擴(kuò)展處理載體應(yīng)用請求的知識請參閱Respond to the Host App’s Request夜畴。在iOS系統(tǒng)中拖刃,如果你的應(yīng)用擴(kuò)展在執(zhí)行完后臺任務(wù)時并沒有在運(yùn)行,那么系統(tǒng)會自動在后臺運(yùn)行擴(kuò)展的載體應(yīng)用贪绘,并調(diào)用application:handleEventsForBackgroundURLSession:completionHandler: 代理方法兑牡。
重要提示:如果你的應(yīng)用擴(kuò)展在后臺創(chuàng)建了 NSURLSession 任務(wù),那么你必須要設(shè)置一個共享容器税灌,以確保擴(kuò)展和載體應(yīng)用實(shí)現(xiàn)數(shù)據(jù)共享均函。我們可以在 NSURLSessionConfiguration 類中使用sharedContainerIdentifier屬性來指定一個共享容器的標(biāo)示符亿虽,然后我們就可以通過該標(biāo)示符獲取到共享容器。請參閱 Sharing Data with Your Containing App 文檔來設(shè)置共享容器苞也。
下面的例子展示了如何配置一個URL會話洛勉,并創(chuàng)建一個下載任務(wù):
NSURLSession *mySession = [self configureMySession];
NSURL *url = [NSURL URLWithString:@"http://www.example.com/LargeFile.zip"];
NSURLSessionTask *myTask = [mySession downloadTaskWithURL:url];
[myTask resume];
- (NSURLSession *) configureMySession {
if (!mySession) {
NSURLSessionConfiguration* config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@“com.mycompany.myapp.backgroundsession”];
// To access the shared container you set up, use the sharedContainerIdentifier property on your configuration object.
config.sharedContainerIdentifier = @“com.mycompany.myappgroupidentifier”;
mySession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
}
return mySession;
}
因?yàn)樵趩挝粫r間內(nèi)只能由一個進(jìn)程使用后臺會話,所以你需要為載體應(yīng)用中的所有擴(kuò)展創(chuàng)建不同的后臺會話(每個后臺會話都要有一個唯一的標(biāo)示符)如迟。在這里我們建議當(dāng)載體應(yīng)用在后臺處理擴(kuò)展的任務(wù)時收毫,只使用一個該擴(kuò)展創(chuàng)建的后臺會話。如果你要執(zhí)行其他的網(wǎng)絡(luò)相關(guān)的任務(wù)氓涣,那么就要創(chuàng)建相應(yīng)的URL會話牛哺。
如果你需要在后臺創(chuàng)建URL會話之前完成載體應(yīng)用的請求,那么要確保創(chuàng)建和使用會話的代碼是有效可執(zhí)行的劳吠。當(dāng)你的擴(kuò)展調(diào)用 completeRequestReturningItems:completionHandler: 方法告知主叫應(yīng)用已經(jīng)完成相關(guān)請求后引润,系統(tǒng)就可以隨時終止你的應(yīng)用擴(kuò)展。
為分享和Action擴(kuò)展申明支持的數(shù)據(jù)類型
在你的分享或Action擴(kuò)展中痒玩,在它們的工作中可能會使用到一些數(shù)據(jù)淳附,并且這些數(shù)據(jù)的類型各不相同。為了確保只有當(dāng)用戶在載體應(yīng)用中選擇了你的擴(kuò)展支持的數(shù)據(jù)類型時蠢古,才會展示你的擴(kuò)展功能奴曙。你需要在擴(kuò)展的Info.plist
屬性列表文件中添加 NSExtensionActivationRule
關(guān)鍵字。你也可以使用該關(guān)鍵字指定擴(kuò)展處理每種類型的最大數(shù)目草讶。當(dāng)你的應(yīng)用擴(kuò)展運(yùn)行時洽糟,系統(tǒng)會將NSExtensionActivationRule
鍵的值與擴(kuò)展項(xiàng)的attachments
屬性中的信息進(jìn)行比較。關(guān)于 NSExtensionActivationRule
關(guān)鍵字的詳細(xì)信息可以參閱 Action Extension Keys文檔中的 Information Property List Key Reference 章節(jié)堕战。
比如坤溃,你可以申明你的分享擴(kuò)展支持最多處理10張圖片,一部影片和一個網(wǎng)站URL嘱丢。您可以使用以下字典作為該NSExtensionAttributes
鍵的值:
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>10</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
如果你想指定不支持的數(shù)據(jù)類型薪介,那么你可以將該類型的值設(shè)置為0,或者在 NSExtensionActivationRule 中不添加該類型即可越驻。
注意:如果你的分享擴(kuò)展或iOS中的Action擴(kuò)展需要訪問網(wǎng)頁汁政,那你必須要確保 NSExtensionActivationSupportsWebURLWithMaxCount 關(guān)鍵字的值不為0(更多關(guān)于在應(yīng)用擴(kuò)展中通過JavaScript訪問網(wǎng)頁的內(nèi)容請參閱Accessing a Webpage
你也可以使用 NSExtensionItem 定義的 UTI子 類型以便數(shù)據(jù)檢測器檢測文本信息,比如電話號碼或通訊地址缀旁。
NSExtensionActivationRule
字典中的鍵足以滿足大多數(shù)應(yīng)用的過濾需求记劈。如果你需要做更復(fù)雜的過濾,比如像 public.url
和 public.image
之間的區(qū)別并巍,那么你就得在文本中創(chuàng)建斷言語句抠蚣。如果你要創(chuàng)建一個斷言,那么就將NSExtensionActivationRule
關(guān)鍵字的值設(shè)置為你指定的斷言字符串履澳。(在運(yùn)行時嘶窄,系統(tǒng)會自動將該字符串編譯為 NSPredicate 對象
比如怀跛,一個應(yīng)用擴(kuò)展的附件屬性可以指定為PDF文件,可以這樣寫:
{extensionItems = ({
attachments = ({
registeredTypeIdentifiers = (
"com.adobe.pdf",
"public.file-url"
);
});
})}
為了指定你的應(yīng)用擴(kuò)展可以處理PDF文件柄冲,你可以像這樣創(chuàng)建斷言字符串:
SUBQUERY (
extensionItems,
$extensionItem,
SUBQUERY (
$extensionItem.attachments,
$attachment,
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.adobe.pdf"
).@count == $extensionItem.attachments.@count
).@count == 1
以下是更復(fù)雜的斷言語句的示例:
SUBQUERY (
extensionItems,
$extensionItem,
SUBQUERY (
$extensionItem.attachments,
$attachment,
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "org.appextension.action-one" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "org.appextension.action-two"
).@count == $extensionItem.attachments.@count
).@count == 1
此語句遍歷一個NSExtensionItem
對象數(shù)組吻谋,其次是遍歷attachments
每個擴(kuò)展項(xiàng)中的數(shù)組。對于每個附件现横,謂詞評估附件中每個表示的統(tǒng)一類型標(biāo)識符(UTI)漓拾。當(dāng)附件表示UTI符合兩個不同的指定UTI中的任何一個(您在每個UTI-CONFORMS-TO
操作員的右側(cè)看到)時,收集該UTI以進(jìn)行最終比較測試戒祠。TRUE
如果應(yīng)用程序擴(kuò)展名僅提供了一個支持UTI的擴(kuò)展項(xiàng)附件骇两,則返回最后一行。
開發(fā)過程中姜盈,在你創(chuàng)建斷言語句之前你可以使用TRUEPREDICATE
常量(結(jié)果為true)測試你的代碼路徑低千。更多斷言語句的語法知識請參閱Predicate Format String Syntax。
重要提示:在將你的載體應(yīng)用上傳App Store之前馏颂,要確保所有的 TRUEPREDICATE 常量已經(jīng)替換為指定的斷言語句或 NSExtensionActivationRule 關(guān)鍵字示血,不然載體應(yīng)用會被App Store拒絕。
配置載體應(yīng)用以適用于老版本的iOS系統(tǒng)
如果你在主體應(yīng)用中使用了內(nèi)嵌框架救拉,那么它就可以在iOS8.0之后的版本中使用难审,即便內(nèi)嵌框架不支持老版本的系統(tǒng)也沒關(guān)系。
使主體應(yīng)用能做到上述這一點(diǎn)的是 dlopen
命令亿絮,它可以使你使用條件鏈接和加載框架包的機(jī)制告喊。你可以使用這個命令來代替編譯時鏈接,你可以在 Xcode 的 General 選項(xiàng)或 Build Phases 選項(xiàng)中對該命令進(jìn)行編輯派昧。其原理就是只有當(dāng)主體應(yīng)用在 iOS8.0 或更高的版本中運(yùn)行時葱绒,才會鏈接使用內(nèi)嵌框架。
您必須在有條件地 framework bundle的代碼語句中使用Objective-C而不是Swift斗锭。您的應(yīng)用程序的其余部分可以用任何一種語言編寫,內(nèi)嵌框架本身也可以用任何一種語言編寫失球。
調(diào)用之后dlopen
岖是,使用以下類型的語句訪問內(nèi)嵌框架類:
MyLoadedClass *loadedClass = [[NSClassFromString (@"MyClass") alloc] init];
重要提示:如果你的主體應(yīng)用使用了內(nèi)嵌框架,那么就必須要支持arm64架構(gòu)实苞,否則會被App Store拒絕豺撑。
設(shè)置Xcode項(xiàng)目中應(yīng)用擴(kuò)展的條件鏈接
1.將每一個應(yīng)用擴(kuò)展的運(yùn)行系統(tǒng)版本設(shè)置為iOS8.0或更高,通常選中Xcode中的target黔牵,在General選項(xiàng)中設(shè)置Deployment info聪轿。
2.將你主體應(yīng)用的運(yùn)行系統(tǒng)版本設(shè)置為你想支持的最低iOS版本。
3.在你的主體應(yīng)用中猾浦,通過 systemVersion 方法陆错,在運(yùn)行時檢查判斷iOS的版本灯抛,并判斷是否執(zhí)行dlopen命令。只有你的載體應(yīng)用在iOS8.0或更高的版本中運(yùn)行時才會指定dlopen命令音瓷。進(jìn)行此調(diào)用時对嚼,請務(wù)必使用Objective-C,而不是Swift绳慎。
特定的iOS API通過dlopen命令使用內(nèi)嵌框架纵竖。你必須選擇性的使用這些API,就像使用 dlopen 命令時那樣杏愤。這些API都是 CFBundleRef 的封裝類型:
CFBundleGetFunctionPointerForName
CFBundleGetFunctionPointersforNames
還有來自NSBundle
類的方法:
loadloadAndReturnError:
classNamed:
因?yàn)槟阋话銜⑤d體應(yīng)用的運(yùn)行系統(tǒng)版本配置為較低的版本靡砌,所以這些API通常都是在運(yùn)行時檢查,只有確保載體應(yīng)用在iOS8.0或更高版本中運(yùn)行時才會使用這些API珊楼。