iOS實(shí)現(xiàn)App之間的內(nèi)容分享

前言

我們?cè)趇OS平臺(tái)上想要實(shí)現(xiàn)不同App之間的內(nèi)容分享一般有幾種常用方式:

  1. 第一種是通過(guò)AirDrop實(shí)現(xiàn)不同設(shè)備的App之間文檔和數(shù)據(jù)的分享;
  2. 第二種是給每個(gè)App定義一個(gè)URL Scheme,通過(guò)訪問(wèn)指定了URL Scheme的一個(gè)URL,實(shí)現(xiàn)直接訪問(wèn)一個(gè)APP;
  3. 第三種是通過(guò)UIDocumentInteractionController或者是UIActivityViewController這倆個(gè)iOS SDK中封裝好的類在App之間發(fā)送數(shù)據(jù)、分享數(shù)據(jù)和操作數(shù)據(jù);
  4. 第四種是通過(guò)App Extension,在iOS 8的SDK中提供的擴(kuò)展新特性實(shí)現(xiàn)跨App的數(shù)據(jù)操作和分享;
  5. 還有一種集成第三方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果原生提供的基于iOS SDK的分享技術(shù),同時(shí)推薦倆篇蘋果開發(fā)者中心的文檔:Inter-App CommunicationDocument Interaction Programming Topics for iOS。我們的第一篇文章就談一下如何通過(guò)UTI讓我們的App支持分享。

原理

我在“詳解蘋果提供的UTI(統(tǒng)一類型標(biāo)識(shí)符)“這篇文章中,詳細(xì)地講解了一下UTI(Uniform Type Identifier),一套蘋果給我們提供用來(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開發(fā)中,蘋果給我們提供了注冊(cè)文檔類型的接口,而這種注冊(cè)的文檔類型是全局的,系統(tǒng)中所有的應(yīng)用程序和服務(wù)都可以偵測(cè)到。因此我們通過(guò)這個(gè)底層偵測(cè),可以使用其他可選的第三方App來(lái)預(yù)覽我們的App中不支持的文檔,而且我們還可以通過(guò)這個(gè)接口在我們的App中打開并處理第三方App的文檔。

如果我們的App可以處理某些類型的實(shí)體內(nèi)容,那么我們就可以在我們項(xiàng)目中的Info.plist文件中進(jìn)行注冊(cè)。關(guān)于使用哪種類型和UTI,就要參考我在“詳解蘋果提供的UTI(統(tǒng)一類型標(biāo)識(shí)符)“這篇文章中的講解。當(dāng)一個(gè)第三方App通過(guò)蘋果的底層偵測(cè)技術(shù)檢查有哪些App可以處理它所指定的內(nèi)容類型時(shí),如果我們的App已經(jīng)注冊(cè)了這種類型,那么我們的App圖標(biāo)就會(huì)顯示在其中,并且作為我們自己的App的一個(gè)入口。

主要技術(shù)

主要應(yīng)用到這種底層偵測(cè)的技術(shù)有iOS SDK中給我們提供的UIDocumentInteractionControllerUIActivityViewControllerQuick Look 框架。此外,在iOS 8中,蘋果又給開發(fā)者提供了App Extension,一種更高大上的方式在App之間的實(shí)現(xiàn)分享內(nèi)容。關(guān)于UIDocumentInteractionControllerUIActivityViewControllerQuick 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開發(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í)別從高到低依次是OwnerAlternate,DefaultNone表示不接受這種類型。

了解了這些基本屬性,我們就需要在注冊(cè)App可用類型時(shí),指定這些屬性,根據(jù)每個(gè)項(xiàng)目的需求不同,屬性值也不同。具體的注冊(cè)請(qǐng)參照我的GitHub上的項(xiàng)目:SeraZheng---ZSUTITest。下圖示例作為一個(gè)參照:

在info中添加Document types

而當(dāng)我們添加完所有屬性后,開始運(yùn)行我們的程序,然后再回到我們的Info界面,就會(huì)看到Document types這個(gè)列表已經(jīng)發(fā)生了變化,這就證明我們成功的注冊(cè)好了App可用的類型。

注冊(cè)成功,運(yùn)行程序顯示的結(jié)果

打開第三方應(yīng)用

我們?cè)谏厦娴牟襟E中注冊(cè)好了我們的App可以識(shí)別的類型,現(xiàn)在我們可以打開一個(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)用程序的我的文件中,打開不同類型的文件進(jìn)行對(duì)比,大家可以看下圖我的文件列表中包含倆種類型的文件,一種是.jpg擴(kuò)展名的圖片文件,一種是.pdf擴(kuò)展名的文檔文件。

我的文件列表

當(dāng)我打開一個(gè)圖片文件進(jìn)行預(yù)覽時(shí),點(diǎn)擊其他應(yīng)用打開,就可以在App列表中看到我們的App圖標(biāo)。簡(jiǎn)單介紹一下這個(gè)頁(yè)面,第一行是蘋果在iOS 7之后給我們提供的使用AirDropiPhoneiPadiPod 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ù)制,打印等。

打開圖片,顯示ZSUTITestDemo App圖標(biāo)

而如果我打開PDF文件的話,就看不到我們的App圖標(biāo)。


打開PDF文件,看不到ZSUTITestDemo App圖標(biāo)

程序回調(diào)

當(dāng)我們通過(guò)上面步驟,成功地顯示了ZSUTITestDemo 的圖標(biāo)之后,點(diǎn)擊圖標(biāo),我們就可以跳轉(zhuǎn)到ZSUTITestDemo應(yī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,示例如下圖:

顯示圖片和源程序的Bundle Identifier
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容