Webcal / .ics subscribe to feed from within Android App

1.8k Views Asked by At

For a recent application, I want to provide the ability to subscribe to a calendar feed while staying on the android device. Going to calendar.google.com and manually adding the http link (ics) isn't an option. I can't really find a lot of information on this topic. Since it is a completely new app it doesn't have to be ics. Just anything that works ok on iOS and Android.

On iOS, this is so easy as you can just programmatically make a call with the .ics link and the user will get a question to subscribe. Android ICS also introduced the Calendar API, but I haven't really found any clues on how you can subscribe to a public ics with this. I don't think it's possible as it just seems to be a way to actually make a new calendar or add/change events but not subscribe to a changing .ics feed.

Anyway, I just want to be sure that this is true and just not an option. (This is a defect of Android in 2014 in my opinion.)

There is another question on SO that is related, with an answer by CommonsWare. But making the user install another app together with my app just isn't an option and is much too cumbersome. Only a library of some kind that could make the subscription would really make this process acceptable for use within an app.

1

There are 1 best solutions below

0
On

So everything that can be subscribed to in Android should be done via BroadcastReceivers(listeners) and everything that is capable of exposing data to other applications is ContentProviders(basically public SQL databases). Keeping that in mind, we can try something like this:

// Adding permissions to the manifest
<uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />


// registering the BroadcasrReceiver in manifest(you can do it also in java/kotlin code):
 <receiver android:name="path.to.some.Receiver">
        <intent-filter>
            <action android:name="android.intent.action.PROVIDER_CHANGED" />
            <data android:scheme="content" />
            <data android:host="com.android.calendar" />
        </intent-filter>
    </receiver>


// Declaring receiver in the code
class Receiver:BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// Your Code that handles the Calendar ContentProvider query for example:
// Run query
val uri: Uri = CalendarContract.Calendars.CONTENT_URI
val selection: String = "((${CalendarContract.Calendars.ACCOUNT_NAME} = ?) AND (" +
        "${CalendarContract.Calendars.ACCOUNT_TYPE} = ?) AND (" +
        "${CalendarContract.Calendars.OWNER_ACCOUNT} = ?))"
val selectionArgs: Array<String> = arrayOf("[email protected]", "com.example", "[email protected]")
val cur: Cursor = contentResolver.query(uri, EVENT_PROJECTION, selection, selectionArgs, null)
}
}    

So there are some limitations, though:

  1. On some devices(especially with highly custom ROMs), this broadcast may be broken - it will trigger but not every time something is changed - so you may have to set up some interval polling of the data from the calendar if you want consistency.
  2. The intent in the BroadcastReceiver has no extras, so in order to know what changed, you would have to query the calendar ContentProvider every time. At least it was like that the last time I tried.

With this API, you can also create events, invite attendees, and do basically whatever with the calendar - more info about that in the official docs.

Regarding Webcal, the Google Calendar app has limited support for Webcal protocol. The changes to take effect may take up to 24 hours, and they are not guaranteed to happen. Also, regarding the Android - I don't think it is supported at all from within the apps - at least by Google itself. I've heard about the calendar apps for Android that do support it - never used those, so I don't know the specifics of implementation - I assume they work via their own backend and use Webcal protocol there with intermediate fetching and caching of the changes in the data - for hastiness - so most definitely no android native approaches are used there.

Hope it helps.