Android8.0 靜態(tài)receiver接收不到隱式廣播

1.前言

Android8.0的新特性值得注意一下,不然會出現(xiàn)很多莫名的問題。。。

2.后臺執(zhí)行限制

Android 8.0 為提高電池續(xù)航時(shí)間而引入的變更之一是,當(dāng)您的應(yīng)用進(jìn)入已緩存狀態(tài)時(shí),如果沒有活動的組件,系統(tǒng)將解除應(yīng)用具有的所有喚醒鎖。

此外,為提高設(shè)備性能,系統(tǒng)會限制未在前臺運(yùn)行的應(yīng)用的某些行為。具體而言:

  • 現(xiàn)在,在后臺運(yùn)行的應(yīng)用對后臺服務(wù)的訪問受到限制。
  • 應(yīng)用無法使用其清單注冊大部分隱式廣播(即,并非專門針對此應(yīng)用的廣播)。
    默認(rèn)情況下,這些限制僅適用于針對 O 的應(yīng)用。不過,用戶可以從 Settings 屏幕為任意應(yīng)用啟用這些限制,即使應(yīng)用并不是以 O 為目標(biāo)平臺。

Android 8.0 還對特定函數(shù)做出了以下變更:

如果針對 Android 8.0 的應(yīng)用嘗試在不允許其創(chuàng)建后臺服務(wù)的情況下使用 startService() 函數(shù),則該函數(shù)將引發(fā)一個(gè) IllegalStateException。
新的 Context.startForegroundService() 函數(shù)將啟動一個(gè)前臺服務(wù)。現(xiàn)在,即使應(yīng)用在后臺運(yùn)行,系統(tǒng)也允許其調(diào)用 Context.startForegroundService()。不過,應(yīng)用必須在創(chuàng)建服務(wù)后的五秒內(nèi)調(diào)用該服務(wù)的 startForeground() 函數(shù)。

以下這個(gè)就是Android8.0的后臺限制新特性導(dǎo)致的.

自己編寫了一個(gè)demo跟蹤廣播的發(fā)送流程。

demo:注冊一個(gè)靜態(tài)receiver,然后發(fā)送廣播。

Activity中發(fā)送廣播的代碼:


public class MainActivity extends Activity {
    public static final String TAG = "TEST";
    public final String TEST_ACTION = "com.test.TEST_ACTION";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG,"onResume");
        Log.d(TAG,">>sendBroadcast");
        Intent intent = new Intent(TEST_ACTION);
        sendBroadcast(intent);
        Log.d(TAG,"<<sendBroadcast");
    }
 
    private BroadcastReceiver mTestReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            Log.d(TAG,"Dynamic receiver:action="+action);
        }
    };
 
}

AndroidManifest.xml中注冊靜態(tài)receiver:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.atc6111.testswitchicon">
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
 
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
 
        <receiver android:name=".MyTestReceiver">
            <intent-filter>
                <action android:name="com.test.TEST_ACTION"/>
            </intent-filter>
        </receiver>
    </application>
 
</manifest>

Receiver對應(yīng)的java文件:

public class MyTestReceiver extends BroadcastReceiver {
    private final String TAG = "TEST-MyTestReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG,"Static receiver:action=" + intent.getAction());
    }
}

運(yùn)行這個(gè)demo。發(fā)現(xiàn)這個(gè)receiver一直都沒有收到廣播。。。。
查看log,發(fā)現(xiàn)了waring信息:

W BroadcastQueue: Background execution not allowed: receiving Intent { act=com.test.TEST_ACTION flg=0x10 } to com.example.atc6111.testswitchicon/.MyTestReceiver

"Background execution not allowed" 打印出該warning的代碼:


image.png

即是以下兩種情況靜態(tài)receiver不會接收到廣播:

1.發(fā)送的intent設(shè)置了FLAG --FLAG_RECEIVER_EXCLUDE_BACKGROUND;
2.以下情況的均滿足時(shí):
①intent沒有指定接收組件,也就是沒有setComponent
②intent沒有執(zhí)行接收的package,也就是沒有setPackage
③發(fā)送的intent沒有設(shè)置FLAG-FLAG_RECEIVER_INCLUDE_BACKGROUND
④給定的權(quán)限并不都是簽名權(quán)限。
根據(jù)這兩種情況,即是說靜態(tài)receiver接收不了隱式廣播。本來打算采用最簡單的方法添加Flag來解決的。

但是奇怪的是,Android Studio里沒有FLAG_RECEIVER_INCLUDE_BACKGROUND!!!!

然后,只好在發(fā)送intent的時(shí)候setPackage。

@Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG,"onResume");
        Log.d(TAG,">>sendBroadcast");
        Intent intent = new Intent(TEST_ACTION);
        intent.setPackage(getPackageName());
        sendBroadcast(intent);
        Log.d(TAG,"<<sendBroadcast");
    }

修改之后,靜態(tài)Receiver就能收到廣播了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。