如果从“最近”中删除应用程序,Android Oreo 接收器将停止
Posted
技术标签:
【中文标题】如果从“最近”中删除应用程序,Android Oreo 接收器将停止【英文标题】:Android Oreo Receiver Stops If Removed App From Recents 【发布时间】:2018-04-14 10:36:17 【问题描述】:Receiver 适用于从 4.2 到 8.0 的所有 android 版本。即使应用从Recent Apps
中删除,但如果在Android Oreo 中从Recent Apps
中删除,它就不会再次触发接收器。
我的 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.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<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>
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true" />
<receiver
android:name=".Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
我的receiver.java:
public class Receiver extends BroadcastReceiver
public String PhoneNumber = "UNKNOWN";
@Override
public void onReceive(Context context, Intent intent)
Log.d("RECEIVER :","CAPTURED THE EVENT.....");
try
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
context.startForegroundService(new Intent(context, WatchMan.class));
else
context.startService(new Intent(context, WatchMan.class));
catch (Exception e)
e.printStackTrace();
Log.e("RECEIVER EXCEPTION : ", "Exception is : ", e);
我想知道我是否在代码中犯了任何错误? Android Developers Documentation
要求使用 context
注册接收器运行时。然后我在***
上搜索在运行时注册它,但看起来没有合适的线程被接受为答案。即使从Android Oreo
的recents
中移除,如何才能使接收器再次准备好?
提前谢谢你。
【问题讨论】:
***.com/questions/37787291/… 找到了一个尝试它...也许它会工作...??!! 不,没有用 【参考方案1】:我删除了不相关的帖子。我正在发布最终答案,因为它可能对其他人有所帮助。感谢@WIZARD 的帮助。
PHONE_STATE is implicit and will not be triggered on android Oreo or higher. So just place permissions in manifest like :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<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:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true">
</service>
<service
android:name=".CatchNumbers"
android:enabled="true"
android:exported="true">
</service>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
从前台服务注册隐式接收器:
public class WatchMan extends Service
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "17";
private boolean running;
private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent)
String PhoneNumber = "UNKNOWN";
Log.d("RECEIVER : ","HERE HERE");
try
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state == null)
PhoneNumber = "UNKNOWN";
else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d("INCOMING ","Incoming number : "+PhoneNumber);
if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d("OUTGOING ","Outgoing number : "+PhoneNumber);
if(!PhoneNumber.contentEquals("UNKNOWN"))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
context.startForegroundService(new Intent(context, CatchNumbers.class));
else
context.startService(new Intent(context, CatchNumbers.class));
catch (Exception e)
e.printStackTrace();
Log.e("RECEIVER EXCEPTION : ", "Exception is : ", e);
;
public WatchMan()
@Override
public void onCreate()
super.onCreate();
mBuilder = new NotificationCompat.Builder(this, null);
IntentFilter filterstate = new IntentFilter();
filterstate.addAction("android.intent.action.NEW_OUTGOING_CALL");
filterstate.addAction("android.intent.action.PHONE_STATE");
this.registerReceiver(mCallBroadcastReceiver, filterstate);
Log.d("RECEIVER : ", "\nCreated....");
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("Insta Promo")
.setContentText("Insta Promo Is Up..")
.setTicker("Insta Promo Is Up..")
.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);
running = true;
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(17, mBuilder.build());
@Override
public int onStartCommand(Intent intent, int flags, int startId)
Log.d("RECEIVER : ", "\nOnStartCommand....");
new Thread(new Runnable()
public void run()
while(running)
try
Log.d("RECEIVER : ", "\nALIVE..");
Thread.sleep(10000);
catch (InterruptedException e)
Log.d("RECEIVER : ", "\nThread : InterruptedException in Receiver...");
Log.e("RECEIVER : ", "\nException is : ", e);
catch (Exception e)
Log.d("RECEIVER : ", "\nThread : Exception Error in Receiver...");
Log.e("RECEIVER : ", "\nException is : ", e);
).start();
return START_STICKY;
@Override
public void onDestroy()
this.unregisterReceiver(mCallBroadcastReceiver);
running = true;
Log.d("RECEIVER : ", "\nDestroyed....");
Log.d("RECEIVER : ", "\nWill be created again....");
@Override
public IBinder onBind(Intent intent)
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
@Override
public void onTaskRemoved(Intent rootIntent)
super.onTaskRemoved(rootIntent);
Log.d("SERVICE : ", "\nTask Removed....");
有一些意图操作,如 NEW_OUTGOING_CALL 和 BOOT_COMPLETED,它们被排除在外,可以在接收器中实现并放置在清单中,如:
public class MyReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
Log.d("INSTA_BOOT : ", "\nBOOT_COMPLETE_EVENT_OF_INSTA....");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
context.startForegroundService(new Intent(context, WatchMan.class));
else
context.startService(new Intent(context, WatchMan.class));
因为我想重新注册或说想在 REBOOT 或 BOOT-COMPLETE 上重新启动前台服务
CatchNumbers.java is a simple service which performs operation when receiver triggers perticular actions.
它在每次重新启动时都能正常工作,并且不再需要 android:excludeFromRecents="true"
,因为即使用户从 Oreo 上的 recents
中删除它,它也会重新启动服务,因为它是 STICKY
。希望它可以帮助像我这样的人..!!
【讨论】:
【参考方案2】:根据 documentation 对 Android 8 中隐式广播的限制,您不能在清单中使用隐式接收器(尽管有一些例外,但手机状态接收器不在这些例外之列)
您必须使用前台服务并在前台服务中注册您的接收器而不是清单
从清单中删除手机状态接收器
在 onCreate of Service 中注册接收者:
@Override
public void onCreate()
super.onCreate();
phoneStateReceiver = new PhoneStateReceiver();
registerReceiver(phoneStateReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));
在 onDestroy 中取消注册:
@Override
public void onDestroy()
unregisterReceiver(phoneStateReceiver);
super.onDestroy();
为你的服务添加一个静态方法来启动服务:
// start service even if your app is in stopped condition in android 8+
static void requestStart(@NonNull final Context context, @NonNull final String action)
final Context appContext = context.getApplicationContext();
Intent intent = new Intent(appContext, AppService.class);
intent.setAction(action);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
// this is required to start the service if there is
// no foreground process in your app and your app is
// stopped in android 8 or above
appContext.startForegroundService(intent);
else
appContext.startService(intent);
在您的onStartCommand
中启动前台
@Override
public int onStartCommand(Intent intent, int flags, int startId)
if(ACTION_START.equals(intent.getAction()))
startForeground(ID, notification);
else if(ACTION_STOP.equals(intent.getAction()))
stopForeground(true);
return START_STICKY;
【讨论】:
以上是关于如果从“最近”中删除应用程序,Android Oreo 接收器将停止的主要内容,如果未能解决你的问题,请参考以下文章
Android - WebSocket - 从最近使用的应用程序清除应用程序时,连接从服务中删除
从最近的任务中删除应用程序时,Android静态BroadcastReceiver无法正常工作