Introduction
The Cordova PhoneGap Library is an awesome JavaSript library that allows developers to implement native functionality in hybrid applications. But, PhoneGap only provides a limited range of functionality. For example, it doesn't provide a way to add to your phones local Calendar Events. However, there is a simple solution using the cordova Java library. This article will explain how to use the cordova library to implement this feature (Note: This article is assuming you have your file structure set up correctly).
Using the Code
There are several parts to this. First, we will start of with the JavaScript. You must first make sure you have the latest PhoneGap library by visiting PhoneGap.com.
Include the cordova.js file and your code to execute the cordova callNativeFunction
in your index.html. The callNativeFunction
is a cordova defined function which is used to call your apps native function which in this case will create the event. This function has three parameters: the first is a result handler that prints the result of the call, the second parameter is the error handling function which will execute if there is an error in the call, the last parameter "returnSuccess
" is the message to the native function. In our case, returnSuccess
will contain all the information needed to create the event. For example, the date/time and name of the event. The calendarPlugin
object is a JavaScript object that you will create, but you need to create this object in a different JavaScript file. We will discuss this part later.
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="calendarPlugin.js"></script>
<script>
function callNativePlugin(returnSuccess){
calendarPlugin.callNativeFunction
(nativePluginResultHandler, nativePluginErrorHandler, returnSuccess);
}
function nativePluginResultHandler(result){
console.log("SUCCESS:\r\n" + result);
}
function nativePluginErrorHandler(error){
alert("Error: \r\n" + error);
}
</script>
Now in your Sencha view, add a button with a tap listener.
{
xtype:'button',
width:100,
height:44,
ui:'red',
listeners:{
tap:function(){
callNativePlugin('success,' + eventTitleData + ','
+ eventEndDateData +
',' + eventStartDateData + ',' +
eventLocationData + ',' +eventDescriptionData);
}
}
}
Now that we have all the HTML and JavaScript set up, it is time to make the calendarPlugin
object. Create a new JavaScript file named calendarPlugin.js and add the following code snippet. Let me explain this code a little. Here, we are defining an object with the property callNativeFunction
. The callNativeFunction
is a JavaScript function which executes the cordova.exe function. There are only two parameters you need to worry about. One is the name of the Android class you are calling. In this case, it's the "com.myPlugins.CalendarPlugin
class that we will define later". Next it's the action "addToCalendar
" which we will define in our CalendarPlugin
class.
var calendarPlugin = {
callNativeFunction: function(success, fail, resultType){
return cordova.exec(success, fail,
"com.myPlugins.CalendarPlugin",
"addToCalendar",[resultType]);
}
};
Now that we have completed all the steps for the JavaScript side, I will start discussing what is needed in the Android side. Under the www folder, add your calendarPlugin.js file. Now, we need to create our Android class to handle the call from cordova and execute the code to add calendar events. Before we create our Java file, we need to add the following line inside the Plugins tag to our config.xml file under the res/xml folder.
<plugin name="com.myPlugins.CalendarPlugin"
value="com.myPlugins.CalendarPlugin"/>
Create a package called "com.MyPlugins
" and a class called "CalendarPlugin
". This class will extend the CordovaPlugin
class which will allow us to implement our cordova plugin. Your Plugin
class must override one of the execute methods defined by cordova. In our case, we are calling the execute
method with an action to perform, data in the form of JSON and a callback method. Specify an intent with the action "ACTION_EDIT
" which will provide editable access to a given data. Then call intent.setType()
, this is used to specify a type and not data for the intent. In this case, we are specifying type uri of "vnd.android.cursor.item/event
". A cursor is an object that provides random read access to rows and columns in databases. In this case, it's the Event
database. Lastly, make sure to provide information to your event
by calling intent.putExtra(Events.TITLE, "YouTitle"
), etc. You can find out more about which kind of fields the CalendarContract.Events object has by visiting the Android development documentation.
package com.myPlugins;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import android.content.Intent;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Events;
import android.util.Log;
public class CalendarPlugin extends CordovaPlugin {
public static final String ACTION_STRING = "addToCalendar";
public static final String PARAMETER = "success";
@Override
public boolean execute(String action, JSONArray data,
CallbackContext callbackContext) throws JSONException {
if (ACTION_STRING.equals(action)){
Map<string,integer> months = new HashMap<string,integer>();
months.put("Jan", 0);
months.put("Feb", 1);
months.put("Mar",2);
months.put("Apr", 3);
months.put("May", 4);
months.put("Jun", 5);
months.put("Jul", 6);
months.put("Aug", 7);
months.put("Sep", 8);
months.put("Oct", 9);
months.put("Nov", 10);
months.put("Dec", 11);
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setType("vnd.android.cursor.item/event");
try{
String [] calendarData = data.getString(0).split(",");
String [] start = calendarData[4].split("\\s+");
int month = months.get(start[1]);
int day = Integer.parseInt(start[2]);
int year = Integer.parseInt(start[3]);
String [] time = start[4].split(":");
int hour = Integer.parseInt(time[0]);
int minutes = Integer.parseInt(time[1]);
GregorianCalendar date1 =
new GregorianCalendar(year, month, day, hour, minutes);
Log.d("beginTime", "time" +date1.getTime());
String [] start2 = calendarData[3].split("\\s+");
Log.d("EndTime", start2[1]);
int month2 = months.get(start2[1]);
int day2 = Integer.parseInt(start2[2]);
int year2 = Integer.parseInt(start2[3]);
String [] time2 = start2[4].split(":");
int hour2 = Integer.parseInt(time2[0]);
int minutes2 = Integer.parseInt(time2[1]);
GregorianCalendar date2 =
new GregorianCalendar(year2, month2, day2, hour2, minutes2);
intent.putExtra(Events.TITLE, calendarData[1]);
intent.putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, true);
intent.putExtra
(CalendarContract.EXTRA_EVENT_BEGIN_TIME, date1.getTimeInMillis());
intent.putExtra
(CalendarContract.EXTRA_EVENT_END_TIME, date2.getTimeInMillis());
intent.putExtra(CalendarContract.EventsEntity.EVENT_LOCATION,
calendarData[5] + calendarData[6] + calendarData[7]);
intent.putExtra
(CalendarContract.EventsEntity.DESCRIPTION, calendarData[8]);
}
catch(Exception e){
Log.d("Error with Calendar Plugins:",e.getMessage());
return false;
}
this.cordova.startActivityForResult(this, intent, 0);
return true;
}
return false;
}
}
History
- 31st March, 2013: Initial version