0

我在从 Android N 开始的完整日历应用程序中遇到了一个奇怪的问题。我想知道我是否遗漏了什么,或者 Android 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 文档本身指出:“注意:本快速入门的目的是演示日历 API 在“

我已经在这方面工作了很长时间,但没有运气,使用 Google Play 客户端/服务库,尝试使用 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$1.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)
4

1 回答 1

0

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

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

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

新设备(使用 Android N、24 及更高版本)

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

于 2017-09-20T10:16:40.860 回答