最近在開發一個車機上的日歷助手,其中一個需求就是要實現手機端日歷和車機端日歷數據的同步。然而這種需求似乎沒辦法實現,畢竟手機日歷是手機廠商自己帶的系統應用,根本不能和車機端實現數據同步的。
那么只能去其他公共的平臺尋求一些機會,最后瞄上了郵箱日歷的同步方式。大致的架構如下:
使用exchange服務中的日歷共享機制,可以把outlook日歷文件通過URL連接的方式發布出來,任何客戶端都可以去訪問這個日歷文件,做到手機端和車機端上數據的同步。這種方式存在的問題就是:
- 車機端只能是被動的接收,不能去做修改;
- 需要用戶自己去發布日歷,并且還要把URL字符串自己填到車機里面,很繁瑣。
但在目前有限的資源情況下,此方案是唯一可以落地的。
具體實現步驟:
1.日歷發布
首先需要有自己的outlook賬號,并且在web瀏覽器中訪問自己的outlook郵箱賬號,把自己的郵箱中的日歷發布出來,會生成一串連接,如下:
2.手機導入日歷
在手機系統日歷應用中,去訂閱這個ICS的的連接。進入日程導入:
然后選擇URL導入的方式:
本來按理說應該使用郵箱賬號的方式導入outlook日歷的,但是就在2024年,微軟終止了基礎方式的登錄驗證。也就是說,對沒有升級新的驗證方式的軟件(比如本手機xiaomi系統自帶的日歷APP),只是用賬號+密碼的方式不能登陸上微軟的exchange服務器了,同步不了數據。
手機應用導入了outlook日歷的URL,就會定期去同步這個地址的日歷數據,并導入到自己的系統中。這里便實現了手機日歷和outlook日歷的同步。
3.車機導入日歷
車機日歷也要獲取到此URL連接,才能導入對應的outlook日歷。只是在車機端,需要我們開發人員自己去實現拉取遠程日歷文件并解析的過程。
3.1 ICS文件簡介:
outlook日歷使用的是icalendar這種日歷數據交互標準(RFC 2445),icalendar標準定義了描述日歷信息的通用格式,它內部還分為了很多類型組件,比如Events(VEVENT)、To-do(VTODO)、Journal(VJOURNAL)、VTIMEZONE (time zones) 和 VALARM (alarms))等,比如下面文件內容:
每個事件都會以BEGIN開頭,以END結束。
3.2下載ICS文件
這并不難,在Android端使用Retroft框架,然后根據用戶填寫的發布的URL地址,可以輕松實現web服務器的文件下載,我這里是先把文件保存到本地,然后再從本地加載文件流并讀取數據。
3.3解析ICS文件
重點說一下解析ICS文件,使用ical4j這個庫文件去完成的。
首先需要在整個工程的setting.gradle中添加:
dependencyResolutionManagement {repositories {......maven { url "https://jitpack.io" }}
}
然后在module的gradle文件中添加引用:
dependencies {......api("org.mnode.ical4j:ical4j:3.2.11") {// exclude modules which are in conflict with system librariesexclude group: 'commons-logging'exclude group: 'org.json', module: 'json'// exclude groovy because we don't need itexclude group: 'org.codehaus.groovy', module: 'groovy'exclude group: 'org.codehaus.groovy', module: 'groovy-dateutil'}
}
這樣就可以把對應的jar包加載到項目中。
然后就是提取文件流里面的數據:
private fun readCalendarFromInputStream(inputStream: InputStream) {var build = CalendarBuilder()var calendar = build.build(inputStream)for(i in calendar.components) {when(i) {is VEvent ->convertVEvent(i)else -> Log.d(TAG, "$i")}}}
我們這里主要是提取VEvent類型的數據,即日歷事件,這個數據結構中包含了上述日志事件例子中的所有字段信息,比如開始時間、結束時間、標題、描述等信息。需要注意的是,從outlook上同步過來的icalendar,時間都是GMT時區,我們需要自己轉換成GMT+8時區。