Background service confusion - xamarin

I'm trying to find out how to keep an Android service running after the starting app is closed. I've tried looking at samples for background services (e.g this one, and some on the Xamarin site) but in every case the service stops running if the minimised app is 'swiped' off the screen. I don't want the service to accidently stop like this, it should run continually until a confirmed stop is requested. The service does not consume much in the way of resources, just gets a GPS location and posts it to a website every 2 minutes.
By way of background, I am a newbie to Xamarin/Android, but have in the past created several successful services in Windows with C#
(Later)
One sample I tried did leave an item in the Settings list of running apps, but didn't actually perform any service tasks once swiped off the screen. Additionally there was no icon in the status bar. After doing some reading it seems that my androidmanifest file is missing a 'service' attribute (although none of the samples I tried have this); what I have now tried is this
<service
android:name=".LocationService"
android:icon="#drawable/icon"
android:label="#string/service_name"
>
<intent-filter>
<action android:name="android.service.LocationService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
...but still no luck.

Have you had a look at the Xamarin sample here the source is here
They create a service like so:
[Service]
public class SimpleService : Service
{
System.Threading.Timer _timer;
public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
Log.Debug ("SimpleService", "SimpleService started");
DoStuff ();
return StartCommandResult.Sticky;
}
public override void OnDestroy ()
{
base.OnDestroy ();
_timer.Dispose ();
Log.Debug ("SimpleService", "SimpleService stopped");
}
public void DoStuff ()
{
_timer = new System.Threading.Timer ((o) => {
Log.Debug ("SimpleService", "hello from simple service");}
, null, 0, 4000);
}
public override Android.OS.IBinder OnBind (Android.Content.Intent intent)
{
throw new NotImplementedException ();
}
}
And start and stop it with this:
StartService (new Intent (this, typeof(SimpleService)));
StopService (new Intent (this, typeof(SimpleService)));
Also it sounds like you want a Sticky service Docs
When the system is under memory pressure, Android may stop any running services. The exceptions to this rule are services explicitly started in the foreground, which are discussed later in this article.
When a service is stopped by the system, Android will use the value returned from OnStartCommand to determine how or if the service should be restarted. This value is of type StartCommandResult, which can be any of the following:
Sticky – A sticky service will be restarted, and a null intent will be delivered to OnStartCommand at restart. Used when the service is continuously performing a long-running operation, such as updating a stock feed.
RedeliverIntent – The service is restarted, and the last intent that was delivered to OnStartCommand before the service was stopped by the system is redelivered. Used to continue a long-running command, such as the completion of a large file upload.
NotSticky – The service is not automatically restarted.
StickyCompatibility – Restart will behave like Sticky on API level 5 or greater, but will downgrade to pre-level 5 behavior on earlier versions.
Hope this helps.

Solved it now. The confusion was mainly due to many samples being out-of-date (using deprecated methods) and different suggestions for 'pure' Android projects and Xamarin ones. Certainly don't need to modify the androidmanifest file as I suggested above.
If anyone is trying to find something similar, my project is here.
Solving the initial issue has now raised some new questions, of course, but I will post separately about that if needed.

Related

Android Beacon Library - didEnterRegion not firing when app in background or stopped for pre-Android 8

First some background:
My setup uses a Service, which implements BeaconConsumer and binds to the BeaconManager. I have additional handling so when my app leaves the foreground, I move my Service to run in foreground, and when my app enters the foreground, I move my Service to run in background. That way, the persistent notification should display if and only if the app isn't displaying. In accordance, I am using the pattern here to tell BeaconManager I'm running this Service in the foreground, to allow for more frequent scanning. The link above isn't quite clear about this, but I believe this pattern should work without alterations needed on both pre-Android 8 as well as Android 8+. It shouldn't be strictly necessary on pre-Android 8, since the OS is more lenient. However, using this setup across all versions has the collateral benefit of ensuring that the OS does not kill the Service. If the app is in the foreground, the Service is background but has priority by virtue of the app, and if the app is not in the foreground, the Service is, and therefore has priority.
Now the problem: On pre-Android 8 devices, my Service is not seeing didEnterRegion called when the app is not in the foreground (but the Service is). It works fine on Android 8+.
some code snippets:
In my Service, set up the BeaconManager, set scan intervals
_beaconManager = BeaconManager.getInstanceForApplication(this);
_beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(IBEACON_PATTERN_1));
_beaconManager.setEnableScheduledScanJobs(false);
_beaconManager.setBackgroundBetweenScanPeriod(0);
_beaconManager.setBackgroundScanPeriod(1100);
Function in my Service I invoke to send the service to the foreground, and background:
private void sendServiceToForeground() {
this.startForeground(NOTIFICATION_ID, _notification);
if (_beaconManager != null) {
if (_beaconManager.isBound(this)) {
_beaconManager.unbind(this);
}
_beaconManager.enableForegroundServiceScanning(_notification, NOTIFICATION_ID);
_beaconManager.bind(this);
}
}
private void sendServiceToBackground() {
if (_beaconManager != null) {
if (_beaconManager.isBound(this)) {
_beaconManager.unbind(this);
}
_beaconManager.disableForegroundServiceScanning();
_beaconManager.bind(this);
}
this.stopForeground(true);
}
I can provide more code as requested. Not sure what all is relevant.
Calls to unbind() and bind() are asynchronous, so calling them one after another will be a problem unless you first wait for the unbind() operation to complete. This is tricky, because the library's BeaconManager does not provide a callback to tell you when unbind is complete (indeed, this is because the underlying Android service APIs also do not provide such a callback. You essentially don't know when the library's scanning service has stopped so you can safely restart it again in a different mode.)
It's a bit of a hack, but you might try adding a delay between unbind() and bind() to see if that makes a difference.

Error while leaving my application xamarin forms android in the background

My solution when I leave the application or leave it in the background gives an error 'The test application stopped', I can not find out where this queue comes from. Does anyone know where this trigger comes from the moment it leaves in the background
Is it something in this part of the code?
protected override void OnStart()
{
Debug.WriteLine("OnStart");
}
protected override void OnResume()
{
Debug.WriteLine("OnResume");
}
protected override void OnSleep()
{
Debug.WriteLine("OnSleep");
}
This type of errors came along with a specific part of your code, like #apineda mentioned maybe you are using an Android service that is updating some data on your application or it may be there to show a local notification who knows? but the thing I want to imply is that you need to take a look at your code and investigate further which is the part that is making the crash. Here are some tips:
1.- If you are using push notifications that may lead to something!
2.- Check you MainActivity.cs class since this is the one responsible of the Xamarin.Forms activity life cycle.
3.- If you have any timers on your shared code or even a background Task created with Task.Run or a Task.Factory.StartNew() check those too, deadlocks on Xamarin.Forms applications between the UI thread and background threads are a common thing on Xamarin.Forms.
I hope this helps!

Android Wear Wake Mobile

Edit
I erased everything for clarity. as i am going to simplify my request for information:
What is best way to handle receiving messages from a wear on a mobile when the mobile is asleep or if app is not in the foreground?
During both these circumstances even though i send messages to the mobile from the wear, the mobile does not receive or process them. i do not know which.
if have read the following:
1) partial wakelocks - no good i dont want to really keep CPU awake
2) handler
3) broadcastreceiver
4) service
i do not know exactly what i should do in order to process messages with my app when app is not in the foreground and/or asleep.
If the onMessageReceieved() SHOULD process during sleep and or when app is not in foreground letting me know that would also be beneficial as right now i think it should not based on what i am seeing in my app.
Also i am using livelisteners instead of a listener service. is this my problem? if i instead switch to a wearablelistenerservice class will that solve my issues and work correctly?
i do this
#Override
public void onConnected(Bundle connectionHint) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Connected to Google Api Service");
}
Wearable.MessageApi.addListener(mGoogleApiClient, this);
}
instead of if i do this:
public class DataLayerListenerService extends WearableListenerService{
and put all my codes in there and then do this:
<service android:name=".DataLayerListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data android:scheme="wear" android:host="*"
android:path="/start-activity" />
</intent-filter>
</service>
will that solve my not receiving messages problem when not in foreground and when phone is asleep? as this intent will act as a service that runs in the background?
You might want to check Keeping the Device Awake wherein it discussed different approaches that you can use such as keeping the CPU on.
As mentioned,
If you need to keep the CPU running in order to complete some work before the device goes to sleep, you can use a PowerManager system service feature called wake locks. Wake locks allow your application to control the power state of the host device.
You may find more tips and information in the use of wake locks from the given documentation.
Using a class that extends WearableListenerService and adding service to manifest worked for working while phone is off. Now i just need to implement and interact into the main feed to update data on the main screen

SignalR Hub method is not called

I have a SignalR hub and two clients (Windows and PCL for Android and iOS). Neither of the clients is able to call some methods on the server. This behaviour is quite odd, since the methods look very similar. Moreover, a colleague of mine is able to call methods I cannot call, and vice versa, does not invoke methods that I invoke with no problems.
Here is an example of a method, which works for me and does not work for my colleague:
public override async Task<bool> RefreshArray(User user, int waitMilis)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(waitMilis);
await Proxy.Invoke("RefreshArray", user);
return true;
}
catch (Exception ex)
{
OnExceptionOccured(ex);
return false;
}
}
And a method which does not work for me, but works for my colleague:
public override async Task<bool> RequestInformation(User user, Product product, int waitMilis)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(waitMilis);
await Proxy.Invoke("RequestInformation", user, product);
return true;
}
catch (Exception ex)
{
OnExceptionOccured(ex);
return false;
}
}
Yes, me and my colleague have exactly the same code. And no, there are no typos or different arguments. I have tried to get as much data from the client connection as possible, by setting _connection.TraceLevel = TraceLevels.All; However, I did not get any information on the invoked methods, just on the replies from the hub. When calling RefreshArray, I got exactly the data I requested. When calling RequestInformation, the debugger never even hit the breakpoint in the hub method and the _connection.Trace displayed only this: 11:22:45.6169660 - 7bc57897-489b-49a2-8459-3fcdb8fcf974 - SSE: OnMessage(Data: {})
Has anybody solved a similar issue? Is there a solution?
UPDATE 1
I just realized that I have encountered almost the same issue about a year ago (Possible SignalR bug in Xamarin Android). StackOverflow has also pointed me to a question with almost the same issue (SignalR on Xamarin.iOS - randomly not able to call Hub method), just related to iOS and Azure. However, I got the same proble even outside Xamarin, on Windows Phone 8.1 and and Windows 10 Universal App. Moreover, I am running the server just locally, so it is not an issue od Azure. Is it really possible, that a 2 years old bug has no solution?
UPDATE 2
I have just created a simple console application with SignalR.Client. In the console application every method worked just fine. Amazingly, also the Windows 10 Universal Application started to behave as expected - every hub method was invoked correctly. Windows Phone 8.1 also improved its behaviour (all hub methods invoked). However, every now and then the connection tried to reconnect periodically (for no apparent reason), leading to Connection started reconnecting before invocation result was received. error. The Android application still behaved as before.
So I tried to replicate my previous steps and created another console application, but this time with SignalR.Client.Portable library. To my dissapointment, there was no change in the Android application behaviour.
Next week we will start to test our application on iOS, so I really wonder what new oddities will we encounter.
I have managed to solve the problem (at least so it seems). As it turned out, there is some weird stuff going around, when an application receives an answer from SignalR hub. It seems as if the HubProxy was blocked for a certain period of time on Android, while it drops the connection and starts to reconnect periodically on Windows Phone, not waiting for an asnwer from the hub.
The implementation of RefreshArray on the hub was something like this:
public async Task RefreshArray(User user)
{
await Clients.Caller.SendArray(_globalArray);
await Clients.Caller.SendMoreInformation(_additionalInfo);
}
Because the method sent two methods as an answer, the client Proxy got stuck and each platform handled it in its own unexpected way. The reason why some methods were called on my computer and not on colleagues was, simply, because we had different position of breakpoints, which enabled the application to resolve at least some requests and responses.
The ultimate solution was to add some synchronization into the invokation of methods. Now my hub calls only await Clients.Caller.SendArray(_globalArray);. This is then handled on the client with a ArraySent(string[] array) event, which then subsequently invokes the SendMoreInformation() method on the hub.

How can I test the background scan and launch the application in background with iBeacon-Android?

I am using the pro library.
But I just found doc for free library
I cannot find any doc for pro version.
Also, I don't know how to implement the background mode even using the pro sample.
Here are the steps:
Build the pro sample project
start the iBeacon source(using iPad) and it can be detected
start the application and then press home button the make it in
background
Turn off the iBeacon source
Turn on the iBeacon source
However, more than 5 minutes, the application does not launch
So, can anyone verify the step I did?
How can I test the background mode more easily?
Also, for the BootstrapNotifier, is it just work only first time when the device reboot?
After that, even I put application in background, the application will not launch when it detect iBeacon?
Your testing method sounds fine. I think the issue is that the reference app for the pro library only auto launches the app on the first detection after boot. After that, it sends a notification instead, and tapping on that notification launches the app.
This is purely for demonstration purposes. You can change it to auto launch on every detection if you wish. Simply alter the haveDetectedIBeaconsSinceBoot logic in this code:
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever an iBeacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedIBeaconsSinceBoot) {
Log.d(TAG, "auto launching MainActivity");
// The very first time since boot that we detect an iBeacon, we launch the
// MainActivity
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Important: make sure to add android:launchMode="singleInstance" in the manifest
// to keep multiple copies of this activity from getting created if the user has
// already manually launched the app.
this.startActivity(intent);
haveDetectedIBeaconsSinceBoot = true;
} else {
// If we have already seen iBeacons and launched the MainActivity before, we simply
// send a notification to the user on subsequent detections.
Log.d(TAG, "Sending notification.");
sendNotification();
}
}
The javadoc link was missing from the main documentation page when you posted this question. That is fixed now.

Resources