我已经检查了所有相关问题,但没有找到解决此问题的方法。所以这对我来说绝对是一个新问题。
我拥有的
我有一个 Android 应用程序,它在其清单中注册了一些广播接收器。这就是我的清单的样子。
<?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>
还有 10-15 个其他活动,但为了简单起见已被删除。这是基本的引导接收器类。我从这里开始服务。
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
}
}
}
问题
当我安装应用程序并启动一次时,所有这些接收器都工作正常。但在我重新启动设备后,这些接收器根本无法工作。既没有BootCompleteReceiver
也不PhoneCallReceiver
得到他们的onReceive()
方法调用。
我的假设是这些接收器会在重新启动后自动注册,但它就是不起作用。我需要BootCompleteReceiver
以便我可以在我的应用程序中启动一项重要服务。
我的观察
我对此进行了彻底的测试。重新启动设备后,接收器在我的设备中工作正常Nexus 5X(牛轧糖)、Nexus 6P(牛轧糖)、YU Yuphoria(棒棒糖)但不在我的OnePlus 3(牛轧糖)和 Mi 4i(棒棒糖).
相同的代码如何在少数设备上完美运行,而在其他设备上根本不起作用?我根本没有改变任何事情。
我在这里做错了什么?我的应用程序严重依赖于这些广播并基于这些广播启动服务。任何帮助将不胜感激。
EDIT 1
为了更好地理解问题,我刚刚创建了一个非常小的测试项目,其中只有一个活动并且完全相同BootCompleteReceiver
and PhoneCallReceiver
.
但奇怪的是,这个项目在我的 OnePlus 3 上完美运行,而我的实际应用程序的接收器在重新启动后无法工作。我最初假设问题出在操作系统或设备上,但事实并非如此。
那么实际问题出在哪里呢?它是在我的应用程序中(但它在其他设备上完美运行)还是在操作系统和设备中(小型测试项目在相同操作系统和相同设备上运行良好)?
这真的让我很困惑。我需要一些专家的帮助。
EDIT 2
我已经尝试过@shadygoneinsane 给出的建议。以下是我的观察。
1)我尝试通过ADB发送BOOT_COMPLETED广播。
./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)
可能是因为我的设备没有root。我无法以任何方式发送此广播。
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
看起来广播成功了,但是我没有看到任何Toast或任何日志。然后我打开拨号器拨打一个号码,然后我可以看到 Toast 和日志。
所以看来通过ADB发送广播不起作用,但实际上打开拨号器并拨打了一个号码。
EDIT 3
根据@ChaitanyaAtkuri 的建议,我还尝试为意图过滤器添加优先级,但这效果不佳。
我使用过 500、999 甚至最高整数值等优先级,但没有任何效果。我的一些朋友的应用程序也出现了这个问题。它们在某些设备上工作,但在其他设备上不起作用。
EDIT 4
I have 终于找到了我的 OnePlus 3 出现问题的根本原因。我的 OnePlus 3 最近更新为 Nougat,他们引入了类似于 Mi 设备的功能,可防止某些应用程序在重新启动后自动启动。
禁用此功能后,我的应用程序在完美重启后开始接收广播。但这仍然不能解释两件事。
1)我的小测试项目自动列入自动启动应用程序列表中的白名单,这就是它按预期工作的原因。但这怎么可能呢?为什么操作系统认为这个小应用程序值得自动启动?
2) 有一些应用程序,如 LockDown Pro、500 Firepaper,在自动启动应用程序屏幕中被列入黑名单,但在我的 OnePlus 3 和 Mi 4i 中重新启动后仍然会收到广播。现在怎么可能?是否可以以某种方式以编程方式允许我的应用程序在这些设备(OnePlus 和 Mi)中自动启动?
EDIT 5
我已经尝试过@Rahul Chowdhury 提出的解决方案,它看起来确实效果很好。添加辅助服务后,问题重新解决。
但是,如果用户在授予可访问性权限后撤销它,那么我是否可以通过编程方式检查可访问性权限是否可用于我的应用程序?