前言
我們?cè)趇OS平臺(tái)上想要實(shí)現(xiàn)不同App之間的內(nèi)容分享一般有幾種常用方式:
- 第一種是通過(guò)
AirDrop
實(shí)現(xiàn)不同設(shè)備的App之間文檔和數(shù)據(jù)的分享; - 第二種是給每個(gè)App定義一個(gè)URL Scheme,通過(guò)訪問(wèn)指定了URL Scheme的一個(gè)URL,實(shí)現(xiàn)直接訪問(wèn)一個(gè)APP;
- 第三種是通過(guò)
UIDocumentInteractionController
或者是UIActivityViewController
這倆個(gè)iOS SDK中封裝好的類在App之間發(fā)送數(shù)據(jù)、分享數(shù)據(jù)和操作數(shù)據(jù); - 第四種是通過(guò)
App Extension
,在iOS 8的SDK中提供的擴(kuò)展新特性實(shí)現(xiàn)跨App的數(shù)據(jù)操作和分享; - 還有一種集成第三方SDK實(shí)現(xiàn)的有限個(gè)App的數(shù)據(jù)分享,比如社交平臺(tái)(QQ,微信,新浪微博等)給我們提供的官方SDK,或者是集成了多個(gè)社交平臺(tái)的ShareSDK組件和友盟分享組件等。
關(guān)于集成第三方SDK的使用,各大平臺(tái)官網(wǎng)上都有詳細(xì)的文檔說(shuō)明,因此我們這系列文章主要是來(lái)談?wù)勌O(píng)果原生提供的基于iOS SDK的分享技術(shù),同時(shí)推薦倆篇蘋(píng)果開(kāi)發(fā)者中心的文檔:Inter-App Communication和Document Interaction Programming Topics for iOS。我們的第一篇文章就談一下如何通過(guò)UTI讓我們的App支持分享。
原理
我在“詳解蘋(píng)果提供的UTI(統(tǒng)一類型標(biāo)識(shí)符)“這篇文章中,詳細(xì)地講解了一下UTI(Uniform Type Identifier)
,一套蘋(píng)果給我們提供用來(lái)在基于Cocoa和Cocoa Touch應(yīng)用程序中識(shí)別實(shí)體內(nèi)容類型的規(guī)范,而關(guān)于實(shí)現(xiàn)內(nèi)容關(guān)聯(lián)的技術(shù)也正是基于這套規(guī)范。在iOS和Mac OS開(kāi)發(fā)中,蘋(píng)果給我們提供了注冊(cè)文檔類型的接口,而這種注冊(cè)的文檔類型是全局的,系統(tǒng)中所有的應(yīng)用程序和服務(wù)都可以偵測(cè)到。因此我們通過(guò)這個(gè)底層偵測(cè),可以使用其他可選的第三方App
來(lái)預(yù)覽我們的App
中不支持的文檔,而且我們還可以通過(guò)這個(gè)接口在我們的App
中打開(kāi)并處理第三方App
的文檔。
如果我們的App可以處理某些類型的實(shí)體內(nèi)容,那么我們就可以在我們項(xiàng)目中的Info.plist
文件中進(jìn)行注冊(cè)。關(guān)于使用哪種類型和UTI,就要參考我在“詳解蘋(píng)果提供的UTI(統(tǒng)一類型標(biāo)識(shí)符)“這篇文章中的講解。當(dāng)一個(gè)第三方App通過(guò)蘋(píng)果的底層偵測(cè)技術(shù)檢查有哪些App可以處理它所指定的內(nèi)容類型時(shí),如果我們的App已經(jīng)注冊(cè)了這種類型,那么我們的App圖標(biāo)就會(huì)顯示在其中,并且作為我們自己的App的一個(gè)入口。
主要技術(shù)
主要應(yīng)用到這種底層偵測(cè)的技術(shù)有iOS SDK中給我們提供的UIDocumentInteractionController
、UIActivityViewController
和Quick Look 框架
。此外,在iOS 8中,蘋(píng)果又給開(kāi)發(fā)者提供了App Extension
,一種更高大上的方式在App之間的實(shí)現(xiàn)分享內(nèi)容。關(guān)于UIDocumentInteractionController
、UIActivityViewController
、Quick Look 框架
以及App Extension
的細(xì)節(jié),我計(jì)劃在后面的文章中詳細(xì)講解。這篇文章,我們主要是來(lái)談?wù)?code>如何注冊(cè)我們App可用的文檔類型以及簡(jiǎn)單使用我們的App來(lái)處理第三方App分享的內(nèi)容
。
注冊(cè)可用類型
我們需要在info.plist
文件中,添加一個(gè)新的屬性CFBundleDocumentTypes
(實(shí)際上輸入的是"Document types"
),這是一個(gè)數(shù)組類型的屬性,意思就是我們可以同時(shí)注冊(cè)多個(gè)類型。而針對(duì)數(shù)組中的每一個(gè)元素,都有許多屬性可以指定,詳細(xì)的屬性列表我們可以從官方文檔上找到: Core Foundation Keys ---- CFBundleDocumentTypes。這里列舉我們?cè)谧鰅OS開(kāi)發(fā)時(shí)常用的屬性:
- CFBundleTypeName(
"Icon File Name"
)
字符串類型,指定某種類型的別名,也就是用來(lái)指代我們規(guī)定的類型的別稱,一般為了保持唯一性,我們使用UTI來(lái)標(biāo)識(shí)。 - CFBundleTypeIconFiles
數(shù)組類型,包含指定的png圖標(biāo)的文件名,指定代表某種類型的圖標(biāo),而圖標(biāo)有具體的尺寸標(biāo)識(shí):
|Device |Sizes |
|:------|:---------|
|iPad |64 x 64 pixels, 320 x 320 pixels|
|iPhone and iPod touch|22 x 29 pixels, 44 x 58 pixels (high resolution)|
- LSItemContentTypes(
"Document Content Type UTIs"
)
數(shù)組類型,包含UTI字符串,指定我們的應(yīng)用程序所有可以識(shí)別的類型集合 - LSHandlerRank(
"Handler rank"
)
字符串類型,包含Owner
,Default
,Alternate
,None
四個(gè)可選值,指定對(duì)于某種類型的優(yōu)先權(quán)級(jí)別,而Launcher Service
會(huì)根據(jù)這個(gè)優(yōu)先級(jí)別來(lái)排列顯示的App的順序。優(yōu)先級(jí)別從高到低依次是Owner
,Alternate
,Default
。None
表示不接受這種類型。
了解了這些基本屬性,我們就需要在注冊(cè)App可用類型時(shí),指定這些屬性,根據(jù)每個(gè)項(xiàng)目的需求不同,屬性值也不同。具體的注冊(cè)請(qǐng)參照我的GitHub上的項(xiàng)目:SeraZheng---ZSUTITest。下圖示例作為一個(gè)參照:
而當(dāng)我們添加完所有屬性后,開(kāi)始運(yùn)行我們的程序,然后再回到我們的Info界面,就會(huì)看到Document types
這個(gè)列表已經(jīng)發(fā)生了變化,這就證明我們成功的注冊(cè)好了App可用的類型。
打開(kāi)第三方應(yīng)用
我們?cè)谏厦娴牟襟E中注冊(cè)好了我們的App可以識(shí)別的類型,現(xiàn)在我們可以打開(kāi)一個(gè)使用UIDocumentInteractionController
或者是Quick Look
框架來(lái)展示內(nèi)容的第三方App,這里以iPhone 上的QQ程序?yàn)槔?/p>
我們?cè)谏厦娴淖?cè)步驟中,注冊(cè)的LSItemContentTypes
僅包含了public.image
這個(gè)UTI。所以我們先從QQ應(yīng)用程序的我的文件
中,打開(kāi)不同類型的文件進(jìn)行對(duì)比,大家可以看下圖我的文件
列表中包含倆種類型的文件,一種是.jpg
擴(kuò)展名的圖片文件,一種是.pdf
擴(kuò)展名的文檔文件。
當(dāng)我打開(kāi)一個(gè)圖片文件進(jìn)行預(yù)覽時(shí),點(diǎn)擊其他應(yīng)用打開(kāi)
,就可以在App列表中看到我們的App圖標(biāo)。簡(jiǎn)單介紹一下這個(gè)頁(yè)面,第一行是蘋(píng)果在iOS 7之后給我們提供的使用AirDrop
在iPhone
、iPad
或iPod Touch
設(shè)備之間通過(guò)iCloud
共享內(nèi)容的一種方式。第二行是通過(guò)文檔類型關(guān)聯(lián)技術(shù)識(shí)別的App的列表。第三行是通過(guò)文檔關(guān)聯(lián)技術(shù)識(shí)別的Action
的列表,Action
表示對(duì)文檔可進(jìn)行的操作,如復(fù)制,打印等。
而如果我打開(kāi)PDF文件的話,就看不到我們的App圖標(biāo)。
程序回調(diào)
當(dāng)我們通過(guò)上面步驟,成功地顯示了ZSUTITestDemo
的圖標(biāo)之后,點(diǎn)擊圖標(biāo),我們就可以跳轉(zhuǎn)到ZSUTITestDemo
應(yīng)用中,而蘋(píng)果在iOS SDK中給我們提供的接收回調(diào)的方法在iOS 9之后做出了改變,因此我們需要針對(duì)不同的設(shè)備版本做出改變:
#if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation
{
UINavigationController *navigation = (UINavigationController *)application.keyWindow.rootViewController;
ViewController *displayController = (ViewController *)navigation.topViewController;
[displayController.imageView setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:url]]];
[displayController.label setText:sourceApplication];
return YES;
}
#else
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(nonnull NSDictionary<NSString *,id> *)options
{
UINavigationController *navigation = (UINavigationController *)application.keyWindow.rootViewController;
ViewController *displayController = (ViewController *)navigation.topViewController;
[displayController.imageView setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:url]]];
[displayController.label setText:[options objectForKey:UIApplicationOpenURLOptionsSourceApplicationKey]];
return YES;
}
#endif
Demo示例可以從GitHub項(xiàng)目上參照代碼:SeraZheng---ZSUTITest。當(dāng)點(diǎn)擊ZSUTITestDemo
程序圖標(biāo)回到調(diào)用代碼中,我們可以在這里做各種我們想做的事,如上傳圖片、預(yù)覽圖片、操作圖片等等。我只對(duì)圖片做了簡(jiǎn)單的預(yù)覽顯示,然后顯示文件的源程序的Bundle Identifier
,示例如下圖: