奥利奥系统:广播接收器无法工作

5

我试图在我的应用程序中获取通知触发器,每当用户进行新的呼叫时。我在我的活动中注册接收器,并在onDestroy()方法中销毁它。以下是注册的代码片段:

registerReceiver(inComingCall = new IncomingCall(),new IntentFilter("android.intent.action.PHONE_STATE"));

我的问题是在Broadcast接收器的override onReceive()方法中没有触发任何事件。请告诉我是否有任何新的实现或者单独处理方式可以接收针对Oreo系统的广播。
提前感谢。

1
你的清单文件(manifest)中是否注册了READ_PHONE_STATE权限并请求了该权限? - Sagar
1
从Android O开始,权限行为已经改变。请查看此链接:https://developer.android.com/about/versions/oreo/android-8.0-changes.html - Chithra B
是的,我已经添加了权限,但仍然无法正常工作。以下是代码:<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>。 - user1955126
Oreo在Broadcast Receiver方面有一些限制。请查看此博客链接https://medium.com/exploring-android/exploring-background-execution-limits-on-android-oreo-ab384762a66c。 - Ashok
这是最佳解决方案 https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices - Danial clarc
4个回答

9
我长期以来一直面临着这个问题。每个人都会向你提供一个指向Google开发者网站的链接,其中仅描述了他们对后台服务有限制的情况,没有适当的文档,也没有示例代码向开发者展示如何在Oreo或更高版本上实现它。即使在Stack Overflow上,您也只会找到有关Google开发人员网站限制的链接。
我希望您或其他开发人员会觉得这非常有帮助。
仍然存在一些排除项,例如NEW_OUTGOING_CALLBOOT_COMPLETED,您仍然可以在清单中使用。但是,在应用程序上下文中实现运行时是一个好习惯。我希望我的PHONE_STATE始终准备好接收来电和去电,即使在每次重新启动时...
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rushi.boottest">

<uses-sdk
    android:minSdkVersion="16"
    android:targetSdkVersion="26" />

<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.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<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">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver
        android:name=".MyReceiver"
        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>
</application>

</manifest>

在上面的 manifest.xml 文件中,我没有放置 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE。因为我在运行时实现了它,所以它会被 Android Studio 自动插入。


这是我的 OnBoot 接收器:

package com.example.rushi.boottest;

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 MyReceiver 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 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("RECEIVER : ","Incoming number : "+PhoneNumber);
            }
            if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
            {
                PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                Log.d("RECEIVER : ","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 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("Checking New Numbers")
            .setTicker("Checking New Numbers")
            .setSmallIcon(R.drawable.ic_launcher_background)
            .setPriority(Notification.PRIORITY_LOW)
            .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_NOT_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");
}
}

现在,在调用之前将电话号码插入到sqlite数据库表中;这样您就可以从CatchNumbers.java服务中读取它,并对进出的数字执行任何操作。希望它能帮助你或其他人。


嗨@Sandhya,你能看一下我的查询吗?https://dev59.com/1ek5XIcBkEYKwwoY7eIE#51221721 - Era Singla
完美的解决方案...谢谢 :) - Krupa Kakkad
看起来现在不工作。它在One plus 5手机上无法运行。 - Feroz Siddiqui
@FerozSiddiqui,One plus X是一个非标准的手机制造商之一,还有多个像VIVO、MI等。它使用的是OXYGEN OS而不是原生的Android操作系统。(你需要关闭电池优化才能在上面工作。我已经在One Plus 3上测试过了,可以正常运行。但是在Oreo版本之后,你需要让用户进行电池优化例外,要求他们进行豁免。) - sandhya sasane

0

Sandhya Sasane的解决方案在Android 9模拟器上对我有效,可以接收到BOOT_COMPLETED通知(无论是通过“adb”强制执行还是重新启动模拟器)。

但是,在真实设备华为P-Smart上,配备EMUI 9.1.0.119,从未发生过 :(


0

以上的答案似乎都对我不起作用。 这是我的解决方案,但是使用 Kotlin。请粘贴以下代码部分,并根据您的应用程序更改必要的详细信息。

在 MainActivity 的 onCreate 方法之后:

override fun onStart() {
    super.onStart()
    var intentfilter1: IntentFilter = IntentFilter("com.spotify.music.playbackstatechanged")

    intentfilter1.addCategory(Intent.CATEGORY_DEFAULT)
    registerReceiver(mreceiver, intentfilter1)


}

override fun onStop() {
    super.onStop()
    unregisterReceiver(mreceiver)
}

在 onCreate 方法中:

mreceiver = SpotifyBroadcastReceiver()

在 MainActivity 的 onCreate 方法之前:

lateinit var mreceiver: SpotifyBroadcastReceiver

主清单文件

     <receiver android:name=".SpotifyBroadcastReceiver" //name of the broadcast receiver class
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.spotify.music.playbackstatechanged" /> //Things required by my broadcast receiver class
        </intent-filter>
    </receiver>

如果我漏掉了什么或者你需要与代码片段相关的其他信息,请告诉我。

附言:我也是 Kotlin 的新手...我只是分享了对我有用的内容。它可能适用于你的配置,也可能不适用,所以祝你编码愉快!


-1

我也遇到过这种问题,但是我找到了更好的解决方案:

@BroadcastReceiverActions({"android.intent.action.SCREEN_ON", "android.intent.action.SCREEN_OFF",
        "android.intent.action.DREAMING_STARTED", "android.intent.action.DREAMING_STOPPED",
        "android.intent.action.ACTION_POWER_DISCONNECTED", "android.intent.action.ACTION_POWER_CONNECTED",
        "android.net.conn.CONNECTIVITY_CHANGE"})
public class MyReceiver extends BroadcastReceiver {

    public MyReceiver() {
        super();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Session.getGlobalReceiverCallBack(context, intent);

        //Log.e("dfd", "" + intent.getAction());
    }
}

public class AppController extends Application {

    private BroadcastReceiver receiver;
    MyReceiver mR;

    @Override
    public void onCreate() {
        super.onCreate();
        mR = new MyReceiver();
        receiver = DynamicReceiver.with(mR)
                .register(this);

    }
}

public class MainActivity extends AppCompatActivity implements GlobalReceiverCallBack {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Session.setmGlobalReceiverCallback(this);

    }

    @Override
    public void onCallBackReceived(Context context, Intent intent) {

        Toast.makeText(context, "" + intent.getAction(), Toast.LENGTH_LONG).show();
    }
}

完整的参考资料可以查看https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices


当应用程序未运行时无法工作。如果应用程序被终止或从最近的屏幕中移除,则应用程序将不会接收任何广播。 - mdroid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接