前言
我們在iOS平臺上想要實現(xiàn)不同App之間的內(nèi)容分享一般有幾種常用方式:
- 第一種是通過
AirDrop
實現(xiàn)不同設(shè)備的App之間文檔和數(shù)據(jù)的分享肴楷; - 第二種是給每個App定義一個URL Scheme,通過訪問指定了URL Scheme的一個URL撰筷,實現(xiàn)直接訪問一個APP;
- 第三種是通過
UIDocumentInteractionController
或者是UIActivityViewController
這倆個iOS SDK中封裝好的類在App之間發(fā)送數(shù)據(jù)、分享數(shù)據(jù)和操作數(shù)據(jù); - 第四種是通過
App Extension
惕蹄,在iOS 8的SDK中提供的擴(kuò)展新特性實現(xiàn)跨App的數(shù)據(jù)操作和分享; - 還有一種集成第三方SDK實現(xiàn)的有限個App的數(shù)據(jù)分享治专,比如社交平臺(QQ,微信,新浪微博等)給我們提供的官方SDK卖陵,或者是集成了多個社交平臺的ShareSDK組件和友盟分享組件等。
關(guān)于集成第三方SDK的使用张峰,各大平臺官網(wǎng)上都有詳細(xì)的文檔說明泪蔫,因此我們這系列文章主要是來談?wù)勌O果原生提供的基于iOS SDK的分享技術(shù),同時推薦倆篇蘋果開發(fā)者中心的文檔:Inter-App Communication和Document Interaction Programming Topics for iOS喘批。我們的第一篇文章就談一下如何通過UTI讓我們的App支持分享撩荣。
原理
我在“詳解蘋果提供的UTI(統(tǒng)一類型標(biāo)識符)“這篇文章中,詳細(xì)地講解了一下UTI(Uniform Type Identifier)
,一套蘋果給我們提供用來在基于Cocoa和Cocoa Touch應(yīng)用程序中識別實體內(nèi)容類型的規(guī)范饶深,而關(guān)于實現(xiàn)內(nèi)容關(guān)聯(lián)的技術(shù)也正是基于這套規(guī)范餐曹。在iOS和Mac OS開發(fā)中,蘋果給我們提供了注冊文檔類型的接口敌厘,而這種注冊的文檔類型是全局的台猴,系統(tǒng)中所有的應(yīng)用程序和服務(wù)都可以偵測到。因此我們通過這個底層偵測俱两,可以使用其他可選的第三方App
來預(yù)覽我們的App
中不支持的文檔饱狂,而且我們還可以通過這個接口在我們的App
中打開并處理第三方App
的文檔。
如果我們的App可以處理某些類型的實體內(nèi)容宪彩,那么我們就可以在我們項目中的Info.plist
文件中進(jìn)行注冊休讳。關(guān)于使用哪種類型和UTI,就要參考我在“詳解蘋果提供的UTI(統(tǒng)一類型標(biāo)識符)“這篇文章中的講解尿孔。當(dāng)一個第三方App通過蘋果的底層偵測技術(shù)檢查有哪些App可以處理它所指定的內(nèi)容類型時衍腥,如果我們的App已經(jīng)注冊了這種類型磺樱,那么我們的App圖標(biāo)就會顯示在其中,并且作為我們自己的App的一個入口婆咸。
主要技術(shù)
主要應(yīng)用到這種底層偵測的技術(shù)有iOS SDK中給我們提供的UIDocumentInteractionController
、UIActivityViewController
和Quick Look 框架
。此外,在iOS 8中低千,蘋果又給開發(fā)者提供了App Extension
想罕,一種更高大上的方式在App之間的實現(xiàn)分享內(nèi)容。關(guān)于UIDocumentInteractionController
渊抄、UIActivityViewController
、Quick Look 框架
以及App Extension
的細(xì)節(jié),我計劃在后面的文章中詳細(xì)講解需五。這篇文章,我們主要是來談?wù)?code>如何注冊我們App可用的文檔類型以及簡單使用我們的App來處理第三方App分享的內(nèi)容
轧坎。
注冊可用類型
我們需要在info.plist
文件中宏邮,添加一個新的屬性CFBundleDocumentTypes
(實際上輸入的是"Document types"
),這是一個數(shù)組類型的屬性缸血,意思就是我們可以同時注冊多個類型蜜氨。而針對數(shù)組中的每一個元素,都有許多屬性可以指定捎泻,詳細(xì)的屬性列表我們可以從官方文檔上找到: Core Foundation Keys ---- CFBundleDocumentTypes飒炎。這里列舉我們在做iOS開發(fā)時常用的屬性:
- CFBundleTypeName(
"Icon File Name"
)
字符串類型,指定某種類型的別名笆豁,也就是用來指代我們規(guī)定的類型的別稱郎汪,一般為了保持唯一性,我們使用UTI來標(biāo)識闯狱。 - CFBundleTypeIconFiles
數(shù)組類型煞赢,包含指定的png圖標(biāo)的文件名,指定代表某種類型的圖標(biāo)扩氢,而圖標(biāo)有具體的尺寸標(biāo)識:
|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)用程序所有可以識別的類型集合 - LSHandlerRank(
"Handler rank"
)
字符串類型录豺,包含Owner
,Default
,Alternate
,None
四個可選值朦肘,指定對于某種類型的優(yōu)先權(quán)級別,而Launcher Service
會根據(jù)這個優(yōu)先級別來排列顯示的App的順序双饥。優(yōu)先級別從高到低依次是Owner
媒抠,Alternate
,Default
。None
表示不接受這種類型咏花。
了解了這些基本屬性趴生,我們就需要在注冊App可用類型時阀趴,指定這些屬性,根據(jù)每個項目的需求不同苍匆,屬性值也不同刘急。具體的注冊請參照我的GitHub上的項目:SeraZheng---ZSUTITest。下圖示例作為一個參照:
而當(dāng)我們添加完所有屬性后浸踩,開始運行我們的程序叔汁,然后再回到我們的Info界面,就會看到Document types
這個列表已經(jīng)發(fā)生了變化检碗,這就證明我們成功的注冊好了App可用的類型据块。
打開第三方應(yīng)用
我們在上面的步驟中注冊好了我們的App可以識別的類型折剃,現(xiàn)在我們可以打開一個使用UIDocumentInteractionController
或者是Quick Look
框架來展示內(nèi)容的第三方App另假,這里以iPhone 上的QQ程序為例。
我們在上面的注冊步驟中怕犁,注冊的LSItemContentTypes
僅包含了public.image
這個UTI边篮。所以我們先從QQ應(yīng)用程序的我的文件
中,打開不同類型的文件進(jìn)行對比因苹,大家可以看下圖我的文件
列表中包含倆種類型的文件苟耻,一種是.jpg
擴(kuò)展名的圖片文件,一種是.pdf
擴(kuò)展名的文檔文件扶檐。
當(dāng)我打開一個圖片文件進(jìn)行預(yù)覽時凶杖,點擊其他應(yīng)用打開
,就可以在App列表中看到我們的App圖標(biāo)款筑。簡單介紹一下這個頁面智蝠,第一行是蘋果在iOS 7之后給我們提供的使用AirDrop
在iPhone
、iPad
或iPod Touch
設(shè)備之間通過iCloud
共享內(nèi)容的一種方式奈梳。第二行是通過文檔類型關(guān)聯(lián)技術(shù)識別的App的列表杈湾。第三行是通過文檔關(guān)聯(lián)技術(shù)識別的Action
的列表,Action
表示對文檔可進(jìn)行的操作攘须,如復(fù)制漆撞,打印等。
而如果我打開PDF文件的話浮驳,就看不到我們的App圖標(biāo)。
程序回調(diào)
當(dāng)我們通過上面步驟至会,成功地顯示了ZSUTITestDemo
的圖標(biāo)之后,點擊圖標(biāo)谱俭,我們就可以跳轉(zhuǎn)到ZSUTITestDemo
應(yīng)用中奉件,而蘋果在iOS SDK中給我們提供的接收回調(diào)的方法在iOS 9之后做出了改變宵蛀,因此我們需要針對不同的設(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項目上參照代碼:SeraZheng---ZSUTITest。當(dāng)點擊ZSUTITestDemo
程序圖標(biāo)回到調(diào)用代碼中县貌,我們可以在這里做各種我們想做的事术陶,如上傳圖片、預(yù)覽圖片煤痕、操作圖片等等瞳别。我只對圖片做了簡單的預(yù)覽顯示,然后顯示文件的源程序的Bundle Identifier
杭攻,示例如下圖: