Writing a background process on Apache Cordova

Two years ago, I became interested in mobile development for Android. Then I wrote unpretentious applications for parsing websites. The program code was written in Java. This is a very powerful language, but for writing simple lightweight applications that do not perform complex tasks, its object-oriented paradigm seemed to me not very useful. At that time, I was just starting to get acquainted with JavaScript. Initially, he attracted me with its simplicity, then I began to open up more and more opportunities in it. I was familiar with HTML5 and CSS3, for the sake of pleasure I created nice web pages.


I once found out about Apache Cordova - a framework that allows you to write mobile applications in HTML, CSS and JavaScript. I installed it right away.


Working with Cordova was really convenient. Nevertheless, judging by the number of feature articles on the Internet, the framework has not yet received widespread distribution. Although it is implemented, for example, the Wikipedia mobile application.


I believe that this is due to the insufficient functionality of the standard Cordova API. For working with Bluetooth, speech recognition and synthesis, a camera, etc. plugins required. Plugins can be written for one or more platforms in their native language.


For the needs of developers, thousands of plugins have been written that are in the public domain. I was pleased until the moment when I needed to create an application that, even after its closure, would send push notifications to the user every time after a certain period of time. On Android, such functionality is implemented through a background process. A plugin for creating something like this was not found. The plugin https://github.com/katzer/cordova-plugin-background-mode allowed you to start a background process, which stopped immediately when the application closed.


The forums claimed that creating a full-fledged background process on Cordova is impossible. But who is bothering to write your own plugin for these needs? After several days of work, I managed to write a plug-in and an application that, when launched, started sending notifications to the user every 5 seconds.


I want to talk about the way to create the application and the plugin in this post.


Install Cordova and launch the application


Before installing Cordova, be sure to install the Android SDK, Apache Ant, and Java.


Then add them to the system path:


On Windows: Type "Control Panel" into the search . Click on Advanced system settings . Click Environment Variables . In the Environment Variables select the environment variable the PATH . Click Change .
Add to end of line: ;C:\Development\adt-bundle\sdk\platform-tools;C:\Development\adt-bundle\sdk\tools;%JAVA_HOME%\bin;%ANT_HOME%\bin.


On Mac / Linux: open .bash_profile with the open command ~/.bash_profile. Add to system variables: export PATH=${PATH}:/Development/adt-bundle/sdk/platform-tools:/Development/adt-bundle/sdk/tools. Add paths for Java and Apache Ant, if none exist.


Be sure to indicate YOUR folder paths.


  1. From the site https://nodejs.org/en/download/ install Node.js, which allows you to translate JavaScript into native codes. The platform contains the npm package manager with which we will install Cordova.


  2. Open a command line or terminal and install Cordova
    npm install -g cordova


  3. Create a new project:

cordova create MyApp com.app.myapp MyApp


The first argument is the name of the folder in which the codes and application files will be stored. In this case, it is MyPluginApp.
The second argument is the name of the application package, its unique identifier.
The third argument is the name of the application that will be visible to the user. Usually the same as the folder name.


Do not forget to go to the application folder:


cd MyApp.


  1. Add the platforms on which the application will run. In my case, it is Android.

cordova platform add android


  1. Now launch your first% Cordova application

cordova run android


image


Writing a plugin


Now create a plugin that will pass the API to the Service class, which is responsible for the background process.


To write a plugin you need to create a regular folder. Create it in the same directory in which the application folder is located. Let's call it MyPlugin.


Any plugin contains the plugin.xml file. Create and add it to the plugin folder.


plugin.xml:


MyPlugin

This file contains information about the plugin, the files and libraries necessary for its functioning, as well as API features. As you can see, we are referring to one JavaScript and two Java files. So let's create them!


Add the www folder to the MyPlugin folder and create the MyPlugin.js file there. There we will describe the functions by which the application can interact with native code. That is, this file will serve as a kind of conductor between the JavaScript code of the application developer and the Java code of the plugin developer.


MyPlugin.js:


module.exports = {
    runBackground: function (successCallback, errorCallback) {
        cordova.exec(successCallback, errorCallback, "MyPlugin", "runBackground", [])
    }
}

The plugin has one single runBackground function that starts a background process sending notifications. As arguments, we pass it a function that is called if the command succeeds, and a function that reports an error. Next comes the class name of the native code to which the command will be sent and the name of the command itself. At the end there is an array of additional arguments, which we will not touch.


And finally, let's get down to working with native code. Create the src / android folder inside MyPlugin. There will be two Java classes: MyPlugin.java and MyService.java.


MyPlugin.java:


package com.example.plugin;
import org.apache.cordova.*;
import org.json.JSONArray;
import org.json.JSONException;
import android.widget.Toast;
import android.content.Context;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
public class MyPlugin extends CordovaPlugin {
    @Override
    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
        if (action.equals("runBackground")) {
            Context context = cordova.getActivity().getApplicationContext();
            Intent service = new Intent(context, MyService.class);
            context.startService(service);
            return true;
        } else {
            return false;
        }
    }
}

First, libraries are imported, including org.apache.cordova. *, Which allows you to interact with an application based on Cordova. Further we can meet Notification and NotificationManager - libraries for work with notifications. For the sake of the NotificationCompat library, we added a line to plugin.xml .


As soon as the application calls any function of the plugin, the method executeto which the string is passed is executed action. Different sets of actions are performed depending on the value of this line. In our plugin, it actioncan take only one value - runBackground. An object of our background process is created and called.


MyService.java:


package com.example.plugin;
import org.apache.cordova.*;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.content.Context;
import android.os.Handler;
import android.support.v4.app.NotificationCompat;
public class MyService extends Service {
    Handler mHandler = new Handler();
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mHandler.postDelayed(ToastRunnable, 5000);
        return START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    Runnable ToastRunnable = new Runnable() {
        public void run() {
            Context context = getApplicationContext();
            NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(context)
                .setSmallIcon(context.getApplicationInfo().icon)
                .setWhen(System.currentTimeMillis())
                .setContentTitle("It works!")
                .setTicker("Ticker")
                .setContentText("Text")
                .setNumber(1)
                .setAutoCancel(true);
            mNotificationManager.notify("App Name", 228, mBuilder.build());
            mHandler.postDelayed( ToastRunnable, 5000);
        }
    };
}

Этот класс — обычный Service. При запуске сервиса его метод onStartCommand возвращает START_STICKY. Благодаря этому даже после закрытия приложения процесс продолжает жить. Чтобы отправлять push-уведомления каждые 5 секунд, был создан поток Runnable, который вызывается хэндлером каждые 5 секунд. В теле потока происходит создание и отправка уведомления.


Добавляем плагин в приложение


Переходим в директорию приложения и добавляем наш плагин:


cordova plugin add ../MyPlugin.


Затем переходим в www/js/index.js и переписываем метод onDeviceReady следующим образом:


onDeviceReady: function() {
       app.receivedEvent('deviceready');
        var failure = function() {
            alert("Error calling MyPlugin");
        }
        MyPlugin.runBackground(function() {}, failure);
}

Через объект MyPlugin вызывается функция runBackground, которой передаем функцию, которая вызывается в случае ошибки и пустую функцию, если все прошло успешно. Эта функция была оставлена пустой, так как подтверждением успешного вызова у нас уже является отправка push-уведомления.


Заключение


Now we have a working application that sends push notifications every 5 seconds even after we close it.


image


image


I want to say that this is just a framework for creating useful applications. So, for example, you can remind a person that it's time to go over (not every 5 seconds, of course). In any case, this example shows that Cordova using plugins is not inferior in functionality to native applications.


You can download the source codes of the application and the plugin from the links: the application itself , the plugin .


Also popular now: