Подтвердить что ты не робот

GCMNetworkManager не запускает PeriodicTask после перезагрузки

Приложение показывает ожидаемое поведение, если приложение работает на переднем плане, в фоновом режиме или убито. Однако после перезагрузки PeriodicTask перестает работать

Ниже приведены соответствующие биты кода:

В 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 config:

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: После нескольких дней анализа я выяснил следующее:

  • Это проблема, связанная с устройством. Например, не происходит на устройствах связи.
  • Это часть более крупной проблемы. Устройства, демонстрирующие это поведение, также не работают с AlarmManager, FirebaseJobScheduler и RECEIVE_BOOT_COMPLETED broadcast receiver.
  • Обходным решением является это решение. Однако это решение имеет как минимум 2 проблемы. (1) Когда вы убиваете приложение, разрешение AccessibilityService reset. Это означает, что каждый раз, когда вы открываете приложение после этого, нужно дать разрешение вручную. (2) Если приложение убито, перезагрузка после этого не ударит по RECEIVE_BOOT_COMPLETED broadcast receiver
  • Сумасшедший поиск: в устройствах с одним плюсом, если ваше приложение имеет слово test в структуре пакета, все работает!!
  • Если вы настроите белый список приложений на настройки > Приложения (расположение и имя этого могут отличаться на разных устройствах), все работает так, как ожидалось.
  • Запуск приложений, к которым вы должны вручную добавить свое приложение, содержит известные приложения, такие как WhatsApp, Facebook, Instagram и многие другие. Когда вы устанавливаете эти приложения, они автоматически добавляются в этот список! Я еще не видел пользовательский API, опубликованный любым из этих производителей для этого. Это заставляет меня думать, что эти приложения белые, перечисленные со стороны производителей.
4b9b3361

Ответ 1

Update: Найдено Не исправить ошибку (неизученный), которая может быть связана с темой. Похоже, что поведение службы доступности несовместимо между устройствами. Некоторые из них отключат службу, некоторые из них возобновятся и т.д. Это соответствует жалобам пользователей, найденным в Интернете, и с вашими наблюдениями хорошо.

Лучший совет, который я могу дать, - сделать сервис как можно более минимальным для другого процесса (чтобы он не был убит при отключении приложения), а также при загрузке, если он включен, а если нет - используйте систему уведомлений, чтобы обеспечить быстрый доступ к экрану настроек Android для удобства.


Я не знаком с конкретной проблемой, но я считаю, что это решение будет работать для вас. Я использую этот код для AlarmManager в производстве.

В AndroidManifest.xml:

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

    <receiver android:name=".BootListener">
        <intent-filter>
            <category android:name="android.intent.category.DEFAULT"/>

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

И создайте класс

public class BootListener extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      // If your bootstrap is in Application class, then it will be called anyway - nothing to do here.
      // else - call your bootsrap here
    }
}

Я считаю, что

(2) Если приложение убито, перезагрузка после этого не ударит RECEIVE_BOOT_COMPLETED широковещательный приемник

Неправильно, при перезагрузке Android не знает, что ваше приложение было убито. Это никогда не было проблемой для моего приложения (+ 1.2M пользователей).

Ответ 2

Конфигурация PeriodicTask:

PeriodicTask task = new PeriodicTask.Builder()
                .setService(MyTaskService.class)
                .setTag(TASK_TAG_PERIODIC)
                .setPeriod(30L)
                .setFlex(10L)
                .setExtras(bundle) **/* you put this line here */**
                .setPersisted(true)
                .build();


    PeriodicTask task = new PeriodicTask.Builder()
                    .setService(MyTaskService.class)
                    .setTag(TASK_TAG_PERIODIC)
/* you don't have ".setExtras(bundle)" line here */ 
/* try adding this line from above, as logcat is showing this */
                    .setPeriod(5)
                    .setPersisted(true)
                    .build();