简体   繁体   English

如果从最近删除的应用程序,Android Oreo Receiver会停止

[英]Android Oreo Receiver Stops If Removed App From Recents

Receiver works on all android versions from 4.2 upto 8.0. Receiver适用于4.2至8.0的所有android版本。 Even if app is removed from Recent Apps But if removed from Recent Apps in Android Oreo, it then never triggers receiver again. 即使从“ Recent Apps程序”中删除了该Recent Apps但即使从Android Oreo的“ Recent Apps中删除了该Recent Apps ,也不会再触发接收方。

my manifest.xml : 我的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>

My receiver.java : 我的receive.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);
    }

}

I want to know if i am doing any mistake in code? 我想知道我是否在代码中犯了任何错误? Android Developers Documentation asking to register receiver runtime using context . Android Developers Documentation要求使用context注册接收器运行时。 Then i searched for registering it in runtime on stackoverflow but looks no proper thread accepted as answer. 然后我搜索了在stackoverflow上的运行时中注册它,但是看起来没有合适的线程被接受作为答案。 How can make receiver to to be ready again, even if removed from recents of Android Oreo ? 即使已从Android Oreo recents Android Oreo删除,如何使接收器再次准备好?

Thanking you in advance. 预先感谢您。

Based on the documentation for restrictions on implicit broadcast in Android 8, you cannot use implicit receivers in your manifest (although there are some exceptions, but phone state receiver is not among those exceptions) 根据有关Android 8中隐式广播限制的文档 ,您不能在清单中使用隐式接收器(尽管有一些例外,但电话状态接收器不在这些例外之中)

You have to use foreground service and register your receiver in your foreground service instead of manifest 您必须使用前台服务,并在前台服务中而不是清单中注册接收者

remove phone state receiver from manifest 从清单中删除电话状态接收器

register receiver in onCreate of Service: 在服务的onCreate中注册接收者:

   @Override
    public void onCreate() {
        super.onCreate();
        phoneStateReceiver = new PhoneStateReceiver();
        registerReceiver(phoneStateReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));
    }

unregister in onDestroy: 在onDestroy中注销:

   @Override
    public void onDestroy() {
        unregisterReceiver(phoneStateReceiver);
        super.onDestroy();
    }

add a static method to your service to start service: 向您的服务添加静态方法以启动服务:

// 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);
        }
    }

start foreground in your onStartCommand 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;
}

I have deleted unrelated posts. 我删除了不相关的帖子。 I am posting final answer as it may help others. 我正在发布最终答案,因为这可能会对其他人有所帮助。 @WIZARD help was thankful. @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>

Register implicit receivers from foreground service : 从前台服务注册隐式接收者:

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....");
}


}

There are some intent actions like NEW_OUTGOING_CALL AND BOOT_COMPLETED which are excluded and can be implemented in receiver and placed in manifest like : 有一些意向动作,例如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));
    }
}
}

As i wanted to re-register or say want to restart foreground service on REBOOT OR BOOT-COMPLETE 正如我想重新注册或说要在REBOOT或BOOT-COMPLETE上重新启动前台服务


CatchNumbers.java is a simple service which performs operation when receiver triggers perticular actions.

It works good on every restart and as android:excludeFromRecents="true" is not needed anymore as even if user removes it from recents on Oreo it will restart the service as it is STICKY . 它在每次重新启动时都可以正常工作,因为不再需要android:excludeFromRecents="true" ,即使用户从Oreo的recents用户中删除它,它也会因为STICKY重新启动服务。 Hope it helps someone like me..!! 希望它能帮助像我这样的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果从最近的应用程序中删除了应用程序,则不会调用接收方 - Receiver not getting invoked if removed app from recents 服务在Android版本Oreo中停止,应用崩溃 - Service stops in android version Oreo and app crashes 当应用程序从最近状态关闭时,销毁时不会收到呼叫-Android - On destroy does not get call when app closes from recents - Android 服务在 android 8 (oreo) 下意外停止 - service stops unexpectedly under android 8 (oreo) 如果从应用启动器启动,则Android App始终会重新启动/冷启动,而不是从最近启动 - Android App always Restarts/Cold Starts if launched from app launcher instead of recents 从最近的应用程序中删除应用程序后,IntentService停止工作 - IntentService stops working when app is removed from recent apps 当应用程序在奥利奥中被杀死时,广播接收器不工作为什么? - Broadcast Receiver not working when the App killed in Oreo Why? 应用被杀死时,广播接收器未在Oreo上收听 - Broadcast receiver not listening on Oreo when app gets killed 是否有可能在Android中为我的应用程序的活动创建一个最近的屏幕 - Is it possible to create a recents screen like in android for the activities of my app 在针对Oreo的Android应用上使用Android Broadcast - Working with Android Broadcast on an Android App targeting Oreo
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM