I have a Xamarin Forms app on Android which uses the Xamarin.Essentials library.
The app requires to run in the background to be fed location data (not particularly relevant to the question in hand, but included for context), and so must not be put to sleep by any battery optimisations that the OS might attempt.
I know that the user can manually opt out specific apps from Battery Optimizations, but as it is so crucial to the successful operation of the app, I would like the app to be able to :
and/or
I have added an entry into AndroidManifest.xml, but it doesn't seem to help, with the newly-installed app defaulting to being Battery Optimized.
The manifest contains the following entry:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
This library gives access to a number of permission-related info on the device, but Battery Optimizations doesn't seem to be one of them.
I don't know if it's relevant, but I am testing on a Samsung Galaxy S20 Ultra.
Can anyone offer any advice?
Following the advice from contributors and with reference to the docs at https://learn.microsoft.com/en-us/xamarin/essentials/permissions?tabs=android#extending-permissions ...
public interface IRequestIgnoreBatteryOptimizationPermission
{
Task<PermissionStatus> CheckStatusAsync();
Task<PermissionStatus> RequestAsync();
}
[assembly: Xamarin.Forms.Dependency(typeof(RequestIgnoreBatteryOptimizationPermission))]
namespace MyAndroidProject
{
public class RequestIgnoreBatteryOptimizationPermission : Permissions.BasePlatformPermission, IRequestIgnoreBatteryOptimizationPermission
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions => new List<(string androidPermission, bool isRuntime)>
{
(Android.Manifest.Permission.RequestIgnoreBatteryOptimizations, true)
}.ToArray();
}
}
// Ensure Required Permissions have been granted
var requestIgnoreBatteryOptimizationPermission = DependencyService.Get<IRequestIgnoreBatteryOptimizationPermission>();
var status = requestIgnoreBatteryOptimizationPermission.CheckStatusAsync().Result;
if (status != PermissionStatus.Granted)
{
status = requestIgnoreBatteryOptimizationPermission.RequestAsync().Result;
}
On calling CheckStatusAsync
, the result comes back as Granted
.
But the app settings still say otherwise...
I've tried it on both a physical device (Samsung Galaxy S20 Ultra) and on an Android Emulator (Pixel 2 API 28), with same result on both.
From this document, there are two ways to set Battery Optimization
An app can fire the ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
intent to take the user directly to the Battery Optimization
, where they can add the app.
An app holding the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
permission can trigger a system dialog to let the user add the app to the exemption list directly, without going to settings. The app fires a ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
Intent to trigger the dialog.
I use PowserManager.isIgnoringBatteryOptimizations to check Battery Optimization.
Firstly, add RequestIgnoreBatteryOptimizations
in AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Then creating Interface in Shared code.
public interface IBattery
{
void getbattery();
}
Implementing this interface in Android platform.
[assembly: Dependency(typeof(ImplementBattery))]
namespace FormsSample.Droid
{
public class ImplementBattery : IBattery
{
public void getbattery()
{
Intent intent = new Intent();
String packageName = MainActivity.mac.PackageName;
PowerManager pm = (PowerManager)MainActivity.mac.GetSystemService(Context.PowerService);
if (pm.IsIgnoringBatteryOptimizations(packageName))
intent.SetAction(Android.Provider.Settings.ActionIgnoreBatteryOptimizationSettings);
else
{
intent.SetAction(Android.Provider.Settings.ActionRequestIgnoreBatteryOptimizations);
intent.SetData(Android.Net.Uri.Parse("package:" + packageName));
}
MainActivity.mac.StartActivity(intent);
}
}
}
Creating static Mainactivity field in Mainactivity.cs.
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public static MainActivity mac;
protected override void OnCreate(Bundle savedInstanceState)
{
initFontScale();
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
mac = this;
Now, using DependencyService to fire.
private void Button_Clicked(object sender, EventArgs e)
{
DependencyService.Get<IBattery>().getbattery();
}