【问题标题】:UIDocumentInteractionController Calendar AccessUIDocumentInteractionController 日历访问
【发布时间】:2015-01-13 17:10:47
【问题描述】:

我有一个 ics(日历)文件,我用 UIDocumentInteractionController 打开,使用 presentOptionsMenuFromRect:。运行时,“打开方式”菜单看起来像 this

如您所见,没有“添加到日历”选项。这让我明白了:我对 .vcf(联系人卡片)文件使用了相同的代码,它 works as expected 带有可用的“在联系人中打开”选项。

我的Info.plist 中是否缺少某种访问日历的权限?为什么UIDocumentInteractionController 不能正确处理.ics 文件类型,但.vcf 工作得很好?这两种文件类型非常相似。从选项菜单中,如果我将 ics 文件邮寄给自己并从邮件应用程序中打开它,它会很好地读取它,并且我可以将事件添加到我的日历中,因此我知道数据是有效的。我到处寻找解决方案,但似乎没有人知道为什么日历访问不起作用。我遇到的一些问题仍未得到解答:

Unable to Add ics file to Calendar

How can I have UIDocumentInteractionController show Calendar as an option for opening a .ics file?

如果 Apple 是故意这样做的,我能想到的唯一原因是因为他们宁愿开发人员使用 EventKit 将事件添加到日历中。如果属实,该解决方案相当令人沮丧。对此问题的任何见解将不胜感激。

【问题讨论】:

  • 开始有点沮丧,因为现在存在解决此问题的方法。我将向 Apple 提交错误报告,看看他们是否有什么要说的。
  • 我也很感兴趣,所以如果您发现任何东西,请务必回帖 :)
  • 我最终使用 EventKit 来让它工作。我没有传入 ics 文件,而是解析原始数据并使用 EventKit 创建一个包含所有事件的日历。我的猜测是 Apple 更喜欢开发人员使用它(可能是安全性?)。这可能不是您想听到的答案,但它似乎是唯一的选择。无论如何,我经历了许多根本无法读取 ICS 文件的 Android 设备。我需要一个第三方导入器应用程序才能将其添加到我的设备日历中。因此,ICS 文件似乎不是任何一个组的高优先级。
  • 这正是我所做的。我用我的解决方案回答了你的问题,所以它可以帮助其他人。另外,我这周在 Android 上工作,所以如果我发现了什么,我会告诉你的。
  • @Alex 找到任何解决方案了吗?有什么方法可以在 UIDocumentInteractionController 上显示添加到日历选项。

标签: ios cocoa-touch nsdata icalendar uidocumentinteraction


【解决方案1】:

我最终通过 (https://github.com/KiranPanesar/MXLCalendarManager) 下载了 .ics 文件。然后我可以使用 EventKit 将下载的 .ics 文件解析为 EKEvent 并通过 EKEventEditViewController (https://developer.apple.com/library/prerelease/ios/samplecode/SimpleEKDemo/Listings/Classes_RootViewController_m.html) 打开它。有点绕,但似乎工作。以下是我设置实现此功能的 webview 控制器类的方法:

@interface WebViewController : UIViewController <UIWebViewDelegate, EKEventEditViewDelegate> {

// EKEventStore instance associated with the current Calendar application
@property (nonatomic, strong) EKEventStore *eventStore;

// Default calendar associated with the above event store
@property (nonatomic, strong) EKCalendar *defaultCalendar;

@end


@implementation WebViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    ...
    // Initialize the event store
    self.eventStore = [[EKEventStore alloc] init];
}


- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = [request URL];
    NSString *path = [url absoluteString];

    NSRange range = [path rangeOfString:@".ics" options:NSCaseInsensitiveSearch];
    if (range.length > 0) {
        [self checkCalendarAndAddEvent:url];
        return NO;
    }
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    return YES;
}

-(void)checkCalendarAndAddEvent:(NSURL*)url
{
     EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
     if(status == EKAuthorizationStatusAuthorized)
     {
         [self addEventToCalendar:url];
     } else
     {
         [self.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
         {
             if (granted)
             {
                  // Let's ensure that our code will be executed from the main queue
                  dispatch_async(dispatch_get_main_queue(), ^{
                     // The user has granted access to their Calendar; add to calendar
                     [self addEventToCalendar:url];
                  });
             }else
             {
                 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Privacy Warning" message:@"Permission was not granted for Calendar"
                                                            delegate:nil
                                                   cancelButtonTitle:@"OK"
                                                   otherButtonTitles:nil];
                 [alert show];
             }
         }];
    }
}

-(void) addEventToCalendar: (NSURL *)url
{
    MXLCalendarManager* calendarManager = [[MXLCalendarManager alloc] init];
    self.defaultCalendar = self.eventStore.defaultCalendarForNewEvents;
    [calendarManager scanICSFileAtRemoteURL:url withCompletionHandler:^(MXLCalendar *calendar, NSError *error) {

        MXLCalendarEvent *mxlEvent = calendar.events.firstObject;

        EKEventEditViewController *addController = [[EKEventEditViewController alloc] init];
        EKEvent * event = [EKEvent eventWithEventStore:self.eventStore];
        event.location = mxlEvent.eventLocation;
        event.startDate = mxlEvent.eventStartDate;
        event.endDate = mxlEvent.eventEndDate;
        event.title = mxlEvent.eventSummary;
        event.notes = mxlEvent.eventDescription;

        addController.event = event;
        // Set addController's event store to the current event store
        addController.eventStore = self.eventStore;
        addController.editViewDelegate = self;
        [self presentViewController:addController animated:YES completion:nil];
   }];
}
@end

我还必须稍微修改 MXLCalendarManager.m 的部分内容,以便为我的特定类型的 .ics 格式做好准备。例如,我的 .ics 文件的摘要部分如下所示:

DESCRIPTION;LANGUAGE=en-us:The following details your appointment:\n\n\n

MXLCalendarManager 只在哪里寻找:

DESCRIPTION: (Something). 

我修改了这样的代码来解释 ;ln。这也删除了所有人工换行符,但允许我在摘要描述中添加自己的:

    // Extract event description
    [eventScanner scanUpToString:@"DESCRIPTION" intoString:nil];
    [eventScanner scanUpToString:@":" intoString:nil];
    [eventScanner scanUpToString:@"\nSEQUENCE" intoString:&descriptionString];
    if(descriptionString.length > 1)
    {
        descriptionString = [descriptionString substringFromIndex:1];
        descriptionString = [[[descriptionString stringByReplacingOccurrencesOfString:@"\nSEQUENCE" withString:@""] stringByReplacingOccurrencesOfString:@"\r\n " withString:@""] stringByReplacingOccurrencesOfString:@"\\n" withString:@"\n"];
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    • 2012-10-29
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多