iOS中的沙盒可以讓平臺更加的安全,這也是沙盒給用戶帶來的最主要好處。不過由于沙盒的嚴格限制,導致程序之間共享數據比較麻煩。一般在程序間共享文檔可以通過UIDocumentInteractionController類實現通訊。它支持在你的app中用其他app預覽和顯示文檔。同時也支持文件關聯,允許其他app通過你的程序打開文件。這些技術包括了UIKit中提供的UIDocumentInteractionController類(UIDocumentInteractionController Class Reference),以及Quick Look框架(Quick Look Framework Reference)。
本文將就如何在應用之間進行文件共享進行基本探究。還請大牛勿噴。
蘋果官方文檔
效果圖
預覽文檔和呈現選項菜單
如果你的app需要打開它不支持的文件(PDF文件、圖像文件,等等),或者需要將app的文件傳輸給另外一個允許接收此類型文件的app時。可以使用文件交互控制器(UIDocumentInteractionController類的實例)為用戶提供可接收程序來處理文件,說的簡單點就是通過Quick Look框架判斷文檔是否能被另一個app打開和預覽。
UIDocumentInteractionController在iOS3.2中就已經存在了,使用起來非常靈活,功能也比較強大。它除了支持同設備上app之間的文檔共享外,還可以實現文檔的預覽、打印、發郵件以及復制。
要使用一個文件交互控制器(UIDocumentInteractionController類的實例),需要以下步驟:
- 為每個你想打開的文件創建一個UIDocumentInteractionController類的實例
- 實現UIDocumentInteractionControllerDelegate代理
- 顯示預覽窗口/顯示菜單。
一、創建實例
DocumentInteraction Controller使用靜態方法interactionControllerWithURL創建實例,這個方法使用一個NSURL作為參數。
//創建實例
NSURL *filePath = [NSURL fileURLWithPath:path];UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
二、顯示預覽窗口
Document Interaction Controller對象使用presentPreviewAnimated方法彈出一個全屏的文檔預覽窗口。
BOOL b = [documentController presentPreviewAnimated:YES];
三、顯示菜單
如果你不想在本應用里面打開文件,那么可以通過第三方應用打開預覽文件。通過OptionsMenu
(選項菜單),顯示能夠接收該類型文件的應用,由用戶選擇相應的操作。
顯示菜單可以使用下列方法:
- presentOptionsMenuFromRect:inView:animated:
- presentOptionsMenuFromBarButtonItem:animated:
- presentOpenInMenuFromRect:inView:animated:
- presentOpenInMenuFromBarButtonItem:animated:
這些方法都是類似的,只是顯示位置有區別而已。以下代碼演示其中一個方法的使用。
CGRect navRect = self.navigationController.navigationBar.frame;
navRect.size = CGSizeMake(1500.0f, 40.0f);
[documentController presentOptionsMenuFromRect:navRectinView:self.viewanimated:YES];
四、使用委托
如果你顯示一個Document Interaction Controller ,則必需要為delegate屬性用指定一個委托。讓委托告訴DocumentInteraction Controller如何顯示。
documentController.delegate = self;
委托對象需要實現一系列委托方法,最常見的包括:
- documentInteractionControllerViewControllerForPreview:
- documentInteractionControllerViewForPreview:
- documentInteractionControllerRectForPreview:
這3個方法在用戶點擊“快速查看”菜單時依次調用。
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller {return self;
}
- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller {return self.view;
}- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController *)controller {return self.view.frame;}//點擊預覽窗口的“Done”(完成)按鈕時調用
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller {
}
功能一:分享文件
- (void)shareFile {NSString *filePath = [[NSBundle mainBundle] pathForResource:@"皮卡丘"ofType:@"jpeg"];//創建實例UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];//設置代理documentController.delegate = self;BOOL canOpen = [documentController presentOpenInMenuFromRect:CGRectZeroinView:self.viewanimated:YES];if (!canOpen) {NSLog(@"沒有程序可以打開要分享的文件");}
}
功能二:預覽文件(注冊應用程序支持的文件類型)
- (void)preview {if (!_path) {return;}NSURL *fileURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self getURL], [_path lastPathComponent]]];//創建實例UIDocumentInteractionController *documentController =[UIDocumentInteractionControllerinteractionControllerWithURL:fileURL];//設置代理documentController.delegate = self;[documentController presentPreviewAnimated:YES];
}
配置Info.plist文件
如果你的程序能夠打開某種文件,你可以向系統進行注冊。方便其他程序通過 iOS 的
document interaction
技術提供給用戶一個選擇,從而調用你的程序處理這些文件。這需要在程序的
Info.plist
文件中添加CFBundleDocumentTypes
鍵(查看CoreFoundation Keys)。系統將該鍵中包含的內容進行登記,這樣其他程序就可以通過
document interaction controller
訪問到這些信息。
CFBundleDocumentTypes
鍵是一個dictionary數組,每個dictionary表示了一個指定的文檔類型。一個文檔類型通常與某種文件類型是一一對應的。但是,如果你的程序對多個文件類型采用同樣的處理方式,你也可以把這些類型都分成一個組,統一視作一個文檔類型。**例如,你的程序中使用到的本地文檔類型,有一個是舊格式的,還有一個新格式(似乎是影射微軟office文檔),則你可以將二者分成一組,都放到同一個文檔類型下。這樣,舊格式和新格式的文件都將顯示為同一個文檔類型,并以同樣的方式打開。**
CFBundleDocumentTypes
數組中的每個 dictionary 可能包含以下鍵:
-
CFBundleTypeName
指定文檔類型名稱。
-
CFBundleTypeIconFiles
是一個數組,包含多個圖片文件名,用于作為該文檔的圖標。
-
LSItemContentTypes
是一個數組,包含多個
UTI
【Uniform Type Identifiers】類型的字符串。UTI
類型是本文檔類型(組)所包含的文件類型。 -
LSHandlerRank
表示應用程序是“擁有”還是僅僅是“打開”這種類型而已。
下表列出了Info.plist
中的一個CFBundleTypeName
官方示例。
-
自定義文件格式的文檔類型
<dict> <key>CFBundleTypeName</key> <string>My File Format</string> <key>CFBundleTypeIconFiles</key><array><string>MySmallIcon.png</string><string>MyLargeIcon.png</string></array> <key>LSItemContentTypes</key><array><string>com.example.myformat</string></array> <key>LSHandlerRank</key> <string>Owner</string> </dict>
-
自己程序配置文件
<key>CFBundleDocumentTypes</key> <array><dict><key>CFBundleTypeName</key><string>com.myapp.common-data</string><key>LSItemContentTypes</key><array><string>com.microsoft.powerpoint.ppt</string><string>public.item</string><string>com.microsoft.word.doc</string><string>com.adobe.pdf</string><string>com.microsoft.excel.xls</string><string>public.image</string><string>public.content</string><string>public.composite-content</string><string>public.archive</string><string>public.audio</string><string>public.movie</string><string>public.text</string><string>public.data</string></array></dict> </array>
打開支持的文件類型
你可以在應用程序委托的application:didFinishLaunchingWithOptions:
方法中獲得該文件的信息。如果你的程序要處理某些自定義的文件類型,你必須實現這個委托方法(而不是applicationDidFinishLaunching: 方法) 并用這個方法啟動應用程序。
application:didFinishLaunchingWithOptions:
方法的option
參數包含了要打開的文件的相關信息。尤其需要在程序中關心下列鍵:
-
UIApplicationLaunchOptionsURLKey
包含了該文件的NSURL。
-
UIApplicationLaunchOptionsSourceApplicationKey
包含了發送請求的應用程序的 Bundle ID。
-
UIApplicationLaunchOptionsAnnotationKey
包含了源程序向目標程序傳遞的與該文件相關的屬性列表對象。
如果UIApplicationLaunchOptionsURLKey
鍵存在,你的程序應當立即用該 URL 打開該文件并將內容呈現給用戶。其他鍵可用于收集與打開的文件相關的參數和信息。
如果你的應用程序處于活躍狀態,此時application:didFinishLaunchingWithOptions:
方法是不會被調用的。需要實現application:openURL:options:
方法
【以下是本人的寫法】
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {_vc = [[ViewController alloc] init];UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:_vc];self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];self.window.backgroundColor = [UIColor whiteColor];self.window.rootViewController = nav;[self.window makeKeyAndVisible];if (launchOptions) {NSString *str = [NSString stringWithFormat:@"\n發送請求的應用程序的 Bundle ID:%@\n\n文件的NSURL:%@\n\n文件相關的屬性列表對象:%@",launchOptions[UIApplicationLaunchOptionsSourceApplicationKey],launchOptions[UIApplicationLaunchOptionsURLKey],launchOptions[UIApplicationLaunchOptionsSourceApplicationKey]];[[[UIAlertView alloc] initWithTitle:@""message:strdelegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil, nil] show];_vc.path = [launchOptions[UIApplicationLaunchOptionsURLKey] description];[_vc preview];}return YES;
}- (BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<NSString *,id> *)options {if (options) {NSString *str = [NSString stringWithFormat:@"\n發送請求的應用程序的 Bundle ID:%@\n\n文件的NSURL:%@", options[UIApplicationOpenURLOptionsSourceApplicationKey], url];[[[UIAlertView alloc] initWithTitle:@""message:strdelegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil, nil] show];_vc.path = [url description];[_vc preview];}return YES;
}