我需要通过UIDocumentInteractionController
类中的"打开方式..."实现从Safari和Mail应用程序打开文档。我该怎么做?
我需要通过UIDocumentInteractionController
类中的"打开方式..."实现从Safari和Mail应用程序打开文档。我该怎么做?
OfflineReaderViewController
,然后我们将进入代码。(我们将接触每个文件,但不包括前缀头文件和main.m,所以请确保你需要所有的文件!)#import <UIKit/UIKit.h>
@class OfflineReaderViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) OfflineReaderViewController *viewController;
@end
然后进入委托的 .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;
}
- (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
这个:
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
if (url != nil && [url isFileURL]) {
[self.viewController handleDocumentOpenURL:url];
}
return YES;
}
-(BOOL)application:(UIApplication *)application
是我们的示例应用程序;openURL:(NSURL *)url
是要打开的URL;sourceApplication:(NSString *)sourceApplication
是发送链接的应用程序;而 annotation:(id)annotation
则是我们不会涉及的额外功能。initWithNibName:
(但我们不会这样做)),并使其看起来像下面的图片:
非常重要的一点是进入 UIWebView
的属性并勾选 "Scales Pages To Fit",这样我们才能通过捏合手势放大和缩小网页。暂时不用担心连接,我们很快就会创建它们。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
#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
如果你正在积极观察而不是仅仅复制我告诉你的一切(开个玩笑),那么你就会知道这行代码:[[NSBundle mainBundle] pathForResource:@"Minore" ofType:@"pdf"];
会导致SIGABRT,因为嗯,文件不存在!所以,拖入任何你从任何地方得到的通用PDF文件(我推荐here,因为谁不喜欢花费大量时间阅读文档?),然后复制它的标题并将其粘贴在后缀(.pdf)被删除的情况下;ofType:@“pdf”
部分会为我们处理。完成后,该行应如下所示:[[NSBundle mainBundle] pathForResource:@“//file name//”ofType:@“pdf”];
现在回到xib并连接那些IBOutlets
!总之,这是您的“文件所有者”选项卡应该看起来像的:
看起来我们已经完成了...但等等!我们还没有做任何事情来启动一个“打开方式”菜单! 好吧,事实证明,在 .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>
[旁注:小心在任何plist的源代码中胡乱操作,如果你不知道自己在做什么,可能会从Xcode获得可怕的“该文件已损坏”错误]
如果右键单击并选择“打开方式>属性列表”,它将看起来像这样:
这里还有一个非常重要的字段,叫做“应用支持iTunes文件共享”。它必须设置为“YES”,否则您的应用程序将不会在iTunes中显示为支持文件共享。
“文档类型”字段指定了我们的示例可以打开的文档类型。展开箭头以找到其角色和UTI。这些是每种文件都有的唯一标识符(唯一类型标识符;现在很明显这个首字母缩写是什么意思了吧?)。UTI是让Finder替换通用文档图像为该文件类型的漂亮本地化图像的关键(不信,请将不重要的文件扩展名重命名为.ouhbasdvluhb并尝试获取漂亮图片!)如果我想要打开自己的自定义格式(比如.code文件),那么我将在UTI字段中放置类似于com.CodaFi.code
(对于没有头绪的人来说,这是反向DNS表示法),文档类型名称将是'CodaFi Document'。处理程序等级和角色应该很简单,因为我们的处理程序等级是备用(因为我们不拥有该文件),我们的角色是查看器(因为我们不需要更重要的东西。我们的示例只是一个查看器,而不是编辑器,所以我们将其保留为此)。
为了以后参考,UTI有官方的系统声明命名方案,当它们来自受尊敬的来源(Oracle、Microsoft,甚至是Apple本身)时,可以在Uniform Type Identifier Reference Guide中找到,但出于追求完美而列出here。
现在,让我们运行它!假设您逐字复制并正确地连接了那些可恶的xib,代码应该无错误地构建。现在,当您第一次启动应用程序时,您应该会看到在iBooks中打开文档的选项。取消选择它,代码的真正精华在于打开其他文档!启动Safari并搜索Safari可以快速查看或打开的任何PDF。然后在“打开方式...”菜单中,我们的应用程序显示出来!点击它。您将得到小的切换动画,并弹出一个带有文件位置的警报。当您关闭它时,UIWebView
将加载PDF。邮件应用程序具有类似的功能与附件。您还可以将这些PDF调用到您的应用程序中。
就这样,全部都完成了。享受愉快的编码吧!
<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>
以上示例中使用的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>