13

Ta aplikacja wyświetla oczekiwane zachowanie, jeśli aplikacja działa na pierwszym planie, w tle lub jest uśmiercana. Jednak, gdy jest on uruchomiony ponownie na PeriodicTask zatrzymaGCMNetworkManager nie uruchamia funkcji Okresowo po ponownym uruchomieniu komputera

Poniżej znajdują się odpowiednie fragmenty kodu:

W 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); 

W logcat , Otrzymuję następujące:

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) 
} 

Dołączanie wszystkie istotne szczegóły:

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> 

główną działalność

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 (App Module)

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: Po kilku dniach analizy, mam zorientowali się, co następuje:

  1. Jest to specyficzny problem urządzenie. Nie dzieje się na przykład na urządzeniach Nexus.
  2. Jest to część większego problemu. Urządzenia wyświetlające to zachowanie również nie działają zgodnie z oczekiwaniami z AlarmManager, i RECEIVE_BOOT_COMPLETED broadcast receiver.
  3. Jedno obejście to this solution. Jednak to rozwiązanie ma co najmniej 2 problemy. (1) Po zabiciu aplikacji, uprawnienie AccessibilityService jest resetowane. Oznacza to, że za każdym razem, gdy otworzysz aplikację po tym czasie, otrzymasz ręczne pozwolenie. (2) Jeśli aplikacja zostanie zabita, ponowne jej uruchomienie nie będzie miało wpływu na szybkie wyszukiwanie: w urządzeniach z jednym plusem, jeśli twoja aplikacja ma w strukturze pakietu słowo "test", wszystko działa!
  4. Jeśli dodasz aplikację do białej listy, przechodząc do ustawień> Aplikacje (lokalizacja i nazwa może być różna na różnych urządzeniach), wszystko działa zgodnie z oczekiwaniami.
  5. Uruchomione aplikacje, do których musisz ręcznie dodać aplikację, zawierają dobrze znane aplikacje, takie jak WhatsApp, Facebook, Instagram i wiele innych. Po zainstalowaniu tych aplikacji zostaną automatycznie dodane do tej listy! Nie widzę jeszcze niestandardowego interfejsu API opublikowanego przez żadnego z tych producentów. To sprawia, że ​​myślę, że te aplikacje są białe wymienione od końca producentów.
+0

Podczas przeglądania dzienników natknąłem się na fakt, że własna aplikacja Google dla Youtube dla dzieci ma ten sam problem: ** E/NetworkScheduler.TED: Nie można uruchomić usługi: Intent {act = com.google.android. gms.gcm.ACTION_TASK_READY cmp = com.google.android.apps.youtube.kids/com.google.android.libraries.youtube.common.gcore.gcoreclient.gcm.impl.GcmTaskServiceDelegator (ma dodatki)} ** – ranjjose

+1

robi to dzieje się na wielu urządzeniach? – user2450263

+0

Tak ... zdarza się to na wielu urządzeniach. Doświadczyłem tego na jednym plusie urządzeń MI. – ranjjose

Odpowiedz

0

PeriodicTask config:

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(); 
+0

Dzięki za zwrócenie na to uwagi. Jednak nie o to chodzi. Przypuszczam, że po skopiowaniu wkleiłem niewłaściwy plik. Problem jest związany z urządzeniem. Na przykład w urządzeniach oneplus i MI te problemy się zdarzają. To też jest niespójne. W rzeczywistości w oneplus (3T), jeśli masz słowo "test" w pakiecie boot_completed to trafienie !! W MI nic nie działa. Na razie dostałem pracę z usługami dostępności, o których tutaj wspomniano: https://stackoverflow.com/a/41627296/1349159 – ranjjose

+1

Tak, to bardzo specyficzne przypadki urządzeń. Wielu producentów tworzy smak Androida i posiada własną warstwę zabezpieczającą, która zatrzymuje usługę z powrotem do usługi aplikacji tak długo, aż użytkownik nie wyda pozwolenia na wyłączność. Powieliliśmy to zachowanie w telefonach Xiomi w naszym rozwoju. W takim przypadku musisz podać użytkownikowi jakiś dokument pomocy. – Devesh

2

Aktualizacja: Znaleziono Won't Fix (Infeasible) bug, które mogą być związane z tematem. Wygląda na to, że zachowanie usługi dostępności nie jest spójne na różnych urządzeniach. Niektóre z nich wyłączy usługę, niektóre zostaną wznowione itd. Pasuje do skarg użytkowników znalezionych w Internecie oraz do obserwacji.

Najlepszą radą, jaką mogę dać, jest uczynienie usługi możliwie minimalną w innym procesie (więc nie zostanie ona zabita po zabiciu aplikacji), a także po sprawdzeniu, czy jest włączona, i czy nie - użyj systemu powiadomień, aby umożliwić szybki dostęp do ekranu ustawień Android Accessibility, dla łatwego włączania.

Nie jestem zaznajomiony z konkretnym problemem, ale uważam, że to rozwiązanie będzie dla ciebie skuteczne. Używam tego kodu do obsługi programu AlarmManager.

W 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> 

I utworzyć klasę

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 
    } 
} 

wierzę, że

(2) Jeśli aplikacja zostanie zabity, restartuje po który wygrał” t hit odbiornik transmisji RECEIVE_BOOT_COMPLETED

Niepoprawnie, po ponownym uruchomieniu system Android nie ma wiedzy o tym, że aplikacja została zabita. To nigdy nie było problemem dla mojej aplikacji (+ 1,2 mln użytkowników).

+0

Dzięki auval. Próbowałem już z filtrem 'android.intent.category.DEFAULT'. Niestety, nie działało ono na trzy do czterech urządzeń testowych (jeden plus 3T, MI, redmi). Problem związany z ponownym uruchomieniem po awarii aplikacji dotyczy "usługi dostępności" – ranjjose

+0

Nie widziałem programu BroadcastReceiver w opublikowanym przez Ciebie kodzie. – auval

+0

Również to, co przeczytałem na temat 'accessibility service' jest to, że kiedy zabijasz aplikację, resetuje ona uprawnienia dostępu do usługi – ranjjose