支持在我的应用程序中打开在...菜单项中的iOS邮件和Safari [英] Supporting Open In... menu item in my app for iOS Mail And Safari

查看:113
本文介绍了支持在我的应用程序中打开在...菜单项中的iOS邮件和Safari的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要让我的应用程式在Safari和邮件应用程式中使用 UIDocumentInteractionController 类中的「开启...」功能开启文件。

解决方案

我知道这对于我来说是一个非常令人沮丧的程序员,一个现在。文件I / O通过邮件和Safari应用程序涉及非常有趣的命名约定在应用程序本身。所以让我们用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

然后输入代理的.m文件,并粘贴以下内容代码:

  #importAppDelegate.h
#importOfflineReaderViewController.h

@implementation AppDelegate

@synthesize window;
@synthesize viewController;

- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)注释
{
//确保url指示一个文件(而不是例如http://)
if(url!= nil&& [url isFileURL]){
//告诉我们的OfflineReaderViewController来处理URL
[self.viewController handleDocumentOpenURL:url];
}
//指示我们已成功打开URL
return YES;
}





   - (void)dealloc 
{
[window release];
[viewController release];
[super dealloc]
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[ initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
//在应用程序启动后覆盖自定义点。
self.viewController = [[[OfflineReaderViewController alloc] initWithNibName:@ViewControllerbundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}

- (void)applicationWillResignActive:(UIApplication *)应用程序
{
/ *
当应用程序从活动移动到非活动状态。这可能发生在某些类型的临时中断(例如来电或SMS消息)或用户退出应用程序时,并且开始转换到后台状态。
使用此方法暂停正在进行的任务,禁用计时器,并降低OpenGL ES帧速率。游戏应该使用这种方法暂停游戏。
* /
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
/ *
使用此方法释放共享资源,保存用户数据,使计时器无效,并存储足够的应用程序状态信息以将应用程序恢复到其当前状态,以备日后终止。
如果应用程序支持后台执行,则调用此方法,而不是applicationWillTerminate:当用户退出时。
* /
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
/ *
从背景到非活动状态的转变;在这里你可以撤消许多在输入背景所做的更改。
* /
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
/ *
重新启动任何在应用程序处于非活动状态时暂停(或尚未启动)。如果应用程序先前在后台,则可选择刷新用户界面。
* /
}

- (void)applicationWillTerminate:(UIApplication *)application
{
/ *
当应用程序即将终止。
保存数据(如果适用)。
另请参见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 是发送链接的应用程序;和注释:(id)注释是我们不会涉及的额外功能。



布局我们的xib。输入xib(它应该标题为OfflineReaderViewController,但是它与xib无关,除非我们调用 initWithNibName:(我们不会)如下图所示:





非常重要的是你进入 UIWebView 的属性并选中Scales Pages To适合,因为这让我们放大和缩小网页上的捏。



输入 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

现在.m:

  #importOfflineReaderViewController.h

@implementation OfflineReaderViewController

UIDocumentInteractionController * documentController;

- (void)openDocumentIn {
NSString * filePath =
[[NSBundle mainBundle]
pathForResource:@MinoreofType:@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 {

}
b $ b - (void)documentInteractionController:(UIDocumentInteractionController *)controller
didEndSendingToApplication:(NSString *)application {

}

- (void)documentInteractionControllerDidDismissOpenInMenu:
(UIDocumentInteractionController *)控制器{

}
- (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 {
// ---获取文档文件夹的路径---
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 {
// ---获取Documents文件夹的路径---
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 \\\
];
for(NSString * s in fileList){
[filesStr appendFormat:@%@ \\\
,s];
}
[self displayAlert:filesStr];
[self loadFileFromDocumentsFolder:@0470918020.pdf];
}

- (IBAction)btnDisplayFiles {
[self listFilesFromDocumentsFolder];
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//释放所有未使用的缓存数据,图像等。
}

#pragma mark - 查看生命周期

- (void)viewDidLoad {
[super viewDidLoad];
[self openDocumentIn];
}

- (void)viewDidUnload
{
[super viewDidUnload];
//释放主视图的任何保留的子视图。
//例如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
{
//返回YES支持的方向
return(interfaceOrientation!= UIInterfaceOrientationPortraitUpsideDown) ;
}

@end

看看而不是只是复制我告诉你的一切(只是开玩笑)会知道这行: [[NSBundle mainBundle] pathForResource:@MinoreofType:@pdf]; 会给我们一个SIGABRT,因为,好吧,该文件不存在!所以,拖动任何通用的PDF,你拉从哪里(我推荐,但列出



现在,让我们运行'er!没有错误,假设你复制逐字,得到那些darned xib连接正确。现在,当您第一次启动应用程序时,您应该会看到在iBooks中打开文档的选项。取消选择它,真正的代码是打开其他文件!启动Safari并搜索Safari可以QuickLook或打开的任何PDF。然后在打开...菜单中,我们的应用程序显示了!点击它。你会得到小小的切换动画和一个警报将出现的文件的位置。当您关闭它时, UIWebView 将加载PDF。邮件应用程序具有与附件类似的功能。您也可以将这些PDF文件调用到您的应用程序。



就这样,这一切都做完了。享受和快乐的编码!


I need to have my app open documents from the Safari and Mail apps with that "Open In..." thing in the UIDocumentInteractionController class. How do I accomplish this?

解决方案

I know this was extremely frustrating for me as a beginning programmer, or even as a moderately skilled one now. File I/O through the Mail and Safari apps involves very... interestingly named conventions within the app itself. So let's get our hands dirty with an Xcode project for iPhone. Open Xcode (I will be using 4.2 for this Tutorial) and select the 'Single View' application template (or create an empty project, then add a single view with a .xib).

In that newly created application, rename the view controller (and associated xib) to OfflineReaderViewController, and then we'll get down to the code. (We will touch every file but the prefix header and main.m, so be aware that you'll need everything in front of you!)

Enter the AppDelegate header and paste the following code into it:

#import <UIKit/UIKit.h>

@class OfflineReaderViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) OfflineReaderViewController *viewController;

@end

Then enter the Delegate's .m file and paste the following code in verbatim:

#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 inactive 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

This:

-(BOOL)application:(UIApplication *)application 
               openURL:(NSURL *)url 
     sourceApplication:(NSString *)sourceApplication 
            annotation:(id)annotation 
    {    
        if (url != nil && [url isFileURL]) {
            [self.viewController handleDocumentOpenURL:url];
        }    
        return YES;
    }

Is the singular most important part of this tutorial. To break it down into its respective parts: -(BOOL)application:(UIApplication *)application is our sample app; openURL:(NSURL *)url is the URL that's sent to tell us what to open; sourceApplication:(NSString *)sourceApplication is the application that sent the link; and annotation:(id)annotation is an extra feature we won't get into.

Now, we must layout our xib. Enter the xib (which should be entitled 'OfflineReaderViewController', but it doesn't matter with a xib, unless we call initWithNibName: (which we won't)), and make it look like the picture below:

It is VERY important that you go into the UIWebView's Attributes and check "Scales Pages To Fit", as this let's us zoom in and out on web pages with pinches. Don't worry about the connections just yet, we will be creating those shortly.

Enter the OfflineReaderViewController header and paste in the following:

#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

Now the .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

Those of you who are actively watching and not just copying everything I tell you to (just kidding) will know that this line: [[NSBundle mainBundle] pathForResource:@"Minore" ofType:@"pdf"]; will give us a SIGABRT because, well, the file doesn't exist! So, drag in any generic PDF that you've pulled from wherever (I recommend here because who doesnt spend their free time reading massive amounts of documentation?), then copy its title and paste it in with the suffix (.pdf) removed; the ofType:@"pdf" part takes care of that for us. The line should look like this when you're done with it: [[NSBundle mainBundle] pathForResource:@"//file name//" ofType:@"pdf"];

Now go back into the xib and hook up those IBOutlets! All told, here's what your "File's owner" tab should look like:

It seems we're done...but wait! We didn't do anything to get an "Open In..." menu up and running! Well, it turns out that there is some mucking around in the .plist file necessary. Open up the app .plist (with a quick right click, then select Open As > Source Code) and paste in the following:

<?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>

[Side note: be careful mucking around in the source code of any plist, if you don't know what you're doing, you could get the dreaded 'This file has been corrupted' error from Xcode]

If one were to right click and select Open As > Property List, it would look like this:

There's another VERY important field in there called 'Application supports iTunes file sharing'. That must be set to "YES", or your app will not show up in iTunes as supporting file sharing.

The 'Document Types' field specifies the kinds of documents our example can open. Expand the arrow to find its role and UTI's. These are unique identifiers (Unique Type Identifiers; seems obvious what that acronym means now, doesn't it?) that every kind of file has. UTI's are what let the finder replace a generic document image with that nice localized image of the file type (don't believe me, rename an unimportant file extension to .ouhbasdvluhb and try to get a nice picture!) If I wanted to open my own custom format (lets say a .code file) then I would put something like com.CodaFi.code (reverse DNS notation for those with no clue) in the UTI field and Document Type Name would be 'CodaFi Document'. Handler Rank and Role should be straightforward as our handler rank is alternate (because we don't own the file) and our role is viewer (because we don't need anything more important. Our example is just a viewer and not an editor, so we'll leave it as such.

For future reference, UTI's have official system-declared naming schemes when they come from respected sources (Oracle, Microsoft, even Apple itself) which can be found in the Uniform Type Identifier Reference Guide, but are listed here for pedantry's sake.

Now, let's run 'er! The code should build with no errors, assuming you copied verbatim and got those darned xib hookups right. Now when you first launch your application, you should be presented with the option to open a document in iBooks. Deselect it, the real meat of the code is opening other documents! Launch Safari and search for any PDF that Safari can QuickLook or open. Then in the "Open in..." menu, our app shows up! Click it. You'll get the little switcheroo animation and an alert will come up with the location of the file. When you dismiss it, the UIWebView will have loaded the PDF. The Mail app has similar functionality with attachments. You can also call those PDFs up to your app.

That's it, it's all done. Enjoy and happy coding!

这篇关于支持在我的应用程序中打开在...菜单项中的iOS邮件和Safari的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆