【问题标题】:Broadcast receiver not working in android oreo广播接收器在android oreo中不起作用
【发布时间】:2018-07-07 09:16:19
【问题描述】:

我的广播接收器无法在 oreo 上运行,但它在 oreo 下运行正常,我对此进行了很多搜索,但找不到合适的解决方案。有没有人面临同样的问题,这是我关于我的服务的代码,其中已经实现了广播。请建议我如何在奥利奥工作。

这是课程

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

注意进入接收器,任何人都可以帮助我吗?

根据讨论添加新内容

清单数据:-

使用权限 :-

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

接收者:-

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

我的广播接收器类:-

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

休息相同的服务将接听电话,但问题是我仍然没有在接收器中接听电话。主要的一点是该服务应该只在用户点击按钮后才被调用,而不是自动调用,因为我必须通过一些服务中的值。

谢谢

【问题讨论】:

  • 我收到了您的请求;谷歌没有很好的文档,也没有示例实现示例。但我已经在 oreo 中实现了它,甚至在即将推出的 android 上测试了 android P;工作正常...
  • 我要写答案,建议你关注它,让我知道对它的反馈..
  • START_NOT_STICKY 只要执行一次就删除您的服务...由于下次没有服务在后台运行...您的呼叫广播接收器也不在那里接收广播. START_STICKY 应始终保持在后台
  • 再次,因为您正在实施接收器的服务将始终运行(正在进行的过程)应该在调用 service oncreate 时立即通过通知通知,以便 onstartcommand 将始终保持活动状态
  • 我建议现在不要实现任何代码:在任务中打破它.. 1)通过在 manifest.xml 中注册仅在启动完成接收器上实现 2)从接收器调用您的服务,这将只是print hello 3) 使用 manifest.xml 上传上述代码;接收器和服务代码在这里,让我看看 4) 然后在服务中实现运行时广播接收器,用于接收呼叫广播...

标签: android broadcastreceiver android-8.0-oreo


【解决方案1】:

广播限制

如果应用注册接收广播,则应用的接收器在每次发送广播时都会消耗资源。如果太多的应用程序注册以接收基于系统事件的广播,这可能会导致问题;触发广播的系统事件会导致所有这些应用程序快速连续消耗资源,从而影响用户体验。为了缓解这个问题,Android 7.0(API 级别 25)对广播设置了限制,如后台优化中所述。 Android 8.0(API 级别 26)使这些限制更加严格。

  1. 面向 Android 8.0 或更高版本的应用无法再在其清单中为隐式广播注册广播接收器。隐式广播是不专门针对该应用程序的广播。例如,ACTION_PACKAGE_REPLACED 是一个隐式广播,因为它被发送给所有注册的监听器,让他们知道设备上的某些包被替换了。但是,ACTION_MY_PACKAGE_REPLACED 不是隐式广播,因为它只会发送到包被替换的应用,无论有多少其他应用注册了该广播的侦听器。

  2. 应用可以继续在其清单中注册显式广播。

  3. 应用可以在运行时使用 Context.registerReceiver() 为任何广播注册接收器,无论是隐式还是显式。

  4. 需要签名权限的广播不受此限制,因为这些广播仅发送到使用相同证书签名的应用,而不是设备上的所有应用。

Check Official Documentation here

希望这会有所帮助。

【讨论】:

  • @Makank 我需要添加包名吗?
  • @MayankBhatnagar 一些意图行为被排除在禁令之外
  • @MayankBhatnagar 如果静态广播接收器的 action 值是任意的,那么它是隐式接收器还是显式接收器?
  • 如果我们使用android Oreo不允许的广播会发生什么?它会不起作用还是应用程序崩溃?
【解决方案2】:

问题在于您尝试运行的服务,服务或持久性后台服务不允许长时间运行针对 Oreo 及更高版本的应用程序。

检查 this guidethis as well 以了解迁移您的应用以支持 Oreo。

【讨论】:

  • 你能提供任何参考,而不是谷歌开发者网站,他们只是提供提示,没有实时示例。因为自 2018 年 11 月以来,我在 SAMSUNG 和 NEXUS 设备中遇到了这个后台崩溃问题。为什么 Google 不站在开发者的角度思考,让我们陷入这样的困境,这是我现在最大的担忧。
【解决方案3】:

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

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

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

    }
}

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

有关完整参考,您还可以查看https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices

【讨论】:

  • 上面的链接代码在应用被杀时不起作用。
【解决方案4】:

在 create 方法而不是 manifest 中注册您的广播接收器,并在 destroy 方法中取消注册。希望这将适用于 android 9。

【讨论】:

  • 寻找静态广播接收器
【解决方案5】:

Android 8.0 对 JobScheduler 进行了多项改进,可以更轻松地使用计划作业替换服务和广播接收器:

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

在许多情况下,以前注册隐式广播的应用可以通过使用 JobScheduler 作业获得类似的功能。例如,社交照片应用程序可能需要不时对其数据执行清理,并且更喜欢在设备连接到充电器时执行此操作。以前,该应用程序在其清单中为 ACTION_POWER_CONNECTED 注册了一个接收器;当应用程序接收到该广播时,它会检查是否需要清理。要迁移到 Android 8.0 或更高版本,应用程序会从其清单中删除该接收器。相反,该应用会安排在设备空闲和充电时运行的清理作业。

【讨论】:

    【解决方案6】:

    我在实现通话录音应用时遇到了类似的问题,

    我在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>
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-14
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多