无法在 android N 中创建日历事件

Cannot create calendar event in android N

从 Android N 开始,我的完整日历应用程序遇到了一个奇怪的问题。我想知道我是否遗漏了什么,或者 [=34] 上的日历提供程序是否有问题=]N.

我正在使用日历内容提供商来管理日历。可以打开、编辑、删除和创建事件(从 Android 2.1 到 Marshmallow),但现在在 N 上无法创建新事件。尝试创建新事件时,该事件会短暂出现在事件列表中,然后消失。查看日志时,实际情况是这样的:

EventHandler::InsertEvent: Forbidden Entity[ id=2172 calendar_id=1 calendar_sync_id=-899202677 ] 

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden {
  "errors": [
  {
    "reason": "forbidden",
    "domain": "global",
    "message": "Forbidden"
  }],
  "message": "Forbidden",
  "code": 403
}

我能找到的关于这个错误的所有信息都与日历 API 调用有关,而不是与内容提供者有关(我的猜测是内部正在使用日历 API 并且某事失败了缺乏身份验证?)。 但是,我查看了提供程序文档 https://developer.android.com/guide/topics/providers/calendar-provider.html,但找不到任何身份验证要求。

我已从 AOSP 查找当前日历应用程序的更改,但找不到任何相关内容。它们作为同步适配器运行,使您可以在我未使用的一些特殊列上进行写入,因此我认为这不是问题的原因。

我也考虑过使用日历 API,但这并不理想,因为它不能离线工作,而且日历 API 文档本身指出:“注意:目的本快速入门的目的是演示如何在 Android 应用程序中使用日历 API。但是,生产日历应用程序将通过使用离线工作、接收推送的日历提供程序内容提供程序而受益匪浅,非常适合该平台。“

我已经在这方面工作了很长时间但没有运气,玩 Google 玩 client/services 库,尝试使用 Google 登录,清单权限和几个示例和好吧,毕竟我不知道现在还能去哪里,如果你们中的任何人能告诉我在 Android N 上写日历事件时可能出现的问题或预期的方式是什么,我将不胜感激。

非常感谢

这里是代码:

public Uri AddCalendarEntry(CalendarEventObject eventObject) {
    ContentValues event = new ContentValues();

    if (eventObject.getCalendar() != null) {
        event.put(CalendarContract.Events.CALENDAR_ID, Integer.parseInt(eventObject.getCalendar().getId()));
    } else { 
        Log.e (DEBUG_TAG,"calendar id not available ");
        return null;
    }

    event.put(CalendarContract.Events.TITLE, eventObject.getSubject());
    event.put(CalendarContract.Events.DESCRIPTION, eventObject.getDescription());
    event.put(CalendarContract.Events.EVENT_LOCATION, eventObject.getLocation());
    event.put(CalendarContract.Events.STATUS, CalendarContract.Events.STATUS_CONFIRMED);
    event.put(CalendarContract.Events.HAS_ALARM, 1);  // 0 for false, 1 for true

    // All day events must use timezone UTC, others can use default
    if (eventObject.isAllDay()) {
        event.put(CalendarContract.Events.ALL_DAY,  1);  // 1 for true
        event.put(CalendarContract.Events.EVENT_TIMEZONE, Time.TIMEZONE_UTC);
    } else {
        event.put(CalendarContract.Events.ALL_DAY, 0);  // 0 for false
        event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().toString());
    }

    // Recurrent events must use "duration", normal events should use "dtend"
    event.put(CalendarContract.Events.DTSTART, eventObject.getStartDateTime());
    String recurrence = eventObject.getRecurrence();
    if (recurrence != null && !TextUtils.isEmpty(recurrence)) {
        String duration = datesToDuration(eventObject.getStartDateTime(), eventObject.getEndDateTime());
        event.put(CalendarContract.Events.DURATION, duration);
        event.put(CalendarContract.Events.RRULE, recurrence);
    } else {
        event.put(CalendarContract.Events.DTEND, eventObject.getEndDateTime());
    }

    Uri eventsUri = CalendarContract.Events.CONTENT_URI;
    Uri insertedUri = null;
    try {
        insertedUri = mainActivity.getContentResolver().insert(eventsUri, event);
    } catch(Exception e) {
        Log.e(DEBUG_TAG, "Error creating event " + e);
    }
    return insertedUri;
}

这里是完整的轨迹:

at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.interceptResponse(AbstractGoogleClientRequest.java:321)
at 
com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at com.google.android.syncadapters.calendar.CalendarRequestExecutor.executeInternal(CalendarRequestExecutor.java:146)
at com.google.android.syncadapters.calendar.CalendarRequestExecutor.execute(CalendarRequestExecutor.java:120)
at com.google.android.syncadapters.calendar.EventHandler.sendEntityToServer(EventHandler.java:485)
at com.google.android.syncadapters.calendar.CalendarSyncAdapterApiary.sendEntityToServer(CalendarSyncAdapterApiary.java:4084)
at com.google.android.syncadapters.calendar.CalendarSyncAdapterApiary.processLocalChanges(CalendarSyncAdapterApiary.java:4031)
at com.google.android.syncadapters.calendar.CalendarSyncAdapterApiary.processLocalChangesForHandler(CalendarSyncAdapterApiary.java:3970)
at com.google.android.syncadapters.calendar.CalendarSyncAdapterApiary.performUpsync(CalendarSyncAdapterApiary.java:791)
at com.google.android.syncadapters.calendar.CalendarSyncAdapterApiary.performSync(CalendarSyncAdapterApiary.java:691)
at com.google.android.syncadapters.calendar.CalendarSyncAdapterApiary.onPerformLoggedSync(CalendarSyncAdapterApiary.java:504)
at com.android.emailcommon.syncadapter.LoggingThreadedSyncAdapter.onPerformSync(LoggingThreadedSyncAdapter.java:50)
at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:272)

我发布此信息,不是真正的解决方案,而是我的结论,以防我能帮助处于相同情况的人。

显然,Google 在某些情况下忘记授予日历权限。所以我的猜测是无意中删除了对日历的支持:

旧应用(目标低于 23,Android M)

新设备(使用 Android N、24 及以上)

根据文档,如果您的目标年龄低于 23 岁,则无需担心运行时权限,但使用日历 API 似乎有一些要求未得到妥善解决。 在我的应用程序(困难的)迁移到 Android Studio 并定位到更新的 APIs,23-24 之后,我的日历终于可以保存事件了。