当前位置: 首页 > 知识库问答 >
问题:

Android中设备重启后广播接收器无法工作

丘普松
2023-03-14

我已经检查了所有相关的问题,还没有找到这个问题的解决方案。所以这对我来说绝对是个新问题。

我所拥有的

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.app.myapp">

    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
    <uses-permission android:name="com.android.vending.BILLING" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    <uses-feature
        android:name="android.hardware.telephony"
        android:required="false" />

    <uses-feature
        android:name="android.hardware.screen.portrait"
        android:required="false" />

    <application
        android:name=".base.MyApp"
        android:allowBackup="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/label_app_name"
        android:largeHeap="true"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:replace="label, allowBackup">

        <receiver android:name=".mics.BootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
        </receiver>

        <receiver android:name=".PhoneCallReceiver">
            <intent-filter>
                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
            </intent-filter>
        </receiver>

        <receiver
            android:name=".mics.DeviceAdminReceiver"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            </intent-filter>

            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/device_admin" />
        </receiver>

        <receiver
            android:name="com.clevertap.android.sdk.InstallReferrerBroadcastReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="com.android.vending.INSTALL_REFERRER" />
            </intent-filter>
        </receiver>

        <meta-data
            android:name="com.app.myapp.utils.ImageLoaderModule"
            android:value="GlideModule" />

        <meta-data
            android:name="com.app.myapp.utils.AudioCoverLoaderModule"
            android:value="GlideModule" />

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">

            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

        <activity
            android:name=".core.activities.SplashActivity"
            android:excludeFromRecents="true"
            android:label="@string/label_app_name"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>

        <activity-alias
            android:name=".core.activities.SplashActivity-Alias"
            android:icon="@drawable/ic_launcher"
            android:label="@string/label_app_name"
            android:noHistory="true"
            android:targetActivity="com.app.myapp.core.activities.SplashActivity">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        </activity-alias>

        <activity
            android:name=".core.flow.authFlow.activities.AuthFlowActivity"
            android:excludeFromRecents="true"
            android:label="@string/label_app_name"
            android:screenOrientation="portrait" />

        <service android:name=".features.fileCloudSync.KillNotificationService" />

    </application>

</manifest>
public class BootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            AlertUtils.showToast(context, "BOOT COMPLETED", Toast.LENGTH_LONG);
        }
    }
}
public class PhoneCallReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
            AlertUtils.showToast(context, "PHONE CALL RECEIVED", Toast.LENGTH_LONG);
            // Simplified for brevity
        }
    }
}

我的观察

我已经彻底测试过了。重新启动设备后,接收器在my Nexus 5x(牛轧糖)、Nexus 6p(牛轧糖)、YU Yuphoria(Lollipop)中工作正常,但在my OnePlus 3(牛轧糖)和Mi 4i(Lollipop)中工作不正常。

同样的代码如何能在少数设备上完美地工作,而在其他设备上完全不工作?我一点都没改变。

那么实际问题在哪里呢?它是在我的应用程序中(但它在其他设备上工作得很好)还是在操作系统和设备中(小测试项目在相同的操作系统和设备上工作得很好)?

对我来说真的很困惑。我需要一些专家的帮助。

编辑2

./adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.app.myapp
Broadcasting: Intent { act=android.intent.action.BOOT_COMPLETED pkg=com.app.myapp }
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.BOOT_COMPLETED from pid=25378, uid=2000
    at android.os.Parcel.readException(Parcel.java:1683)
    at android.os.Parcel.readException(Parcel.java:1636)
    at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:3696)
    at com.android.commands.am.Am.sendBroadcast(Am.java:778)
    at com.android.commands.am.Am.onRun(Am.java:404)
    at com.android.internal.os.BaseCommand.run(BaseCommand.java:51)
    at com.android.commands.am.Am.main(Am.java:121)
    at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
    at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:276)

2)之后我尝试使用PROCESS_OUTGOING_CALLS广播。

./adb shell am broadcast -a android.intent.action.PROCESS_OUTGOING_CALLS -p com.app.myapp

我拿到了,

Broadcasting: Intent { act=android.intent.action.PROCESS_OUTGOING_CALLS pkg=com.app.myapp }
Broadcast completed: result=0

似乎广播很成功,但我没有看到任何祝酒词或任何日志。然后我打开拨号器拨一个号码,然后我可以看到吐司和日志两者。

我终于找到了问题的根本原因发生在我的一加3。我的OnePlus3最近更新为牛轧糖,他们引入了一个类似于Mi设备的功能,可以防止某些应用程序在重启后自动启动。

在禁用这个功能,我的应用程序开始接收广播后,重新启动完美。但这仍然不能解释两件事。

1)我的小测试项目在自动启动应用程序列表中会自动加白名单,这就是为什么它能正常工作。但这是怎么可能的?为什么操作系统认为这个小应用程序值得自动启动?

但是,如果用户在授予辅助功能权限后撤销了它,那么是否有一种方法让我以编程方式检查辅助功能权限是否对我的应用程序可用?

共有1个答案

戎元忠
2023-03-14

这是一个在你提到的一加和MI两个设备上经过测试和工作的解决方案。

正如你所说,一加和Mi设备上的自动启动防止功能可以防止应用程序在启动完成时自动启动服务,从而提高设备的整体启动速度和电池性能。然而,即使打开这个功能,也有一个变通方法来让你的应用程序工作。

我注意到,如果您的应用程序中有AccessibilityService,并且由用户打开,那么您的应用程序将通过这些制造商应用的筛选器,并且应用程序将接收它的引导完成事件,并且任何其他BroadcastReceiver都将按预期工作。

首先将此权限添加到AndroidManifest.xml中,

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

这将允许您向系统注册应用程序的AccessibilityService

现在,通过在项目的res文件夹下的XML文件夹中创建一个文件,例如my_accessibility_service.XML,为AccessibilityService添加一个非常基本的配置。

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:description="@string/service_desc"
    android:notificationTimeout="100"/>
public class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) { }

    @Override
    public void onInterrupt() {

    }
}

注意,由于您不需要AccessibilityService来实现任何目的,因此可以将重写的方法保留为空。

最后,只需在AndroidManifest.xml中声明AccessibilityService

<service
    android:name=".MyAccessibilityService"
    android:label="@string/app_name"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService"/>
    </intent-filter>

    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/my_accessibility_service"/>
</service>

仅此而已。现在在你的应用程序中,只需要让你的用户从设置中打开你的应用程序的辅助服务,然后让它打开,瞧!你的应用程序在所有设备上都能正常工作,即使OS设置了一个过滤器,应用程序应该在引导时自动启动。

private static final int ACCESSIBILITY_ENABLED = 1;

public static boolean isAccessibilitySettingsOn(Context context) {
    int accessibilityEnabled = 0;
    final String service = context.getPackageName() + "/" + MyAccessibilityService.class.getCanonicalName();
    try {
        accessibilityEnabled = Settings.Secure.getInt(
                context.getApplicationContext().getContentResolver(),
                android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
    } catch (Settings.SettingNotFoundException e) {
        Log.e("AU", "Error finding setting, default accessibility to not found: "
                + e.getMessage());
    }
    TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');

    if (accessibilityEnabled == ACCESSIBILITY_ENABLED) {
        String html" target="_blank">settingValue = Settings.Secure.getString(
                context.getApplicationContext().getContentResolver(),
                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
        if (settingValue != null) {
            mStringColonSplitter.setString(settingValue);
            while (mStringColonSplitter.hasNext()) {
                String accessibilityService = mStringColonSplitter.next();

                if (accessibilityService.equalsIgnoreCase(service)) {
                    return true;
                }
            }
        }
    }

    return false;
}

希望这能有所帮助。

 类似资料:
  • 我刚把Nexus5更新到Android6,直到现在我的应用程序还能正常工作,但现在广播接收器却不工作了。新版本有什么变化吗?这是我试过的在以前的版本上工作的代码,但在Marshmallow中不行- Android清单 同样,PHONE_STATE的广播接收器也不工作。

  • 问题内容: 有人可以解释和之间的确切区别吗? 在什么情况下我们必须使用每个Receiver类? 问题答案: 和之间只有一个区别。 当您收到内部广播方法时, 假设, BroadcastReceiver : 它 不保证 该 CPU将保持清醒 ,如果你启动一些长时间运行的进程。CPU可能会立即回到睡眠状态。 WakefulBroadcastReceiver : 这是 保证 该 CPU将保持清醒 ,直到你

  • 你好,我会开发一个简单的应用程序没有主活动作为启动程序。 弗朗切斯科

  • 本文向大家介绍Android中的广播和广播接收器代码实例,包括了Android中的广播和广播接收器代码实例的使用技巧和注意事项,需要的朋友参考一下 BroadcastReceiver不仅可以接收系统广播,也可接收自定义的广播   1.定义一个广播接收器   2.发送广播,定义好action标志,用Intent发送 3.注册只接收指定action的广播接收器 4.取消该广播接收器

  • (与我刚刚发布的另一个问题略有不同,如果这违反了规则,请道歉) 在我的活动1中,我正在设置一些共享首选项,接下来我将通过意图启动另一个活动2,并从中设置一些文本视图。。。这一切都很好。 这就是我的问题。在我的第一个活动1中,我有一个带有挂起意图的警报管理器,这个挂起意图是一个用于锁定手机的广播接收器,然后启动活动2。这个活动和上面提到的第二个活动是一样的。但是,当此活动从启动时,没有任何文本视图从

  • 问题内容: 我想实现一个侦听器,如果有人从任何应用程序复制了任何东西,它将监听。 我听说有哪个将侦听复制操作,但这不是接收方(据我了解)。我有一个示例应用程序,该应用程序背后的逻辑是,从系统启动启动服务并运行一个服务,该服务将侦听“复制”操作,但是我认为这会耗尽电池。我对吗? 因此,我该如何实现可以监听复制动作的广播接收器。 问题答案: 这是监听器: 只需注册: