简体   繁体   English

广播接收器在android oreo中不起作用

[英]Broadcast receiver not working in android oreo

My Broadcast receiver is not working on oreo but its working below oreo it's working fine, I searched a lot regarding this but could not find the suitable solution.我的广播接收器无法在 oreo 上运行,但它在 oreo 下运行正常,我对此进行了很多搜索,但找不到合适的解决方案。 Does anyone face the same problem, here is my code regarding my service in which broadcast has been implemented.有没有人面临同样的问题,这是我关于我的服务的代码,其中已经实现了广播。 Kindly suggests me that how I can make in working in oreo.请建议我如何在奥利奥工作。

Here is the class这是课程

public int onStartCommand(Intent intent, int flags, int startId) {
        mContext = this;
        mAppPreferences = new AppPreferences(mContext);
        if (intent.getExtras() != null) {
            data = (String) intent.getExtras().get("showPopUp");
            phoneNumber= (String) intent.getExtras().get("dialNumber");
        }
        final IntentFilter intentFilter = new IntentFilter();
        if (data.equalsIgnoreCase("true")) {
            showPopup(getApplicationContext());
            Utils.ApiHit(phoneNumber,getApplicationContext());
        }
        intentFilter.setPriority(2147483647);
        intentFilter.addAction("android.intent.action.PHONE_STATE");
        callExplicitReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
                    if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
                        savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
                    } else {
                        String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
                        phoneNumber = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
                        int state = 0;
                        if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                            state = TelephonyManager.CALL_STATE_IDLE;
                        } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                            state = TelephonyManager.CALL_STATE_OFFHOOK;
                        } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
                            state = TelephonyManager.CALL_STATE_RINGING;
                        }
                        onCallStateChanged(context, state, phoneNumber);
                    }
                }
            }
        };
        mContext.registerReceiver(callExplicitReceiver, intentFilter);
        return START_NOT_STICKY;
    }


    public void onIncomingCallReceived(Context ctx, String number, Date start) {
    }

    public void onIncomingCallAnswered(Context ctx, String number, Date start) {
        if (popupView.getVisibility() == View.GONE) {
            popupView.setVisibility(View.VISIBLE);
        }
    }

    public void onIncomingCallEnded(Context ctx, String number, Date start, Date end) {

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                DeleteCallLogByNumber(number);
            }
        }, 2000);
        if (popupView.getVisibility() == View.VISIBLE) {
            popupView.setVisibility(View.GONE);
        }
    }

    public void onOutgoingCallStarted(Context ctx, String number, Date start) {
//        mAppPreferences.setPrefrenceString("busy", "yes");
//        if (data.equalsIgnoreCase("true")) {
            mediaPlayer = MediaPlayer.create(ctx, R.raw.speech_audio);
//        } else {
//            mediaPlayer = MediaPlayer.create(ctx, R.raw.speech_audio);
//        }

        mediaPlayer.start();
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                    mediaPlayer.stop();
                    mediaPlayer.release();
                }
            }
        }, 12000);
        if (popupView.getVisibility() == View.GONE) {
            popupView.setVisibility(View.VISIBLE);
        }
    }


    public void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
        mAppPreferences.setPrefrenceString("busy", "no");
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                DeleteCallLogByNumber(phoneNumber);
            }
        }, 2000);
        if (popupView.getVisibility() == View.VISIBLE) {
            popupView.setVisibility(View.GONE);
        }
    }

    public void onMissedCall(Context ctx, String number, Date start) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                DeleteCallLogByNumber(phoneNumber);
            }
        }, 2000);
        if (popupView.getVisibility() == View.VISIBLE) {
            popupView.setVisibility(View.GONE);
        }
    }




public void onCallStateChanged(Context context, int state, String number) {
        if (lastState == state) {
            return;
        }
        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                isIncoming = true;
                callStartTime = new Date();
                savedNumber = number;
                onIncomingCallReceived(context, number, callStartTime);
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                if (lastState != TelephonyManager.CALL_STATE_RINGING) {
                    isIncoming = false;
                    callStartTime = new Date();
                    onOutgoingCallStarted(context, savedNumber, callStartTime);
                } else {
                    isIncoming = true;
                    callStartTime = new Date();
                    onIncomingCallAnswered(context, savedNumber, callStartTime);
                }
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                if (popupView.getVisibility() == View.VISIBLE) {
                    popupView.setVisibility(View.GONE);
                }
                if (lastState == TelephonyManager.CALL_STATE_RINGING) {
                    onMissedCall(context, savedNumber, callStartTime);
                } else if (isIncoming) {
                    onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
                } else {
                    onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
                }
                break;
        }
        lastState = state;
    }

    @Override
    public void onDestroy() {
        mContext.unregisterReceiver(callExplicitReceiver);
    }

Noting is in coming inside receiever,Can anyone help me out in this?注意进来接收器,有人可以帮助我吗?

New Additions as per discussion根据讨论添加新内容

Manifest data :-清单数据:-

Permission used :-使用的权限:-

 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Reciver :-接收器:-

<receiver android:name="com.example.dialer.AppUtils.StartUpBootReceiver" android:enabled="true" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

My BroadCast Reciever Class :-我的广播接收器类:-

public class StartUpBootReceiver extends BroadcastReceiver {

    private Context mContext;

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext= context;
        String action = "START";

        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            {
                context.startForegroundService(new Intent(context, PhoneStateService.class));
            }
            else
            {
                context.startService(new Intent(context, PhoneStateService.class));
            }
        }
    }


    private boolean isServiceRunning(Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }
}

Rest the same service will get the call, but the problem is i still does not get call in receiver.And m primary point is that service should only get called once user tap on button , not automatically as i have to pass some values in the service.休息相同的服务将接听电话,但问题是我仍然没有在接收器中接听电话。主要的一点是该服务应该只在用户点击按钮后才被调用,而不是自动调用,因为我必须在服务。

Thanks谢谢

Broadcast Limitations广播限制

If an app registers to receive broadcasts, the app's receiver consumes resources every time the broadcast is sent.如果应用注册接收广播,则应用的接收器在每次发送广播时都会消耗资源。 This can cause problems if too many apps register to receive broadcasts based on system events;如果太多的应用程序注册以接收基于系统事件的广播,这可能会导致问题; a system event that triggers a broadcast can cause all of those apps to consume resources in rapid succession, impairing the user experience.触发广播的系统事件会导致所有这些应用程序快速连续消耗资源,从而影响用户体验。 To mitigate this problem, Android 7.0 (API level 25) placed limitations on broadcasts, as described in Background Optimization.为了缓解这个问题,Android 7.0(API 级别 25)对广播设置了限制,如后台优化中所述。 Android 8.0 (API level 26) makes these limitations more stringent. Android 8.0(API 级别 26)使这些限制更加严格。

  1. Apps that target Android 8.0 or higher can no longer register broadcast receivers for implicit broadcasts in their manifest.面向 Android 8.0 或更高版本的应用无法再在其清单中为隐式广播注册广播接收器。 An implicit broadcast is a broadcast that does not target that app specifically.隐式广播是不专门针对该应用程序的广播。 For example, ACTION_PACKAGE_REPLACED is an implicit broadcast, since it is sent to all registered listeners, letting them know that some package on the device was replaced.例如,ACTION_PACKAGE_REPLACED 是一个隐式广播,因为它被发送给所有注册的监听器,让他们知道设备上的某些包被替换了。 However, ACTION_MY_PACKAGE_REPLACED is not an implicit broadcast, since it is sent only to the app whose package was replaced, no matter how many other apps have registered listeners for that broadcast.但是, ACTION_MY_PACKAGE_REPLACED 不是隐式广播,因为它只发送到包被替换的应用程序,无论有多少其他应用程序已经为该广播注册了侦听器。

  2. Apps can continue to register for explicit broadcasts in their manifests.应用程序可以继续在其清单中注册显式广播。

  3. Apps can use Context.registerReceiver() at runtime to register a receiver for any broadcast, whether implicit or explicit.应用程序可以在运行时使用 Context.registerReceiver() 为任何广播注册接收器,无论是隐式的还是显式的。

  4. Broadcasts that require a signature permission are exempted from this restriction, since these broadcasts are only sent to apps that are signed with the same certificate, not to all the apps on the device.需要签名权限的广播不受此限制,因为这些广播仅发送到使用相同证书签名的应用程序,而不是设备上的所有应用程序。

From the Official Documentation来自官方文档

The problem comes with the service you're trying to run, services or persistent background services are not permitted to run for long for apps targeting Oreo and above.问题出在您尝试运行的服务上,对于针对 Oreo 及更高版本的应用程序,服务或持久性后台服务不允许长时间运行。

Check this guide and this as well for migrating your app to support Oreo.查看本指南以及迁移您的应用程序以支持 Oreo 的信息。

I also had this kind of issue, but I found a better solution:我也遇到过这种问题,但我找到了更好的解决方案:

Class MyReceiver MyReceiver 类

@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());
    }
}

Class AppController类 AppController

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

    }
}

Class MainActivity类 MainActivity

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

For complete reference you can see also https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices如需完整参考,您还可以查看https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices

Android 8.0 offers several improvements to JobScheduler that make it easier to replace services and broadcast receivers with scheduled jobs: Android 8.0 对 JobScheduler 进行了多项改进,可以更轻松地使用计划作业替换服务和广播接收器:

https://developer.android.com/about/versions/oreo/backgroundhttps://developer.android.com/about/versions/oreo/background

In many cases, apps that previously registered for an implicit broadcast can get similar functionality by using a JobScheduler job.在许多情况下,以前注册隐式广播的应用程序可以通过使用 JobScheduler 作业获得类似的功能。 For example, a social photo app might need to perform cleanup on its data from time to time, and prefer to do this when the device is connected to a charger.例如,社交照片应用程序可能需要不时对其数据执行清理,并且更喜欢在设备连接到充电器时执行此操作。 Previously, the app registered a receiver for ACTION_POWER_CONNECTED in its manifest;以前,该应用程序在其清单中为 ACTION_POWER_CONNECTED 注册了一个接收器; when the app received that broadcast, it would check whether cleanup was necessary.当应用程序接收到该广播时,它会检查是否需要清理。 To migrate to Android 8.0 or higher, the app removes that receiver from its manifest.要迁移到 Android 8.0 或更高版本,应用程序会从其清单中删除该接收器。 Instead, the app schedules a cleanup job that runs when the device is idle and charging.相反,该应用会安排在设备空闲和充电时运行的清理作业。

Register your broadcast receiver in activity on create method rather than in manifest and unregister it on destroy method.在 create 方法而不是 manifest 中注册您的广播接收器,并在 destroy 方法中取消注册。 Hope this will work on android 9.希望这将适用于android 9。

I have faced the similar issue when implementing call recording app,我在实现通话录音应用程序时遇到了类似的问题,

I have added the following code in the AndroidManifest.xml file, then the register is working normally我在AndroidManifest.xml文件中添加了如下代码,那么注册机就可以正常工作了

         <receiver android:name=".Services.Receiver"
             android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
             android:enabled="true"
             android:exported="true">
            <intent-filter>

                <action android:name="android.intent.action.PHONE_STATE"/>
                <action android:name="android.intent.action.ANSWER"/>
                <action android:name="android.intent.action.CALL_BUTTON"/>
                <action android:name= "android.intent.action.NEW_OUTGOING_CALL"/>
                <action android:name="android.intent.action.BOOT_COMPLETED" />

            </intent-filter>
         </receiver>

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM