发布Android 7后,如果应用程序因从最近的任务列表中滑出而被杀死,我的闹钟接收器没有收到广播接收器。
以下是我的AlarmReceiver中的一部分,它扩展了BroadCastReceiver。
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(Constants.TAG, "event received");
setContext(context);
/*
*** My logic here ***
*/
Log.d(Constants.TAG, "alarm received");
}
}
我正在设置闹钟并为闹钟注册AlarmReceiver类的地方。
public class UnityNotificationManager
{
public static void SetNotification(int id, long delayMs, String title, String message, String ticker, int sound, int vibrate,
int lights, String largeIconResource, String smallIconResource, int bgColor, String bundle, String dataString)
{
Context currentActivity = UnityPlayer.currentActivity;
AlarmManager am = (AlarmManager)currentActivity.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(Constants.ALARM_RECEIVER);
intent.setClass(currentActivity, AlarmReceiver.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.putExtra("ticker", ticker);
intent.putExtra("title", title);
intent.putExtra("message", message);
intent.putExtra("id", id);
intent.putExtra("color", bgColor);
intent.putExtra("sound", sound == 1);
intent.putExtra("vibrate", vibrate == 1);
intent.putExtra("lights", lights == 1);
intent.putExtra("l_icon", largeIconResource);
intent.putExtra("s_icon", smallIconResource);
intent.putExtra("bundle", bundle);
intent.putExtra("dataString", dataString);
PendingIntent pendingIntent = PendingIntent.getBroadcast(currentActivity,
id, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pendingIntent);
long finalTime = System.currentTimeMillis() + delayMs;
if (Build.VERSION.SDK_INT < 23) {
am.set(AlarmManager.RTC_WAKEUP,finalTime, pendingIntent);
} else {
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,finalTime, pendingIntent);
}
Log.d(Constants.TAG, "event fired finalTime = "+ finalTime);
}
}
上面使用的Constants.ALARM_RECEIVER
的值与广播AlarmReceiver将侦听的清单中定义的操作名称相同。
<receiver android:name="com.example.app.AlarmReceiver">
<intent-filter>
<action android:name="com.example.app.alarm.action.trigger" />
</intent-filter>
</receiver>
使用显式广播的原因是android文档声明发布Android Oreo后,android应用程序将无法在后台使用隐式广播来提高性能。相同的链接:https://developer.android.com/about/versions/oreo/background.html#broadcasts
我还尝试使用WakefulBroadCastReceiver来避免在Android设备上通过Doze模式进行优化,但事实证明这个类在Android Oreo中已被弃用。相同的链接:https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html
上述代码适用于几乎所有其他制造商,除了运行在氧气操作系统上的One Plus设备。有没有办法解决这个问题,因为如果应用程序以相同的方式被杀死,WhatsApp等应用程序的通知将继续有效。
附加信息:
1.我在One Plus 5T上运行命令adb shell dumpsys package <package_name> | grep stopped
并返回以下输出:
User 0: ceDataInode=2039857 installed=true hidden=false suspended=false stopped=false notLaunched=false enabled=0 instant=false
反过来表明,在从最近的任务列表中滑动应用程序时,应用程序不会停止。此外,在应用程序信息页面上启用了“强制停止”按钮,表明应用程序尚未强制停止。
有人可以建议任何修复或解决方法来修复Oxygen OS上运行Android 7或更高版本的设备上的通知问题吗?
答案 0 :(得分:0)
是的,我也发现很难获得参考样本代码,因为8.0以后总是运行任务有限制。
不要在intent-actions
中放置任何Manifest.xml
,如下所示:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".CatchNumbers"
android:enabled="true"
android:exported="true" />
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true" >
</service>
<activity android:name=".developer_activity" />
<activity android:name=".WhiteListActivity" />
<activity android:name=".Contacts" />
</application>
请注意
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
我没有插入,当我在服务中注册运行时接收器时,android studio会自动插入它。这是必要的。
在我的receiver.java上,每个boot_complete
i在前台服务中注册接收器运行时。如果你想让你的接收器工作,这是必须的:
package com.example.rushi.instapromo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
public class Receiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Log.d("BootTest : ", "\nOnBootReceiver - Received a broadcast!");
Toast.makeText(context, "OnBootReceiver Received a broadcast!!", Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
context.startService(new Intent(context, WatchMan.class));
}
}
}
请注意,Watchman.java是注册运行时接收器的前台服务,如果不使用此方法,它将永远不会工作。我已经尝试了很多并发明了这是唯一的方式。
在前台服务中注册接收器,如
public class WatchMan extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "17";
private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
String PhoneNumber = "UNKNOWN";
Log.d("RECEIVER : ","IS UP AGAIN....");
try
{
String action = intent.getAction();
if(action.equalsIgnoreCase("android.intent.action.PHONE_STATE"))
{
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING))
{
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d("RECEIVER : ","Incoming number : "+PhoneNumber);
// update in database and goto catchnumber to sms
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, CatchNumbers.class));
}
else
{
context.startService(new Intent(context, CatchNumbers.class));
}
}
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE))
{
PhoneNumber = "UNKNOWN";
}
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
{
Log.d("RECEIVER : ","OUTGOING CALL RECEIVED....");
// UPDATED in database and JUST GOTO catchnumber to sms
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, CatchNumbers.class));
}
else
{
context.startService(new Intent(context, CatchNumbers.class));
}
}
}
if(action.equalsIgnoreCase("android.intent.action.NEW_OUTGOING_CALL"))
{
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d("RECEIVER : ","Outgoing number : "+PhoneNumber);
// update in database and BUT DO NOT GOTO catchnumber to sms
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("RECEIVER : ", "Exception is : ", e);
}
}
};
public WatchMan() { }
@Override
public void onCreate()
{
super.onCreate();
Log.d("WatchMan : ", "\nOnCreate...");
IntentFilter CallFilter = new IntentFilter();
CallFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
CallFilter.addAction("android.intent.action.PHONE_STATE");
this.registerReceiver(mCallBroadcastReceiver, CallFilter);
Log.d("WatchMan : ", "\nmCallBroadcastReceiver Created....");
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("Insta Promo")
.setContentText("InstaPromo Service ready")
.setTicker("InstaPromo Service ready")
.setSmallIcon(R.drawable.ic_launcher_background)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(17, mBuilder.build());
}
else
{
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
//startForeground(17, mBuilder.build());
mNotifyManager.notify(17, mBuilder.build());
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("WatchMan : ", "\nmCallBroadcastReceiver Listening....");
//return super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
public void onDestroy()
{
this.unregisterReceiver(mCallBroadcastReceiver);
Log.d("WatchMan : ", "\nDestroyed....");
Log.d("WatchMan : ", "\nWill be created again....");
}
@Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
请注意我的注册和未注册的NEW_OUTGOING_CALL
和PHONE_STATE
意图行为。 CatchNumbers
是另一个service
,我用来做任何我想要的传入和传出号码。
您的意图行为可能与我不同..但是,如果您希望它在8.0以后实施,这是唯一的方法。经过测试,我正在使用此代码。它支持4.2到Android P api等级29。在每次重启时,这两个意图过滤器和接收器都可以在我的
CatchNumbers
中使用。希望它真的能帮助你。或其他人。
答案 1 :(得分:0)
我观察到相同的行为。该错误似乎是Oxygen OS不允许广播接收器从PendingIntent开始。解决方案是在BroadcastReceiver上使用Service代替。
将您的代码从BroadcastReceiver的onReceive()移至服务的onStartCommand()方法,然后在PendingIntent中设置此Service类。
...
intent.setClass(currentActivity, AlarmService.class);
...
PendingIntent pendingIntent = PendingIntent.getService(currentActivity, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
...
希望这会有所帮助。