Apps handle GeoFence needs to receive PROVIDERS_CHANGED broadcast since:
Registered GeoFences will be removed when both 2 location providers
(network and GPS) are turned off.
When one of 2 location providers is turned on, app needs to register
GeoFences to work. This should be performed w/o asking user to run
my app again.
So my app has been registering its broadcast receiver in manifest. But it does not work any more in Android Oreo since PROVIDERS_CHANGED is not one we can make it work as before.
I can register broadcast receiver for that in app's activity or in service but it will quit (end its life cycle) sooner or later, then I need to unregister it. My app starts working by some events like GeoFence transition, but receiving PROVIDERS_CHANGED is critical to make it work.
I verified PROVIDERS_CHANGED can't be received by receiver registered in manifest in Android Oreo. Is there any solution for it?
#Tomcat and #Virat18 - I've come across a solution to the fact that you can no longer register a Broadcast Receiver in your Manifest to receive the PROVIDERS_CHANGED action Intent-filter in Android-OREO..
The solution? Simply register your BroadcastReceiver dynamically (from within your code), instead of from the Manifest.. Also, instead of checking for the hard-coded regex android.location.PROVIDERS_CHANGED, you should use LocationManager.PROVIDERS_CHANGED_ACTION (and of course import the LocationManager).
Here is an example of the Code I used to get this to work! (ex: from a Button Click):
public void buttonClick(View view) {
IntentFilter filter = new IntentFilter();
filter.addAction("android.location.PROVIDERS_CHANGED");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().matches(LocationManager.PROVIDERS_CHANGED_ACTION)) {
Log.i(TAG, "Action MATCHES LocationManager.PROVIDERS_CHANGED_ACTION!");
}
}
};
this.getApplicationContext().registerReceiver(receiver, filter);
Log.i(TAG, "RECEIVER HAS BEEN REGISTERED");
}
Also, don't forget to unregister the receiver in your code appropriately.
If you find this to be a good solution, please accept it as the Answer.
Happy Coding!
PS. This will continue to receive the broadcast from the background, even once the User leaves your Activity (presses the back-button, home-button, etc).. However, if the user closes your App from the Multitask button, it will no longer receive, so take note of that.
I try to connect to BLE peripheral. First, I watch for advertisements:
watcher = new BluetoothLEAdvertisementWatcher { ScanningMode = BluetoothLEScanningMode.Active };
watcher.Received += WatcherOnReceived;
watcher.Start();
and in the WatcherOnReceived callback I try to create BluetoothLEDevice
public async void WatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs btAdv)
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
}
However, I always get bleDevice == null in WatcherOnReceived callback. Why and how to fix it? What is the proper way of creating BLE device in UWP application? I then need to connect to that device, discover its GATT services and characteristics, enable notifications on some of them and read/write some of them.
The answer to this question is simple - do not use BLE on Windows 10. The API doesn't work or behaves randomly and is totally undocumented. I like everyone talking about IoT being next industrial revolution and Microsoft not having working BLE API after 6 year BLE exists.
See example 8 and 9 in https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing if you want to be able to connect to previously non-paired BLE devices, i.e. use a DeviceWatcher with a Bluetooth LE selector.
Otherwise you need to first pair it in the system's bluetooth pairing settings before you will be able to retrieve a BluetoothLEDevice from FromBluetoothAddressAsync.
You can check device information in WatcherOnReceived() to ensure that the device is what you want to connect with. Do it like this:
public async void WatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs btAdv)
{
if (btAdv.Advertisement.LocalName == "SensorTag")
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
}
}
Use your own BLE device name instead of "SensorTag".
Note: You need pair your BLE device beforehand(either programatically like DeviceEnumerationAndPairing sample or PC's setting app as shown in the following image.).
How to terminate a Xamarin application from any of the activities?
I have tried both System.Environment.Exit(0) and System.Environment.Exit(1) as well as Finish() and killing all the activities.
It still opens one blank page with default activity name and a black screen.
Is there any specific solution for this?
If you are using Xamarin.Forms create a Dependency Service.
Interface
public interface ICloseApplication
{
void closeApplication();
}
Android : Using FinishAffinity() won't restart your activity. It will simply close the application.
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
var activity = (Activity)Forms.Context;
activity.FinishAffinity();
}
}
IOS : As already suggested above.
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
Thread.CurrentThread.Abort();
}
}
UWP
public class CloseApplication : ICloseApplication
{
public void closeApplication()
{
Application.Current.Exit();
}
}
Usage in Xamarin Forms
var closer = DependencyService.Get<ICloseApplication>();
closer?.closeApplication();
A simple way to make it work cross platform is by this command:
System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
Got it from this link.
EDIT: After using it for a while, I discovered that .CloseMainWindow() don't kill the application, only Closes it (well, thats obvious). If you want to terminate the app (kill), you shoud use the following:
System.Diagnostics.Process.GetCurrentProcess().Kill();
For Android, you can do
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
iOS explicitly does not provide any API for existing an App. Only the OS can close an App.
For iOS, you can use this code:
Thread.CurrentThread.Abort();
For Android, as #Jason mentioned here:
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
System.Environment.Exit(0);
Works for me.
In your activity, use this code
this.FinishAffinity();
I tried this code
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
var result = await DisplayAlert("", "Would you like to exit from application?", "Yes", "No");
if (result)
{
if (Device.OS == TargetPlatform.Android)
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
else if (Device.OS == TargetPlatform.iOS)
{
Thread.CurrentThread.Abort();
}
}
});
return true;
}
In this, iOS and Android application close when a user chooses to terminate the application. Maybe it helps you.
A simple all-in-one combination of the previous answers, instead of the interface/dependency:
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
var result = await this.DisplayAlert("Alert!", "want to exit?", "Yes", "No");
if (result)
{
#if __ANDROID__
var activity = (Android.App.Activity)Forms.Context;
activity.FinishAffinity();
#endif
#if __IOS__
Thread.CurrentThread.Abort();
#endif
}
});
return true;
}
System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
System.Diagnostics.Process.GetCurrentProcess().Kill();
None of the methods above helped my Xamarin Android app to completely shut down. I tried to close it from Activity B, having Activity A also open under it.
A clever guy left a trick here.
First call FinishAffinity() in Activity B (closes both activities,
however, the app is still alive in the background)
Then call JavaSystem.Exit(0) to kill the background app (I think it can be replaced with Android.OS.Process.KillProcess(Android.OS.Process.MyPid()); or System.Diagnostics.Process.GetCurrentProcess().Kill();)
My method to close the app:
private void CloseBtn_Click(object sender, EventArgs e){
FinishAffinity();
JavaSystem.Exit(0);
}
As your original question mentions activities, your question is specifically for Android, you should probably update the question title with that in mind to avoid people looking for a cross-platform solution coming here.
For iOS and Android (say in Xamarin Forms) you can just throw an exception, which while being the "heavy handed" approach, will do the job:
throw new Exception();
As this isn't the best user experience and you may only want to use this for iOS because on Android, you are likely to get a system popup telling you the app crashed. However, unlike other iOS methods like calling exit(0) or calling private iOS methods like "terminateWithSuccess" via a selector, it shouldn't fail app store validation purely based on how you do it. They may still fail you because your app tries to terminate itself.
You may want to implement something different specifically for Android, in which case Jason's answer is sufficient, again if not a little on the nose i.e. using this approach may not allow your app to clean itself up:
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
Either way, you should really question why you need to provide this option. Unlike desktop applications where closing an application is needed because apps reside inside windows which by design allow multi-tasking and are not task orientated, mobile platforms are primarily designed for users to focus on one task at a time. Once the user is finished the task, they should decide to exit this task by clicking the home button, back button or change app (task) button. This really applies to all platforms.
None of these work with Android 8. They all left the app in the background.
I can prove this by pressing the close all button and the app is still there.
For my testing I used a brand new simple Android app and tried all of your answers.
Application.Quit();
I'm assuming you are using C#
Call
public void Quit ();
This will quit the application the correct way without it "crashing".
i want my application should work on specific devices\OS like "Lumia 650"\"windows phone 8", this is my project requirement.
Is it possible ? if yes where should I mention the details ?
It is not a problem to restrict Windows Phone 8. You just need to build it targeting Windows Phone OS 8.0.
For the device model you do something like this in the App.xaml.cs
private void Application_Launching(object sender, LaunchingEventArgs e)
{
var deviceName = DeviceExtendedProperties.GetValue("DeviceName").ToString();
if (!deviceName.Contains("Lumia_650")) // Please check your phone's actual value
Application.Current.Terminate();
}
If you want to show a friendly message before it exits you can move the code to the MainPage.xaml.cs then add the MessageBox.Show(message) part.
This is only possible in code as you can not prevent users from installing the app if the app is meant for that particular OS what that user has. However, once the app is launched you can get the name of the device and do actions accordingly.
You can try this:
var PhoneName = Microsoft.Phone.Info.DeviceStatus.DeviceName;
if(PhoneName == "Not Allowed Phone")
{
MessageBox.Show("You can not use this app");
}
else
{
}
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.