【发布时间】:2017-05-22 07:45:49
【问题描述】:
我已经检查了所有相关问题,但没有找到任何解决此问题的方法。所以这对我来说是一个全新的问题。
我有什么
我有一个 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 (Nougat)、Nexus 6P (Nougat)、YU Yuphoria (Lollipop) 上工作正常,但在我的 OnePlus 3 (Nougat) 和 Mi 4i 上却不行(棒棒糖)。
相同的代码如何在少数设备上完美运行,而在其他设备上完全无法运行?我根本没有改变任何东西。
我在这里做错了什么?我的应用程序严重依赖这些广播并基于这些广播启动服务。任何帮助将不胜感激。
编辑 1
为了更好地理解这个问题,我刚刚创建了一个非常小的测试项目,只有一个活动和完全相同的BootCompleteReceiver 和PhoneCallReceiver。
但奇怪的是,这个项目在我的 OnePlus 3 上完美运行,我的实际应用程序的接收器在重新启动后无法工作。我最初假设问题出在操作系统或设备上,但事实并非如此。
那么真正的问题在哪里?它是在我的应用中(但它在其他设备上运行良好)还是在操作系统和设备中(小型测试项目在同一操作系统和同一设备上运行良好)?
这真的让我很困惑。我需要一些专家的帮助。
编辑 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)
可能是因为我的设备没有植根。我无法以任何方式发送此广播。
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 发送广播不起作用,但实际上打开拨号器并拨打了一个号码。
编辑 3
根据@ChaitanyaAtkuri 的建议,我也尝试为意图过滤器添加优先级,但效果不佳。
我使用了诸如 500、999 甚至最高整数值之类的优先级,但没有任何效果。这个问题也出现在我的一些朋友应用程序中。它们适用于某些设备,但不适用于其他设备。
编辑 4
我终于找到了我的 OnePlus 3 出现问题的根本原因。我的 OnePlus 3 最近更新为 Nougat,他们引入了类似于 Mi 设备的功能,可以防止某些应用在重启后自动启动。
禁用此功能后,我的应用程序在完美重启后开始接收广播。但这仍然不能解释两件事。
1) 我的小型测试项目在 AutoLaunch 应用程序列表中自动列入白名单,这就是它按预期工作的原因。但这怎么可能?为什么操作系统认为这个小应用值得自动启动?
2) 有一些应用程序,如 LockDown Pro、500 Firepaper,它们在 AutoLaunch 应用程序屏幕中被列入黑名单,但在我的 OnePlus 3 和 Mi 4i 重新启动后,它仍然会接收广播。现在怎么可能?是否有可能以编程方式允许我的应用在这些设备(OnePlus 和 Mi)中自动启动?
编辑 5
我已经尝试过@Rahul Chowdhury 提出的解决方案,它似乎真的很有效。添加无障碍服务后问题得到解决。
但如果用户在授予访问权限后撤销了访问权限,那么我有没有办法以编程方式检查访问权限是否可用于我的应用程序?
【问题讨论】:
-
尝试将这些添加到清单声明中:
android:enabled="true"和android:exported="true"。同样在启动接收器类中,删除intent.getAction条件,因为没有理由检查它,因为广播将被触发的唯一时间是在启动时。 -
我刚试过你的建议,结果还是一样。实际上,这些可以被视为最佳实践,不会以任何方式改变实施。
-
不同的路径。也许它确实有效,但你没有看到吐司。也许它失败了,而你没有看到它失败。更改代码以保存您以后可以检测到的内容。记住广播接收器会在 10 秒内完成,否则应用会失败。
-
我没有测试过一次,把这个问题放在这里。经过几次测试,我可以确认这些接收器在上述某些设备中重新启动后无法正常工作。正如您所提到的,我如何检测它是否失败?
-
接受的答案解决了我所面临的实际问题并得到了解决。谢谢。
标签: android broadcastreceiver android-broadcast android-broadcastreceiver