Cod*_*aFi 49 cocoa-touch objective-c ios uidocumentinteraction
我需要让我的应用程序打开来自Safari和Mail应用程序的文档,并在UIDocumentInteractionController
课堂上打开"Open In ..." .我该如何做到这一点?
Cod*_*aFi 97
我知道这对我来说是一个非常令人沮丧的程序员,现在甚至是一个技术熟练的程序员.通过Mail和Safari应用程序的文件I/O涉及应用程序本身内有趣的命名约定.因此,让我们亲自动手使用适用于iPhone的Xcode项目.打开Xcode(我将在本教程中使用4.2)并选择"单视图"应用程序模板(或创建一个空项目,然后使用.xib添加单个视图).
在新创建的应用程序中,将视图控制器(和关联的xib)重命名为OfflineReaderViewController
,然后我们将开始使用代码.(我们将触摸每个文件,但前缀标题和main.m,所以请注意,你需要在你面前的所有内容!)
输入AppDelegate标头并将以下代码粘贴到其中:
#import <UIKit/UIKit.h>
@class OfflineReaderViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) OfflineReaderViewController *viewController;
@end
Run Code Online (Sandbox Code Playgroud)
然后输入Delegate的.m文件并逐字粘贴以下代码:
#import "AppDelegate.h"
#import "OfflineReaderViewController.h"
@implementation AppDelegate
@synthesize window;
@synthesize viewController;
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
// Make sure url indicates a file (as opposed to, e.g., http://)
if (url != nil && [url isFileURL]) {
// Tell our OfflineReaderViewController to process the URL
[self.viewController handleDocumentOpenURL:url];
}
// Indicate that we have successfully opened the URL
return YES;
}
Run Code Online (Sandbox Code Playgroud)
- (void)dealloc
{
[window release];
[viewController release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[OfflineReaderViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}
@end
Run Code Online (Sandbox Code Playgroud)
这个:
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
if (url != nil && [url isFileURL]) {
[self.viewController handleDocumentOpenURL:url];
}
return YES;
}
Run Code Online (Sandbox Code Playgroud)
这是本教程中最重要的部分.将其分解为各自的部分:-(BOOL)application:(UIApplication *)application
是我们的示例应用程序; openURL:(NSURL *)url
是发送给我们告诉我们打开什么的URL; sourceApplication:(NSString *)sourceApplication
是发送链接的应用程序; 并且annotation:(id)annotation
是我们不会涉及的额外功能.
现在,我们必须布局我们的xib.输入xib(应该标题为'OfflineReaderViewController',但它与xib无关,除非我们调用initWithNibName:
(我们不会)),并使其如下图所示:
进入UIWebView
"属性"并选中"缩放页面以适应" 非常重要,因为这样我们可以通过捏合放大和缩小网页.暂时不要担心连接,我们很快就会创建它们.
输入OfflineReaderViewController
标题并粘贴以下内容:
#import <UIKit/UIKit.h>
@interface OfflineReaderViewController : UIViewController
<UIDocumentInteractionControllerDelegate> {
IBOutlet UIWebView *webView;
}
-(void)openDocumentIn;
-(void)handleDocumentOpenURL:(NSURL *)url;
-(void)displayAlert:(NSString *) str;
-(void)loadFileFromDocumentsFolder:(NSString *) filename;
-(void)listFilesFromDocumentsFolder;
- (IBAction) btnDisplayFiles;
@end
Run Code Online (Sandbox Code Playgroud)
现在.m:
#import "OfflineReaderViewController.h"
@implementation OfflineReaderViewController
UIDocumentInteractionController *documentController;
-(void)openDocumentIn {
NSString * filePath =
[[NSBundle mainBundle]
pathForResource:@"Minore" ofType:@"pdf"];
documentController =
[UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
documentController.delegate = self;
[documentController retain];
documentController.UTI = @"com.adobe.pdf";
[documentController presentOpenInMenuFromRect:CGRectZero
inView:self.view
animated:YES];
}
-(void)documentInteractionController:(UIDocumentInteractionController *)controller
willBeginSendingToApplication:(NSString *)application {
}
-(void)documentInteractionController:(UIDocumentInteractionController *)controller
didEndSendingToApplication:(NSString *)application {
}
-(void)documentInteractionControllerDidDismissOpenInMenu:
(UIDocumentInteractionController *)controller {
}
-(void) displayAlert:(NSString *) str {
UIAlertView *alert =
[[UIAlertView alloc] initWithTitle:@"Alert"
message:str
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
- (void)handleDocumentOpenURL:(NSURL *)url {
[self displayAlert:[url absoluteString]];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView setUserInteractionEnabled:YES];
[webView loadRequest:requestObj];
}
-(void)loadFileFromDocumentsFolder:(NSString *) filename {
//---get the path of the Documents folder---
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory
stringByAppendingPathComponent:filename];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
[self handleDocumentOpenURL:fileUrl];
}
-(void)listFilesFromDocumentsFolder {
//---get the path of the Documents folder---
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *fileList =
[manager contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSMutableString *filesStr =
[NSMutableString stringWithString:@"Files in Documents folder \n"];
for (NSString *s in fileList){
[filesStr appendFormat:@"%@ \n", s];
}
[self displayAlert:filesStr];
[self loadFileFromDocumentsFolder:@"0470918020.pdf"];
}
- (IBAction) btnDisplayFiles {
[self listFilesFromDocumentsFolder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self openDocumentIn];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end
Run Code Online (Sandbox Code Playgroud)
那些积极观看并且不仅仅是复制我告诉你的所有内容(开玩笑)的人都会知道这一行:[[NSBundle mainBundle] pathForResource:@"Minore" ofType:@"pdf"];
会给我们一个SIGABRT,因为,该文件不存在!所以,拖动你从哪里拉出的任何通用PDF(我在这里推荐,因为谁不花时间阅读大量的文档?),然后复制它的标题并将其粘贴,后缀(.pdf)被删除; 该ofType:@"pdf"
部分为我们处理.当你完成它时,该行应该如下所示:[[NSBundle mainBundle] pathForResource:@"//file name//" ofType:@"pdf"];
现在回到xib并连接它们IBOutlets
!总而言之,这是您的"文件所有者"标签应如下所示:
看来我们已经完成了......但是等等!我们没有做任何事情来启动和运行"Open In ..."菜单!好吧,事实证明,必须在.plist文件中存在一些问题.打开应用程序.plist(快速右键单击,然后选择打开方式>源代码)并粘贴以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFiles</key>
<array/>
<key>CFBundleIdentifier</key>
<string>CodaFi.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>PDF Document</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>
<array>
<string>com.adobe.pdf</string>
</array>
</dict>
</array>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)
[旁注:在任何plist的源代码中都要小心,如果你不知道你在做什么,你可能会得到可怕的'这个文件已被损坏'来自Xcode的错误]
如果要右键单击并选择打开方式>属性列表,它将如下所示:
还有另一个非常重要的领域叫做"应用程序支持iTunes文件共享".必须将其设置为"YES",否则您的应用程序将不会在iTunes中显示为支持文件共享.
"文档类型"字段指定了我们的示例可以打开的文档类型.展开箭头以查找其角色和UTI.这些是每种文件都有的唯一标识符(唯一类型标识符;现在看起来很明显是什么缩写,不是吗?).UTI是让发现者用文件类型的优秀本地化图像替换通用文档图像的东西(不要相信我,将一个不重要的文件扩展名重命名为.ouhbasdvluhb并尝试获得一个漂亮的图片!)如果我想打开我的自己的自定义格式(比如说.code文件)然后我会com.CodaFi.code
在UTI字段中输入类似的东西(对于那些没有线索的人反向DNS表示法),文档类型名称将是"CodaFi Document".处理程序等级和角色应该是直截了当的,因为我们的处理程序等级是备用的(因为我们不拥有文件)而我们的角色是查看器(因为我们不需要任何更重要的东西.我们的示例只是一个查看器而不是编辑器,所以我们会这样离开.
为了供将来参考,UTI有来自受尊敬的来源(甲骨文,微软,甚至是苹果本身)的官方系统声明的命名方案,可以在统一类型标识符参考指南中找到,但是为了迂实而列在这里.
现在,让我们跑吧!代码应该构建没有错误,假设你逐字复制并使那些darned xib连接正确.现在,当您首次启动应用程序时,您应该会看到在iBooks中打开文档的选项.取消选择它,代码的真正含义是打开其他文档!启动Safari并搜索Safari可以QuickLook或打开的任何PDF.然后在"打开..."菜单中,我们的应用程序显示出来!点击它.你会得到一个小的switcheroo动画,一个警报会提出文件的位置.当你解雇它时,UIWebView
意志已经加载了PDF.Mail应用程序具有与附件类似的功能.您也可以将这些PDF调用到您的应用程序.
就是这样,一切都完成了.享受和快乐的编码!
有一个极好的回答这个问题在这里.为了清楚起见,我已经复制了下面的一些答案,但你应该参考那个问题来获得完整的答案.
文件类型处理是iPhone OS 3.2的新增功能,与现有的自定义URL方案不同.您可以注册应用程序以处理特定的文档类型,任何使用文档控制器的应用程序都可以将这些文档的处理交给您自己的应用程序.
要注册支持,您需要在Info.plist中包含以下内容:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFiles</key>
<array>
<string>Document-molecules-320.png</string>
<string>Document-molecules-64.png</string>
</array>
<key>CFBundleTypeName</key>
<string>Molecules Structure File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.sunsetlakesoftware.molecules.pdb</string>
<string>org.gnu.gnu-zip-archive</string>
</array>
</dict>
</array>
Run Code Online (Sandbox Code Playgroud)
上面示例中使用的UTI之一是系统定义的,但另一个是特定于应用程序的UTI.需要导出特定于应用程序的UTI,以便系统上的其他应用程序可以识别它.为此,您需要在Info.plist中添加一个部分,如下所示:
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.plain-text</string>
<string>public.text</string>
</array>
<key>UTTypeDescription</key>
<string>Molecules Structure File</string>
<key>UTTypeIdentifier</key>
<string>com.sunsetlakesoftware.molecules.pdb</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<string>pdb</string>
<key>public.mime-type</key>
<string>chemical/x-pdb</string>
</dict>
</dict>
</array>
Run Code Online (Sandbox Code Playgroud)
此特定示例com.sunsetlakesoftware.molecules.pdb
使用.pdb文件扩展名导出UTI,对应于MIME类型chemical/x-pdb
.
有了这个,您的应用程序将能够处理附加到电子邮件或系统上其他应用程序的文档.在Mail中,您可以点按并按住以显示可以打开特定附件的应用程序列表.
打开附件后,您的应用程序将启动,您需要在-application:didFinishLaunchingWithOptions:
应用程序委托方法中处理此文件的处理.看来,以这种方式从Mail加载的文件被复制到应用程序的Documents目录下,该子目录对应于它们到达的电子邮箱.