|

Create a service on android with phonegap application

This is a repost of an old post I wrote in July 2013 (pardon my English from back then, and the poor layout). It got a lot of traction and got people requesting for a repost. This is unfortunately not an updated post, but I’d be happy to answer questions if I can. Hopefully there are still some fair advice to learn from. Happy coding! —

Installing your application as a background service using phonegap is not easy and intuitive. This article will show you the easiest way to install your application as a service so that whatever the user will be doing with its phone, your app will always be running and execute the code you want even if your application is not in the foreground anymore. I’ll also give you more tips about keeping your phone awake (no sleep mode) and prevent the Android garbage collector from stopping your service.

Native or Javascript?

Before we start, let me tell you that the code executed as a service must be written in JAVA. You can still pass information (as a JSON object) from JavaScript to Java before the execution of your service. You’ll realize pretty quickly that it’s going to be really useful so I’ll show you how to do that in my article as well.

The Phonegap Plugin

A Phonegap plugin is basically an interface between your JavaScript code and your Java class. It allows you to call native code from your app and optionally get some data returned as JSONObjects.
You could either code your own plugin and your class in order to install your app as a service and then execute what you want with java OR you could download this excellent Background Service Plugin for Phonegap developed by Mark Taylor. Trust me, this plugin will do the trick and will give you enough options to personalize it so that it fit your needs and save you a lot of time. This article will tell you what you need to know in order to make it fit your needs!

Import the Plugin in your Project

After you’ve downloaded the right version (based on your phonegap version), unpack the archive, navigate to your phonegap project folder and follow carefully these instructions:

  • Copy “backgroundserviceplugin-2.x.x.jar” in your /libs directory
  • Copy “backgroundserviceplugin-2.x.x.js” and “myService-2.x.x.js” in your /assets/www directory (feel free to rename them)
  • Copy “MyService.java” in your /src/your.package.name
  • Add in your “index.html” the following lines to load the plugin in your app
<script type="text/javascript" src="backgroundService-2.2.0.js"></script>;
<script type="text/javascript" src="myService-2.2.0.js"></script>
  • Add in your “index.html” the following lines to load the plugin in your app
  • open your /res/xml/config.xml, go to the <plugins> node and add this line
<plugin name="BackgroundServicePlugin" value="com.red_folder.phonegap.plugin.backgroundservice.BackgroundServicePlugin"/>
  • Open your AndroidManifest.xml and add these lines to your <application> node:
<service android:name="com.yournamespace.yourappname.MyService">
   <intent-filter>     
      <action android:name="com.yournamespace.yourappname.MyService"/> 
   </intent-filter>     
</service>

TIPS: If you want your app to start when you’re rebooting your phonethen follow these extra steps:

  • Open your AndroidManifest.xml and make sure to add this permission if doesn’t exist:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  • Then add this in your <application> node, still in your AndroidManifest.xml:
<receiver android:name="com.red_folder.phonegap.plugin.backgroundservice.BootReceiver">   
  <intent-filter>    
       <action android:name="android.intent.action.BOOT_COMPLETED"></action>   
   </intent-filter> 
</receiver>

If you followed carefully these steps, your app is now ready to execute native code as a service with your Android application using Phonegap!

Install and Control The Service

To start/stop/install a service with a Phonegap application, there’s multiple steps. First you will need to write your Java functions and get some optional parameters. Then you will need to install and launch your service from your JavaScript code. Let me introduce you the main steps of the process.

The Java Native Code

Take a look at the MyService.java file.

  • Notice first the property “String mHelloTo”.This means that you can add properties to your class, and that you will be able to set their values through JavaScript. So feel free to add more properties or edit that one if it’s useful for you.
  • Then you can see the function “doWork()”. This code gets executed every time your Timer reaches 0. This function doesn’t get called if you just start the service, you’ll need to enable the timer to actually execute the code you would write there. This function can optionally return a JSONObject to your JavaScript when it gets executed.
  • The two next functions
    getConfig() and setConfig() will allow you to pass parameters and set your properties from JavasScript. In the actual state, getConfig() will return the values of your Java properties to your JavaScript as a JSONObject whereas the setConfig() will take a JSONObject as a parameter from your JavaScript and then set your java properties with it.
protected void setConfig(JSONObject config) {         
try {             
if (config.has('HelloTo'))                 
this.mHelloTo = config.getString('HelloTo');         } catch (JSONException e) {}
}

In this example, we test if the config JSONObject as a “HelloTo” attribute and then set its value to the java class string.

  • Finally, the functions onTimerEnabled() and onTimerDisabled() are simple to understand. The code gets executed once when the timer is enabled or disabled. This is useful if you want to call a function just once when you start or stop your service.

The Javascript code

Now that you understand the structure of the Java Class, let’s see how you can actually use this plugin inside your app. There’s two approaches based on if you would either execute a code every X seconds or just a one-time code setting a listener on a specific event in order to do something else.

Let’s assume you want your service to actually execute a code every 20 seconds. First, install your service, then set and start the timer. Pass the optional parameters to your service if you need to:

app.service = cordova.require('cordova/plugin/myService'); //instantiate the service
app.service.startService(function(r){handleSuccess(r)}, //start the service and set its callbacks
function(){handleError(e)});

Now that your service is started, use the callback to set the configuration and the timer.

function handleSuccess(data) {    
if (data.ServiceRunning){        
//config the service        
setConfig(); //will set the parameters of your java class (this call is OPTIONAL)         
enableTimer(); // will set and start the timer = execute doWork()    
}
}

Then we write our setConfig() and enableTimer() functions.

function enableTimer() {     
app.service.enableTimer(20000,function(r){handleSuccessTimer(r)},function(e){handleError(e)});
}

Set the timer to 20sec which means that the Java function
doWork() will get executed every 20 seconds.

function setConfig() {         
var config = {                        
'HelloTo' : 'foo'
};
  app.service.setConfiguration(config,function(r){handleSuccessConfig(r)},function(e){handleError(e)});}

The service will then log “Hello foo” instead of “Hello World”. Feel free add more attributes… Don’t forget to update your setConfig() function into your Java class and add your properties to your class.

What About Stopping The Service?

It’s actually pretty simple from your JavaScript application and can be done with two calls.

app.service.stopService(function(r){handleSuccess(r)},          function(e){handleError(e)}); 

Then in your HandleSuccess function we wrote earlier, notice the if testing if the service is running. If not, then it means you successfully stopped your service and you can safely disable the timer.

function handleSuccess(data) {
        if (data.ServiceRunning){ //service has been started                 setConfig(); //will set the parameters of your java class (this call is OPTIONAL)                 
enableTimer(); // will set and start the timer; execute doWork()         
}else{ //service has been stopped                 app.service.disableTimer();
        }
}

This will stop the timer and call the onTimerDisabled() java function, allowing you to stop a loop, release a wake lock (tell you about it later), or any other stuff that you might have started with your service.

Summary

Take the time to make sure you got everything here. First, code your java class, dowork() is your main function called every X seconds based on your timer. Add properties to your class if you need it. Then go back to your JavaScript and start your service (which means that it got installed). Set its configuration if needed, then enable the timer which will actually start calling the code from your Java class.

If what I said above made sense, then keep reading this article. If not, then you should read the “Install and Control the service“
section again.

More Tips About The Service

Handle errors with just one function

Since we have callbacks for each function controlling our service, you could set your handleError() this way to easily debug each problem from your service with just one function:

function handleError(data) {     
alert("Error: " + data.ErrorMessage); //basic error     alert(JSON.stringify(data)); //get all the info you need
}

Create an Android Service Without Using a Timer

If you don’t need a timer for your service, then you could just use the setConfig() function. It’s not really clean but by calling it from your JavaScript, you execute the code into your setConfig() Java function. Here is how it would work:

  • Add the code to execute as a service in the doWork() java function
  • Add a call to doWork() from the setConfig() function of your java class
  • Install/start your service with JavaScript
  • If the service is started, call the JS setConfig() function. This will execute your code inside the doWork() function.

Prevent the Android Garbage Collector to Kill The Service

You will notice, even with recent smartphones, that Android is killing apps running in the background in order to reallocate the memory used to other apps you are trying to launch. To prevent this automatic behavior, Google wants you to be honest with your users and warn them that your service is running in the background as a high priority task and can’t be killed by Android.
You would have to create a notification and link it to your activity (service). That way, your service will never stop and could come back to the foreground thanks to the notification bar. This will need to be done in Java, and be run every time you are starting your service.

If you are using a Timer and don’t want to re-create the notification every time, you could add this code into the onTimerEnabled() Java function.
I won’t tell you how to create a notification, you can Google that and find plenty of info about it.

Keep The Screen Awake While The Service is Running

If your service needs special features or functionality from your phone while it’s running, you would need to do some extra works. You could face this situation if you don’t want the phone to go to its sleep mode, or to keep the CPU alive, etc.
Here is a good example to illustrate what to do:

  • Open your AndroidManifest.xml and add this permission
<uses-permission android:name"android.permission.WAKE_LOCK" />
  • Then inside your Java Class, implement this code
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
wl.acquire();
   ..screen will stay on during this section..
wl.release();

If you want the list of the possibilities given by WakeLock, visit this page, it will be easy to understand.

The end

Hope this article will help some of you out there dying to install your Android application as a service using Phonegap. I’d be happy to discuss more about this subject and help people that could be confused. I would happily update my article if I see that some sections are not clear enough.
Good luck with your projects and app to everybody!

Share this story

Leave a Comment