一切都有效,但是服务被Android系统终止。唯一真正有效的解决方案是本文中提到的指令: http://nine-faq.9folders.com/articles/37422-stop-your-huawei-smartphone-from-closing-apps-when-you-lock-the-screen 不幸的是,这个解决方案依赖于用户,所以无法接受。
代码使用Xamarin的C#创建,但如果有人知道如何在程序中实现这篇文章中的解决方案,我将感激他们提供有用的建议,即使使用其他语言(如Java、Kotlin)也可以。
清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.companyname.com.bgapptest">
<uses-sdk android:minSdkVersion="25" android:targetSdkVersion="28" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
<service
android:name="com.BGAppTest.BackgroundService"
android:enabled="true"
android:exported="false"/>
</application>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
</manifest>
从Activity启动服务
活动
using System;
using System.Linq;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Provider;
using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Support.V7.App;
using Android.Views;
using Android.Widget;
using AlertDialog = Android.Support.V7.App.AlertDialog;
namespace com.BGAppTest
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme.NoActionBar", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
public static string HOPE = "Nothing";
string[] perms = new string[] { "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_NETWORK_STATE", "android.permission.READ_PHONE_STATE","android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"};
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
Android.Support.V7.Widget.Toolbar toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
FloatingActionButton fab = FindViewById<FloatingActionButton>(Resource.Id.fab);
fab.Click += FabOnClick;
HOPE = DateTime.Now.ToString();
StartService();
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.menu_main, menu);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
int id = item.ItemId;
if (id == Resource.Id.action_settings)
{
return true;
}
return base.OnOptionsItemSelected(item);
}
private void FabOnClick(object sender, EventArgs eventArgs)
{
View view = (View)sender;
Intent service = new Intent(this, typeof(BackgroundService));
StopService(service);
}
protected void IGnoreBatteryActivity()
{
PowerManager m = GetSystemService(PowerService) as PowerManager;
Intent intent = new Intent();
if (m.IsIgnoringBatteryOptimizations(this.PackageName))
{
//intent.SetAction(Settings.ActionIgnoreBatteryOptimizationSettings);
}
else
{
intent.SetAction(Settings.ActionRequestIgnoreBatteryOptimizations);
intent.SetData(Android.Net.Uri.Parse("package:" + PackageName));
StartActivity(intent);
}
}
void StartService()
{
foreach (var p in perms)
{
if (CheckSelfPermission(p) == Permission.Denied)
{
RequestPermissions(perms, 2);
return;
}
}
IGnoreBatteryActivity();
Intent service = new Intent(this, typeof(BackgroundService));
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
StartForegroundService(service);
else
StartService(service);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.Any(x => x == Permission.Denied))
{
RunOnUiThread(() =>
{
new AlertDialog.Builder(this)
.SetMessage("Uprawnienia są wymagane.Chcesz nadać uprawnienia?")
.SetNegativeButton("Nie", delegate
{
this.FinishAffinity();
})
.SetPositiveButton("Tak", delegate
{
RequestPermissions(perms, requestCode);
})
.SetCancelable(false)
.Create()
.Show();
});
}
else
StartService();
}
}
}
服务
[Service(Name = "com.BGAppTest.BackgroundService")]
public class BackgroundService : Service
{
NetworkChangeReceiver networkReceiver;
PhoneCallsReceiver receiver;
const int Service_Running_Notification_ID = 937;
public bool isStarted = false;
PowerManager.WakeLock wakeLock;
public BackgroundService()
{
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (isStarted)
return StartCommandResult.Sticky;
isStarted = true;
PowerManager m = GetSystemService(Context.PowerService) as PowerManager;
wakeLock = m.NewWakeLock(WakeLockFlags.Partial, "MYWeakLock");
wakeLock.Acquire();
return StartCommandResult.Sticky;
}
public override void OnCreate()
{
base.OnCreate();
RegisterForegroundService();
RegisterWifiReceiver();
RegisterPhoneReceiver();
}
public void RegisterForegroundService()
{
Notification notification = BuildNotification("Title","Text");
StartForeground(Service_Running_Notification_ID, notification);
}
Notification BuildNotification(string title, string message)
{
NotificationCompat.Builder notificationBuilder = null;
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
String NOTIFICATION_CHANNEL_ID = "com.BGAppTest";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "MY_Foreground", NotificationImportance.High);
NotificationManager manager = (NotificationManager)GetSystemService(Context.NotificationService);
manager.CreateNotificationChannel(chan);
notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
}
else
notificationBuilder = new NotificationCompat.Builder(this);
return notificationBuilder
.SetSmallIcon(Resource.Drawable.ic_mtrl_chip_checked_black)
.SetContentTitle(Resources.GetString(Resource.String.app_name))
.SetContentIntent(BuildIntentToShowMainActivity())
.SetContentTitle(title)
.SetStyle(new NotificationCompat.BigTextStyle().BigText(message))
.SetOngoing(true)
.Build();
}
private PendingIntent BuildIntentToShowMainActivity()
{
var intent = this.PackageManager.GetLaunchIntentForPackage(this.PackageName);
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
return pendingIntent;
}
public void RegisterWifiReceiver()
{
var networkReceiver = new NetworkChangeReceiver();
IntentFilter intentFilters = new IntentFilter();
intentFilters.AddAction("android.net.conn.CONNECTIVITY_CHANGE");
RegisterReceiver(networkReceiver, intentFilters);
}
public void RegisterPhoneReceiver()
{
var receiver = new PhoneCallsReceiver();
IntentFilter intentFilters = new IntentFilter();
intentFilters.AddAction("android.intent.action.PHONE_STATE");
RegisterReceiver(receiver, intentFilters);
}
public override IBinder OnBind(Intent intent)
{
return null;
}
#region Session checker
//TODO:przenieść tą fukcionalność do odzielnego serwisu
System.Timers.Timer timers = new System.Timers.Timer();
private void StartTokenExpiredTimer()
{
}
#endregion
public override void OnDestroy()
{
base.OnDestroy();
try
{
UnregisterReceiver(receiver);
UnregisterReceiver(networkReceiver);
}
catch { }
}
}
接收器
using Android.Content;
using Android.Widget;
namespace com.BGAppTestReceivers
{
public class NetworkChangeReceiver: BroadcastReceiver
{
static NetworkChangeReceiver()
{
}
public NetworkChangeReceiver()
{
}
public override async void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "BGNetworkChange", ToastLength.Short).Show();
}
}
public class PhoneCallsReceiver : BroadcastReceiver
{
static PhoneCallsReceiver()
{
}
public PhoneCallsReceiver()
{
}
public override async void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "BGPhoneChange", ToastLength.Short).Show();
}
}
}
更新于2020年9月26日
我将我的示例应用程序的完整代码添加进来,使其尽可能简单。
更新于2020年9月30日
添加了android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
和ActionRequestIgnoreBatteryOptimizations