Приложение показывает ожидаемое поведение, если приложение запущено на переднем плане, в фоновом режиме или завершено. Однако после перезагрузки PeriodicTask
перестает работать
Ниже приведены соответствующие фрагменты кода:
In AndroidManifest
:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<service android:name=".tracking.MyTaskService"
android:exported="true"
android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
<intent-filter>
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
</intent-filter>
</service>
Конфигурация PeriodicTask:
PeriodicTask task = new PeriodicTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG_PERIODIC)
.setPeriod(30L)
.setFlex(10L)
.setExtras(bundle)
.setPersisted(true)
.build();
mGcmNetworkManager.schedule(task);
В Logcat я получаю следующее:
E/NetworkScheduler.TED: Couldn't start service: Intent
{ act=com.google.android.gms.gcm.ACTION_TASK_READY
cmp=xxx.xxxxxx.xxx/.tracking.MyTaskService (has extras)
}
Прилагая все соответствующие детали:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.example.gcmnetworkmanagerquickstart">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
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>
<!-- [START manifest_service] -->
<service
android:name=".MyTaskService"
android:exported="true"
android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
<intent-filter>
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
</intent-filter>
</service>
<!-- [END manifest_service] -->
</application>
</manifest>
MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int RC_PLAY_SERVICES = 123;
public static final String TASK_TAG_PERIODIC = "periodic_task";
private GcmNetworkManager mGcmNetworkManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGcmNetworkManager = GcmNetworkManager.getInstance(this);
if(checkPlayServicesAvailable()){
startPeriodicTask();
}
}
public void startPeriodicTask() {
Log.d(TAG, "startPeriodicTask");
PeriodicTask task = new PeriodicTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG_PERIODIC)
.setPeriod(5)
.setPersisted(true)
.build();
mGcmNetworkManager.schedule(task);
}
private boolean checkPlayServicesAvailable() {
GoogleApiAvailability availability = GoogleApiAvailability.getInstance();
int resultCode = availability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (availability.isUserResolvableError(resultCode)) {
// Show dialog to resolve the error.
availability.getErrorDialog(this, resultCode, RC_PLAY_SERVICES).show();
} else {
// Unresolvable error
Toast.makeText(this, "Google Play Services error", Toast.LENGTH_SHORT).show();
}
Log.d(TAG, "Play Services NOT Available");
return false;
} else {
Log.d(TAG, "Play Services Available");
return true;
}
}
}
MyTaskService
public class MyTaskService extends GcmTaskService {
private static final String TAG = "MyTaskService";
@Override
public void onInitializeTasks() {
}
@Override
public int onRunTask(TaskParams taskParams) {
Log.d(TAG, "onRunTask: " + taskParams.getTag());
return doPeriodicTask();
}
private int doPeriodicTask() {
Log.d(TAG, "doPeriodicTask Called");
return GcmNetworkManager.RESULT_SUCCESS;
}
}
build.gradle (модуль приложения)
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.0"
defaultConfig {
applicationId "com.google.example.gcmnetworkmanagerquickstart"
minSdkVersion 14
targetSdkVersion 26
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
allprojects {
repositories {
jcenter()
google()
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
implementation 'com.android.support:appcompat-v7:26.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.7.0'
compile 'com.google.android.gms:play-services-gcm:11.0.2'
}
Edit1: После нескольких дней анализа я выяснил следующее:
- Это проблема конкретного устройства. Например, этого не происходит на устройствах Nexus.
- Это часть более серьезной проблемы. Устройства, демонстрирующие такое поведение, также не работают должным образом с
AlarmManager
,FirebaseJobScheduler
иRECEIVE_BOOT_COMPLETED broadcast receiver
. - Одним из способов обхода проблемы является это решение. Однако у этого решения есть как минимум 2 проблемы. (1) Когда вы убиваете приложение,
AccessibilityService
разрешение сбрасывается. Это означает, что каждый раз, когда вы открываете приложение после этого, вы должны будете давать разрешение вручную. (2) Если приложение убито, перезагрузки после этого не дойдут доRECEIVE_BOOT_COMPLETED broadcast receiver
- Безумный вывод: на устройствах типа «один плюс», если ваше приложение содержит слово
test
в структуре пакета, все работает !! - Если вы внесете свое приложение в белый список, выбрав «Настройки»> «Приложения» (его расположение и имя могут отличаться на разных устройствах), все будет работать должным образом.
- Приложения для запуска, в которые вам нужно вручную добавить свое приложение, содержат хорошо известные приложения, такие как WhatsApp, Facebook, Instagram и многие другие. Когда вы устанавливаете эти приложения, они автоматически добавляются в этот список! Я еще не видел специального API, опубликованного любым из этих производителей для этого. Это заставляет меня думать, что эти приложения внесены в белый список со стороны производителей.