Cordova建立体系日历事宜

在制造一款打卡App的时刻有这么一个需求 — 建立提示到体系日历中,也就是运用体系日向来做事宜的提示,这么做的优点很明显,App无需处置惩罚提示的细节,也无需背景。这个App是基于Cordova开辟的,并没有接见体系日历的接口,我们只能经由历程插件来完成,这是一个风趣的应战。

APP设想

请看下图,App许可建立事项时,能够设置反复,最先,完毕和提示时候四个选项:

《Cordova建立体系日历事宜》

这四个选项对建立到日历的事宜都有影响:

  • 反复 能够设置一周中的恣意几天,比方挑选周一到周五示意只需事情日。
  • 最先 从哪每天最先
  • 完毕 到哪天完毕
  • 提示时候 在每天的哪一个时候发出提示

这个四个组合起来就组成一个日历事宜。

插件

Cordova平台实际上是一个基于web的平台,所以除了webview供应的才,其他和装备交互的功用悉数依赖于插件来完成,插件的装置和运用一般并不难题,比方增添一个关于状态栏掌握的插件,能够在项面前目今这么做:

cordova plugin add cordova-plugin-statusbar

然后在js里挪用插件供应的接口就能够了,更多的关于cordova平台和插件的运用,我有一个视频课程能够参考。很明显,建立体系日历事宜也须要经由历程插件来做,搜刮以后我们能够发明,完成这个功用的插件并不多,个中运用比较多的是cordova-plugin-calendar,试着装置

cordova plugin add cordova-plugin-calendar

这个插件能够支撑android和iOS,我们如今android下测试,首先在js里写下下面的代码:

let calOptions = window.plugins.calendar.getCalendarOptions()
calOptions.firstReminderMinutes = 0
calOptions.secondReminderMinutes = null
calOptions.recurrenceEndDate = actionRemindEnd(action)
if (action.repeat.length === 7) {
  calOptions.recurrence = 'daily'
}
else {
  calOptions.recurrence = 'weekly'
  calOptions.recurrenceByDay = dateRepeat2Calendar(action.repeat)
}
window.plugins.calendar.createEventWithOptions(
  action.name, null, 'dayday', eventTime, new Date(eventTime.getTime() + 15 * 60000), calOptions,
  (result) => {
  }, (err) => {
  })

action保留了用户所建立的一个运动事宜的一切信息,个中有两个函数就不展开了,看起来应当能够了,实测的效果倒是,日历事宜建立起来了,没有报错,然则反复有题目,并没有能一向反复下去,在反复数次以后,事宜就停了,相似下图如许,到15号事宜就没有了:

《Cordova建立体系日历事宜》

修正插件

在这类情况下,调试js代码已没有什么协助了,js代码已完全根据插件的请求来通报了参数,只能翻开android studio,加载cordova项面前目今platforms/android下的这个工程,这个工程就是一个规范的android项目,翻开以后能够定位到这个插件所供应的源码文件,找到AbstractCalendarAccessor.java,个中的createEvent函数完成在android下建立一个日历事宜所做的事变,代码以下:

public String createEvent(Uri eventsUri, String title, long startTime, long endTime, String description,
                              String location, Long firstReminderMinutes, Long secondReminderMinutes,
                              String recurrence, int recurrenceInterval, String recurrenceWeekstart,
                              String recurrenceByDay, String recurrenceByMonthDay, Long recurrenceEndTime, Long recurrenceCount,
                              String allday,
                              Integer calendarId, String url) {
        ContentResolver cr = this.cordova.getActivity().getContentResolver();
        ContentValues values = new ContentValues();
        final boolean allDayEvent = "true".equals(allday) && isAllDayEvent(new Date(startTime), new Date(endTime));
        if (allDayEvent) {
            //all day events must be in UTC time zone per Android specification, getOffset accounts for daylight savings time
            values.put(Events.EVENT_TIMEZONE, "UTC");
            values.put(Events.DTSTART, startTime + TimeZone.getDefault().getOffset(startTime));
            values.put(Events.DTEND, endTime + TimeZone.getDefault().getOffset(endTime));
        } else {
            values.put(Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
            values.put(Events.DTSTART, startTime);
            values.put(Events.DTEND, endTime);
        }
        values.put(Events.ALL_DAY, allDayEvent ? 1 : 0);
        values.put(Events.TITLE, title);
        // there's no separate url field, so adding it to the notes
        if (url != null) {
            if (description == null) {
                description = url;
            } else {
                description += " " + url;
            }
        }
        values.put(Events.DESCRIPTION, description);
        values.put(Events.HAS_ALARM, firstReminderMinutes > -1 || secondReminderMinutes > -1 ? 1 : 0);
        values.put(Events.CALENDAR_ID, calendarId);
        values.put(Events.EVENT_LOCATION, location);

        if (recurrence != null) {
            String rrule = "FREQ=" + recurrence.toUpperCase() +
                    ((recurrenceInterval > -1) ? ";INTERVAL=" + recurrenceInterval : "") +
                    ((recurrenceWeekstart != null) ? ";WKST=" + recurrenceWeekstart : "") +
                    ((recurrenceByDay != null) ? ";BYDAY=" + recurrenceByDay : "") +
                    ((recurrenceByMonthDay != null) ? ";BYMONTHDAY=" + recurrenceByMonthDay : "") +
                    ((recurrenceEndTime > -1) ? ";UNTIL=" + nl.xservices.plugins.Calendar.formatICalDateTime(new Date(recurrenceEndTime)) : "") +
                    ((recurrenceCount > -1) ? ";COUNT=" + recurrenceCount : "");
            values.put(Events.RRULE, rrule);
        }

        String createdEventID = null;
        try {
            Uri uri = cr.insert(eventsUri, values);
            createdEventID = uri.getLastPathSegment();
            Log.d(LOG_TAG, "Created event with ID " + createdEventID);

            if (firstReminderMinutes > -1) {
                ContentValues reminderValues = new ContentValues();
                reminderValues.put("event_id", Long.parseLong(uri.getLastPathSegment()));
                reminderValues.put("minutes", firstReminderMinutes);
                reminderValues.put("method", 1);
                cr.insert(Uri.parse(CONTENT_PROVIDER + CONTENT_PROVIDER_PATH_REMINDERS), reminderValues);
            }

            if (secondReminderMinutes > -1) {
                ContentValues reminderValues = new ContentValues();
                reminderValues.put("event_id", Long.parseLong(uri.getLastPathSegment()));
                reminderValues.put("minutes", secondReminderMinutes);
                reminderValues.put("method", 1);
                cr.insert(Uri.parse(CONTENT_PROVIDER + CONTENT_PROVIDER_PATH_REMINDERS), reminderValues);
            }
        } catch (Exception e) {
            Log.e(LOG_TAG, "Creating reminders failed, ignoring since the event was created.", e);
        }
        return createdEventID;
    }

这段代码并不长,在Android Studio下设置断点,衔接真机调试,发明全部历程没有任何毛病,日历事宜已建立起来,但就是反复次数不正确。好吧,找到android api参考,看看官方文档中怎样说的:

Here are the rules for inserting a new event:

  • You must include CALENDAR_ID and DTSTART.
  • You must include an EVENT_TIMEZONE. To get a list of the system’s installed time zone IDs, use getAvailableIDs(). Note that this rule does not apply if you’re inserting an event through the INSERT Intent, described in Using an intent to insert an event—in that scenario, a default time zone is supplied.
  • For non-recurring events, you must include DTEND.
  • For recurring events, you must include a DURATION in addition to RRULE or RDATE. Note that this rule does not apply if you’re inserting an event through the INSERT Intent, described in Using an intent to insert an event—in that scenario, you can use an RRULE in conjunction with DTSTART and DTEND, and the Calendar application converts it to a duration automatically.

细致对比代码和文档,我们发明DURATION这个参数并没有根据文档来通报,好吧,我们修正一下症结代码:

if (allDayEvent) {
  //all day events must be in UTC time zone per Android specification, getOffset accounts for daylight savings time
  values.put(Events.EVENT_TIMEZONE, "UTC");
  values.put(Events.DTSTART, startTime + TimeZone.getDefault().getOffset(startTime));
  if (recurrence == null) {
    values.put(Events.DTEND, endTime + TimeZone.getDefault().getOffset(endTime));
  } else {
    values.put(Events.DURATION, "P" + ((endTime - startTime) / (24 * 60 * 60000)) + "D");
  }
} else {
  values.put(Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
  values.put(Events.DTSTART, startTime);
  if (recurrence == null) {
    values.put(Events.DTEND, endTime);
  } else {
    values.put(Events.DURATION, "P" + ((endTime - startTime) / 60000) + "M");
  }
}

修正后的代码再次测试,此次ok了,这个例子表清楚明了cordova生态的一个征象,插件质量良莠不齐,有些插件能够须要我们的修正才事情。

运用修正

为了运用修正后的插件,我们能够删除本来的插件,运用fork并修正后的插件,很简单,要领以下:

cordova plugin remove cordova-plugin-calendar
cordova plugin add https://github.com/i38/Calendar-PhoneGap-Plugin.git

一切其他代码都不必修正,这是cordova很天真的一个处所,如许一切都ok了,末了附上完全App的链接,有兴致能够参考: 每天

    原文作者:十年
    原文地址: https://segmentfault.com/a/1190000017311978
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞