Initiating a Phonegap plugin after device restart
Asked Answered
B

2

10

I am in the process of developing a hybrid Phonegap app for Android. The app uses just the one plugin which I am developing as well. The plugin does three things

  • Watches for geo-location changes (both foreground and background)
  • Sets up a half-hourly alarm to perform certain periodic tasks
  • Listens for push messages. I use the pushy.me service and the code I use follows their documentation.

I had implemented the code to get the application to tune in to device reboots with some trepidation but it turned out to be easy (thanks to information I found in other threads on SO)

package com.example.plugin;

import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaWebView;
import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.pm.PackageManager;
import android.app.Activity;

import android.content.Intent;

public class Rebooter extends BroadcastReceiver
{
 @Override
 public void onReceive(Context context, Intent intent) 
 {
  Intent i = new Intent(context, MyAppCordovaPlugin.class); 
  i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  context.startActivity(i);  
 }
}

I register the reboot receiver thus

<receiver android:enabled="true" android:name=".Rebooter" 
 android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
 <intent-filter>
  <action android:name="android.intent.action.BOOT_COMPLETED" />
  <category android:name="android.intent.category.DEFAULT" />
 </intent-filter>
</receiver>

MyAppCordovaPlugin is the entry point to my app/plugin - the one that extends the CordovaPlugin class. Here is what I do there

public class MyAppCordovaPlugin extends CordovaPlugin
{
 private Context context;

 public void initialize(CordovaInterface cordova, CordovaWebView webView) 
 {
  super.initialize(cordova, webView);
  this.context = cordova.getActivity().getApplicationContext();
  //setup pushy.me broadcast receiver
  //setup geolocation changes receiver
  //setup broadcast receiver for a half-hourly alarm
 } 

 @Override
 public void onResume(boolean multitasking) 
 {
  super.onResume(multitasking);
  //unregister background location change receiver, if present
  //switch geolocation to foreground mode. i.e. using
  //FusedLocationApi.requestLocationUpdates
 }

 @Override
 public void onPause(boolean multitasking) 
 {
  super.onPause(multitasking);
  //stop request for foreground location updates, if present
  //switch geolocation to background mode, i.e by
  //registering a broadcast receiver that listens for location change 
  //broadcasts
 } 

When I start up the app manually on my Android 4.4.2 test device everything works perfectly. i.e.

  • Geo location changes are detected:both in the foreground and in the background
  • push messages are received. Once again both in f/g and in b/g
  • The half hourly alarm works

When I examine the running app I find that it consists of one service PushySocketService and the main process, com.example.app which is marked as being in use. Memory usage is considerable.

When I restart the phone I still find the same service and "main process" running. However, the memory usage reported for the main process is significantly lower.

Most importantly - the app does not recieve push messages and does not respond to geo location changes. This only starts happening after I have launched the app by main activity.

I must be missing something here - so the rebooted app does not automatically start its main activity? If so there must be something wrong with my Rebooter.onReceive code?

For completeness I should mention

  • Only the Pushy.me and Rebooter broadcast receivers are declared statically in the plugin.xml file. The Geo location and alarm broadcast receivers are registered dynamically from within my plugin code.
  • I am building the app using Phonegap CLI v 6.4.2 and JDK 7

I am clearly doing something wrong here. I'd be most grateful to anyone who might be able to put me on the right track.

Broadcast answered 17/1, 2017 at 4:55 Comment(9)
Have you tried to use github.com/ToniKorin/cordova-plugin-autostart? It also states that "Installation to the SD card will prevent the automatic start of your app after the boot." @BroadcastHeyduck
instead of starting main activity in OnReceive try to use getInstance (implement singleton pattern) and call respective method of mainactivity.Pearlstein
@AkshayTilekar, could you elaborate? I thought that the BroadcastReceiver.OnReceive event was a logical place to restart the activity. You appear to be suggesting something else.Broadcast
what do you want actually?Pearlstein
I just want you to clarify your comment since it is difficult to understand what you are suggestingBroadcast
@Heyduck - thank you for this. I cannot use any third party plugins but I took a look at what they have done there. I might well be able to implement similar code in my own plugin.Broadcast
@Broadcast HI, did u tried it out? Were you able to achieve it?Bonnard
@Bonnard - I am going to try and replicate the technique used in that plugin later today. I will post back here in due courseBroadcast
@Broadcast Thanks for the update. Wish you crack it. CheersBonnard
B
3

If you dont want to use any third party plugin for this functionality, then you can borrow the logic from cordova auto start plugin.

You can have a look at BootCompletedReceiver class in the plugin. It invokes everytime when the device reboots successfully which in turn invokes AppStarter helper class to start the respective app. You can implement the same logic in your plugin too.

Hope it helps. Cheers.

Bonnard answered 1/2, 2017 at 11:52 Comment(6)
Tried this - even tried using the pluguin. It does nothing and has the unfortunate side effect of stopping my app from tuning in to push messages after reboot. Shorn of all the plugin code all it is doing is to create an intent with `packageName.mainActivity.class. This works but does not appear to initialize the plugins used by the app until I have brought the app to the foregroundBroadcast
DroidOS will check and get backBonnard
From what I understand the issue is that Cordova plugins are not initialized until the CordovaWebView has been created and that does not appear to happen when the app is restarted from the packageName.mainActivity.class intent via the boot reciever. Given that I tune in to push, start alarms, watch geo-location etc in my own plugin initialization code the started app does nothing till I bring it to the foreground manuallyBroadcast
@Broadcast Hi,Looks like the solution for your issue is available in the following link - github.com/ToniKorin/cordova-plugin-autostart/issues/15 Check out jorantos's comment in the link... It should give you some clue. Hope it helps.Bonnard
Thanks. I will post a full solution to all of these issues here in a few days time for the benefit of anyone else running into this thread.Broadcast
@Broadcast Thanks for the update. Please do post once you are done so that everyone gets benefited. CheersBonnard
I
1

Cordova Plugin

Let's look at this piece of code:

Intent i = new Intent(context, MyAppCordovaPlugin.class); 
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
  • CordovaPlugin is not an activity, so you cannot start it as if it were.
  • Cordova Android application are is a single Activity application with a WebView, which loads the plugins only after the WebView is created. You don't really want to launch the application / start app UI in order to listen to GCM messages or geofencing events.

Pushy.me

Pushy.me documentation recommend to declare the BroadcastReceiver in the app's manifest. Seems also that Pushy also take care of boot event for you. Why not use their recommended approach?

Running stuff in the background after boot

As mentioned above, the code in initialize() callback will run only when the application's activity has been started. But you want to invoke some of the code there in the background after boot-complete event.

What I recommend is moving the 'start listening to background events' logic to an IntentService, which you can start both from your plugin's initialize(), and your boot complete receiver.

Investigator answered 4/2, 2017 at 19:1 Comment(2)
I am upvoting your answer because you have highlighted a couple of important issues. Clearly, passing the MyAppCordovaPlugin class is wrorng. Secondly, given that I want to restart not just push message listening but a few other things as well - alarms, geo location etc - I should not use the PushyMe boot receiver at all.Broadcast
I dont think there's a problem having two BroadcastReceivers for the same event in one application, so how to integrate pushy.me is for you to consider. I prefer to write few code as possible. Regardless, moving initialization of your alarms, geo, etc to IntentService should solve your problem.Investigator

© 2022 - 2024 — McMap. All rights reserved.