摘要:在制作一款打卡的時(shí)候有這么一個(gè)需求創(chuàng)建提醒到系統(tǒng)日歷中,也就是利用系統(tǒng)日歷來(lái)做事件的提醒,這么做的好處很明顯,無(wú)需處理提醒的細(xì)節(jié),也無(wú)需后臺(tái)。
在制作一款打卡App的時(shí)候有這么一個(gè)需求 -- 創(chuàng)建提醒到系統(tǒng)日歷中,也就是利用系統(tǒng)日歷來(lái)做事件的提醒,這么做的好處很明顯,App無(wú)需處理提醒的細(xì)節(jié),也無(wú)需后臺(tái)。這個(gè)App是基于Cordova開發(fā)的,并沒有訪問(wèn)系統(tǒng)日歷的接口,我們只能通過(guò)插件來(lái)完成,這是一個(gè)有趣的挑戰(zhàn)。
APP設(shè)計(jì)請(qǐng)看下圖,App允許創(chuàng)建事項(xiàng)時(shí),可以設(shè)置重復(fù),開始,結(jié)束和提醒時(shí)間四個(gè)選項(xiàng):
這四個(gè)選項(xiàng)對(duì)創(chuàng)建到日歷的事件都有影響:
重復(fù) 可以設(shè)置一周中的任意幾天,比如選擇周一到周五表示只要工作日。
開始 從哪天天開始
結(jié)束 到哪天結(jié)束
提醒時(shí)間 在每天的哪個(gè)時(shí)間發(fā)出提醒
這個(gè)四個(gè)組合起來(lái)就構(gòu)成一個(gè)日歷事件。
插件Cordova平臺(tái)實(shí)際上是一個(gè)基于web的平臺(tái),所以除了webview提供的能力,其他和設(shè)備交互的功能全部依賴于插件來(lái)完成,插件的安裝和使用通常并不困難,比如增加一個(gè)關(guān)于狀態(tài)欄控制的插件,可以在項(xiàng)目下這么做:
cordova plugin add cordova-plugin-statusbar
然后在js里調(diào)用插件提供的接口就可以了,更多的關(guān)于cordova平臺(tái)和插件的使用,我有一個(gè)視頻課程可以參考。很明顯,創(chuàng)建系統(tǒng)日歷事件也需要通過(guò)插件來(lái)做,搜索之后我們可以發(fā)現(xiàn),完成這個(gè)功能的插件并不多,其中使用比較多的是cordova-plugin-calendar,試著安裝
cordova plugin add cordova-plugin-calendar
這個(gè)插件可以支持android和iOS,我們現(xiàn)在android下測(cè)試,首先在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保存了用戶所創(chuàng)建的一個(gè)活動(dòng)事件的所有信息,其中有兩個(gè)函數(shù)就不展開了,看起來(lái)應(yīng)該可以了,實(shí)測(cè)的結(jié)果卻是,日歷事件創(chuàng)建起來(lái)了,沒有報(bào)錯(cuò),但是重復(fù)有問(wèn)題,并沒有能一直重復(fù)下去,在重復(fù)數(shù)次之后,事件就停了,類似下圖這樣,到15號(hào)事件就沒有了:
修改插件在這種情況下,調(diào)試js代碼已經(jīng)沒有什么幫助了,js代碼已經(jīng)完全按照插件的要求來(lái)傳遞了參數(shù),只能打開android studio,加載cordova項(xiàng)目下platforms/android下的這個(gè)工程,這個(gè)工程就是一個(gè)標(biāo)準(zhǔn)的android項(xiàng)目,打開之后可以定位到這個(gè)插件所提供的源碼文件,找到AbstractCalendarAccessor.java,其中的createEvent函數(shù)完成在android下創(chuàng)建一個(gè)日歷事件所做的事情,代碼如下:
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; }
這段代碼并不長(zhǎng),在Android Studio下設(shè)置斷點(diǎn),連接真機(jī)調(diào)試,發(fā)現(xiàn)整個(gè)過(guò)程沒有任何錯(cuò)誤,日歷事件已經(jīng)創(chuàng)建起來(lái),但就是重復(fù)次數(shù)不正確。好吧,找到android api參考,看看官方文檔中怎么說(shuō)的:
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.
仔細(xì)對(duì)照代碼和文檔,我們發(fā)現(xiàn)DURATION這個(gè)參數(shù)并沒有按照文檔來(lái)傳遞,好吧,我們修改一下關(guān)鍵代碼:
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"); } }
修改后的代碼再次測(cè)試,這次ok了,這個(gè)例子表明了cordova生態(tài)的一個(gè)現(xiàn)象,插件質(zhì)量參差不齊,有些插件可能需要我們的修改才能工作。
應(yīng)用修改為了使用修改后的插件,我們可以刪除原來(lái)的插件,使用fork并修改后的插件,很簡(jiǎn)單,方法如下:
cordova plugin remove cordova-plugin-calendar cordova plugin add https://github.com/i38/Calendar-PhoneGap-Plugin.git
所有其他代碼都不用修改,這是cordova很靈活的一個(gè)地方,這樣一切都o(jì)k了,最后附上完整App的鏈接,有興趣可以參考: 天天。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99841.html
摘要:本文源碼為版本。的代碼結(jié)構(gòu)也是一個(gè)很經(jīng)典的定義結(jié)構(gòu)構(gòu)造函數(shù)實(shí)例修改函數(shù)原型共享實(shí)例方法,它提供事件通道上事件的訂閱撤消訂閱調(diào)用。 前言 cordova(PhoneGap) 是一個(gè)優(yōu)秀的經(jīng)典的中間件框架,網(wǎng)上對(duì)其源代碼解讀的文章確實(shí)不多,本系列文章試著解讀一下,以便對(duì)cordova 框架的原理理解得更深入。本文源碼為cordova android版本6.1.2。 源碼結(jié)構(gòu) 我們使用IDE...
摘要:經(jīng)過(guò)網(wǎng)上查找很多資料,發(fā)現(xiàn)很多只有的項(xiàng)目整合,但是使用插件的文章很少,現(xiàn)在把從創(chuàng)建和創(chuàng)建到使用插件到項(xiàng)目打包到手機(jī)運(yùn)行過(guò)程記錄下來(lái)先上項(xiàng)目結(jié)構(gòu)目錄項(xiàng)目創(chuàng)建安裝環(huán)境這個(gè)這邊就不描述了,網(wǎng)上很多教程創(chuàng)建應(yīng)用創(chuàng)建項(xiàng)目為目錄命名空間項(xiàng)目名稱添加平臺(tái) 經(jīng)過(guò)網(wǎng)上查找很多資料,發(fā)現(xiàn)很多只有vue+cordova的項(xiàng)目整合,但是vue使用cordova插件的文章很少,現(xiàn)在把從創(chuàng)建cordova和創(chuàng)建v...
摘要:經(jīng)過(guò)網(wǎng)上查找很多資料,發(fā)現(xiàn)很多只有的項(xiàng)目整合,但是使用插件的文章很少,現(xiàn)在把從創(chuàng)建和創(chuàng)建到使用插件到項(xiàng)目打包到手機(jī)運(yùn)行過(guò)程記錄下來(lái)先上項(xiàng)目結(jié)構(gòu)目錄項(xiàng)目創(chuàng)建安裝環(huán)境這個(gè)這邊就不描述了,網(wǎng)上很多教程創(chuàng)建應(yīng)用創(chuàng)建項(xiàng)目為目錄命名空間項(xiàng)目名稱添加平臺(tái) 經(jīng)過(guò)網(wǎng)上查找很多資料,發(fā)現(xiàn)很多只有vue+cordova的項(xiàng)目整合,但是vue使用cordova插件的文章很少,現(xiàn)在把從創(chuàng)建cordova和創(chuàng)建v...
摘要:任何初始化任務(wù)應(yīng)該在文件中的事件的事件處理函數(shù)中。這個(gè)配置文件有幾個(gè)地方很關(guān)鍵,一開始沒有認(rèn)真看,將插件導(dǎo)進(jìn)工程跑的時(shí)候各種問(wèn)題,十分頭痛,不得不重新認(rèn)真看看文檔。 前言 來(lái)新公司的第一個(gè)任務(wù),研究hybrid App中間層實(shí)現(xiàn)原理,做中間層插件開發(fā)。這個(gè)任務(wù)挺有意思,也很有挑戰(zhàn)性,之前在DCloud雖然做過(guò)5+ App開發(fā),但是中間層的東西確實(shí)涉及不多。本系列文章屬于系列開篇cord...
閱讀 2864·2023-04-25 18:46
閱讀 726·2021-11-19 09:40
閱讀 2097·2021-09-28 09:36
閱讀 3430·2021-09-10 11:11
閱讀 3491·2019-08-30 15:55
閱讀 1828·2019-08-30 15:54
閱讀 2621·2019-08-29 16:16
閱讀 3562·2019-08-29 15:08