17

Mam usługę w tle, która wywołuje GoogleAuthUtl.getTokenWithNotification i działa poprawnie, ale próbuję zaimplementować część wywołania zwrotnego tej funkcji i że nie działa poprawnie.Android GoogleAuthUtil.getTokenWithNotification Intent wywołanie zwrotne nie wyzwala

Zaimplementowałem odbiornik transmisji i dodałem go do manifestu, mam również aktywność w mojej aplikacji. Poniżej znajdują się odpowiednie fragmenty kodu.

GoogleAuthUtil.getTokenWithNotification

GoogleAuthUtil.getTokenWithNotification(this.getContext(), account, "oauth2:" + GmailScopes.GMAIL_SEND, null, new Intent(AuthReceiver.AUTH_INTENT)); 

AuthReceiver

public class AuthReceiver extends BroadcastReceiver 
{ 
    public final static String AUTH_INTENT = "com.testoauth.AUTH_INTENT"; 

    public AuthReceiver() 
    { 
    } 

    @Override 
    public void onReceive(Context context, Intent intent) 
    { 
     Log.d("RECEIVER", "Received Auth broadcast."); 
     NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 
     notificationManager.cancelAll(); 
    } 
} 

AndroidManifest

<receiver android:name=".AuthReceiver" android:enabled="true" android:exported="true"> 
    <intent-filter> 
     <action android:name="com.testoauth.AUTH_INTENT" /> 
    </intent-filter> 
</receiver> 

Nie mam pojęcia, dlaczego nie odbiera transmisji. Nie widzę żadnych wyjątków w dziennikach i nic nie wskazuje na to, że odbiornik został w ogóle wywołany, nawet nie złamie punktu przerwania podczas debugowania. Czy robię coś niepoprawnie?

EDIT

Używam min SDK 16 i docelowy SDK 25

Z dokumentacji GoogleAuthUtil.getTokenWithNotification API:

Metoda ta jest specjalnie przewidziany zadań w tle. W zdarzeniu o błędzie wymagającym interwencji użytkownika ta metoda zajmuje się wysyłania odpowiedniego powiadomienia. Po zgłoszeniu przez użytkownika powiadomienia wywołanie zwrotne jest nadawane. Jeśli użytkownik anuluje to , wywołanie zwrotne nie zostanie uruchomione.

Oddzwonienie nie jest wywoływane, niezależnie od tego, czy użytkownik anulował czy nie. Pomijając ActivityManager, mówiąc, że powiadomienie zostało wyświetlone (Displayed com.google.android.gms/.auth.uiflows.gettoken.GetTokenActivity), nic nie wskazuje na to, że określone intencje transmisji (w tym przypadku com.testoauth.AUTH_INTENT) zostały przesłane w dziennikach. Transmisja "Odebrane uwierzytelnianie". komunikat jest również nieobecny w dziennikach.

Załączony przykład SDK tej funkcji (<android-sdk>/extras/google/google_play_services/samples/auth/gau) nawet nie działa.

+0

Czy znalazłeś rozwiązanie tego problemu? Próbowałem tego samego, ale to też nie działa dla mnie. – Emanuel

+0

@Emanuel Niestety nie, nie mam. – vane

+0

Wystarczy sprawdzić, 'AuthReceiver.AUTH_INTENT =" com.testoauth.AUTH_INTENT ";', prawda? *** /// *** Prawdopodobnie nie są powiązane: nie używaj ukrytych zamiarów, są ograniczenia związane z każdą nową wersją platformy [(Android O teraz)] (https://developer.android.com/preview/features /background.html#broadcasts), a twoja sprawa wcale nie wymaga ukrytego zamiaru. Po prostu stwórz 'new Intent (context, com.package.AuthReceiver.class)'. –

Odpowiedz

0

Nie wydaje się, aby ktokolwiek mógł udzielić prawidłowej odpowiedzi na to pytanie; mnóstwo absolutnie wspaniałych sugestii, jak obejść ten problem, ale nic nie odpowiada na faktyczne pytanie. Doszedłem do wniosku, że musi to być błąd w Androidzie lub Usługach Google Play. Niestety zgłosiłem ten problem zarówno trackerowi problemów z Androidem, jak i forum pomocy usług Google Play ... Obie wskazują palcem na siebie i odmawiają nawet spojrzenia na problem.

1

migracji z GoogleAuthUtil i Plus.API

Jeśli zintegrowany z Google logowania w przeszłości przy użyciu GoogleAuthUtil.getToken lub Plus.API, należy przeprowadzić migrację do najnowszej logowania API dla większego bezpieczeństwa i lepsze wrażenia użytkownika.
Ref: https://developers.google.com/identity/sign-in/android/migration-guide

również sprawdzić to, czy to pomaga

http://www.programcreek.com/java-api-examples/index.php?source_dir=AndroidAppDeployer-master/AndroidAppDeployer/src/com/appjma/appdeployer/service/DownloadService.java

http://www.programcreek.com/java-api-examples/index.php?source_dir=AndroidAppDeployer-master/AndroidAppDeployer/src/com/appjma/appdeployer/receiver/AuthReceiver.java

+0

Te 2 przykłady, których próbowałem wcześniej i one też nie działają. Zaczynam myśleć, że to prawdziwy błąd w Usługach Google Play. Jeśli chodzi o Plus.API, z tego co rozumiem, to jest to, że użytkownik loguje się do google i daje aplikacji dostęp do niektórych aspektów swoich kont, podczas gdy aplikacja, którą próbuję stworzyć, tylko potrzebuje i chce tylko dostępu do wysyłania e-maili i używania GoogleAuthUtil pozwala nam wyświetlać podłączoną aplikację i to, czego potrzebuje dostęp na koncie Google użytkownika. – vane

1

Próbowałem następujących błędów na Android API 25, ale funkcja zwrotna była nigdy nie wywołane:

  • Nie Internet
  • Użytkownik nie zalogował się jeszcze
  • Użytkownik nie wyraził zgody na wysyłanie e-maili na jego/jej imieniu
  • Usługi Google Play jest wyłączona
  • Google Play jest obecnie nieaktualne

Jeżeli metoda callback wezwanie nie jest kluczowa dla przypadku użycia, można śledzić Android Quickstart for Gmail API do wysyłania wiadomości e-mail w imieniu użytkownika w i roid. Sprawdź Sending Email, aby utworzyć wiadomość. Możesz również sprawdzić MyGoogleAuthUtilApplication utworzony przy użyciu powyższych samouczków.

Mam nadzieję, że to pomoże.

+0

Problem z tą metodą polega na tym, że przykład interfejsu Gmail API opiera się na 'MimeMessage', który jest w bibliotece, która nie jest dostępna dla Androida, lub przynajmniej nie jest bardzo jasne, gdzie ta biblioteka jest dla Androida. – vane

+0

Tak, miałem problemy ze znalezieniem biblioteki dla 'MimeMessage'.W końcu "https://mvnrepository.com/artifact/com.sun.mail/android-mail" <- ta biblioteka działała dla mnie. Możesz sprawdzić mój projekt GitHub. – BhalchandraSW

+0

Przetestowałem to i jest to świetne rozwiązanie do wysyłania wiadomości e-mail (do którego będę migrować), ale nadal nie rozwiązuje problemu z oddzwanianiem. Jeśli użyję tego, będę musiał albo mieć przerwane wywołanie zwrotne, albo utworzyć własne powiadomienie i nie używać wbudowanego w Android. – vane

1

Zaimplementowałem demo używam najnowszej wersji auth gradle i jej pracy. Wygląda na to, że może być problem z wersją autoryzacji

public class AuthActivity extends Activity { 


    private static final int AUTHORIZATION_CODE = 1993; 
    private static final int ACCOUNT_CODE = 1601; 

    private AuthPreferences authPreferences; 
    private AccountManager accountManager; 

    /** 
    * change this depending on the scope needed for the things you do in 
    * doCoolAuthenticatedStuff() 
    */ 
    private final String SCOPE = "https://www.googleapis.com/auth/googletalk"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     accountManager = AccountManager.get(this); 

     authPreferences = new AuthPreferences(this); 
     if (authPreferences.getUser() != null 
       && authPreferences.getToken() != null) { 
      doCoolAuthenticatedStuff(); 
     } else { 
      chooseAccount(); 
     } 
    } 

    private void doCoolAuthenticatedStuff() { 
     // TODO: insert cool stuff with authPreferences.getToken() 

     Log.e("AuthApp", authPreferences.getToken()); 
     clickSendEmail(); 
    } 

    private void chooseAccount() { 
     // use https://github.com/frakbot/Android-AccountChooser for 
     // compatibility with older devices 
     Intent intent = AccountManager.newChooseAccountIntent(null, null, 
       new String[] { "com.google" }, false, null, null, null, null); 
     startActivityForResult(intent, ACCOUNT_CODE); 
    } 

    private void requestToken() { 
     Account userAccount = null; 
     String user = authPreferences.getUser(); 
     for (Account account : accountManager.getAccountsByType("com.google")) { 
      if (account.name.equals(user)) { 
       userAccount = account; 
Preferences.setAccount(AuthActivity.this,account.name, account.type); 
       break; 
      } 
     } 

     accountManager.getAuthToken(userAccount, "oauth2:" + SCOPE, null, this, 
       new OnTokenAcquired(), null); 
    } 

    /** 
    * call this method if your token expired, or you want to request a new 
    * token for whatever reason. call requestToken() again afterwards in order 
    * to get a new token. 
    */ 
    private void invalidateToken() { 
     AccountManager accountManager = AccountManager.get(this); 
     accountManager.invalidateAuthToken("com.google", 
       authPreferences.getToken()); 

     authPreferences.setToken(null); 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 

     if (resultCode == RESULT_OK) { 
      if (requestCode == AUTHORIZATION_CODE) { 
       requestToken(); 
      } else if (requestCode == ACCOUNT_CODE) { 
       String accountName = data 
         .getStringExtra(AccountManager.KEY_ACCOUNT_NAME); 
       authPreferences.setUser(accountName); 

       // invalidate old tokens which might be cached. we want a fresh 
       // one, which is guaranteed to work 
       invalidateToken(); 

       requestToken(); 
      } 
     } 
    } 

    private class OnTokenAcquired implements AccountManagerCallback<Bundle> { 

     @Override 
     public void run(AccountManagerFuture<Bundle> result) { 
      try { 
       Bundle bundle = result.getResult(); 

       Intent launch = (Intent) bundle.get(AccountManager.KEY_INTENT); 
       if (launch != null) { 
        startActivityForResult(launch, AUTHORIZATION_CODE); 
       } else { 
        String token = bundle 
          .getString(AccountManager.KEY_AUTHTOKEN); 

        authPreferences.setToken(token); 

        doCoolAuthenticatedStuff(); 
       } 
      } catch (Exception e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } 

    private void clickSendEmail() 
    { 
     final Account account = Preferences.getAccount(this); 
     final String token = Preferences.getToken(this); 

     new Thread(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       try 
       { 

        Session session = Session.getDefaultInstance(new Properties(), null); 

        MimeMessage email = new MimeMessage(session); 

        email.setFrom(new InternetAddress(account.name)); 

        //TODO: change email address to your email address for testing 
        email.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress("[email protected]")); 
        email.setSubject("TEST OAUTH EMAIL"); 
        email.setText("This is a test"); 
        ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 
        email.writeTo(bytes); 
        String encodedEmail = Base64.encodeBase64URLSafeString(bytes.toByteArray()); 
        Message message = new Message(); 
        message.setRaw(encodedEmail); 

        Intent intent = new Intent(AUTH_INTENT); 
        PendingIntent pendingIntent = PendingIntent.getBroadcast(AuthActivity.this, 0, intent, 0); 
        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); 
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 
          , pendingIntent); 
        String test = GoogleAuthUtil.getTokenWithNotification(AuthActivity.this, account, "oauth2:" + GmailScopes.GMAIL_SEND, null, intent); 
        GoogleCredential credential = new GoogleCredential(); 
        credential.setAccessToken(test); 

        boolean changed = false; 
        if (!test.equals(token)) 
        { 
         changed = true; 
         // Snackbar.make(AuthActivity.this.getView(), "TOKEN CHANGED", Snackbar.LENGTH_LONG).show(); 
         Preferences.setToken(AuthActivity.this, test); 
        } 



        Gmail service = new Gmail.Builder(AndroidHttp.newCompatibleTransport(), 
          AndroidJsonFactory.getDefaultInstance(), credential) 
          .setApplicationName("Test OAuth").build(); 

        service.users().messages().send("me", message).execute(); 

        String msg = "Email sent"; 
        if (changed) 
         msg = "TOKEN CHANGED: " + msg; 



       } 
       catch (MessagingException e) 
       { 
        Log.d("ERROR", e.getMessage()); 
       } 
       catch (GoogleJsonResponseException e) 
       { 
        if (e.getDetails().getCode() == 401) 
        { 
         try 
         { 
          Intent intent = new Intent(AUTH_INTENT); 
          GoogleAuthUtil.clearToken(AuthActivity.this, Preferences.getToken(AuthActivity.this)); 
          GoogleAuthUtil.getTokenWithNotification(AuthActivity.this, account, "oauth2:" + GmailScopes.GMAIL_SEND, null, intent); 
         } 
         catch (Exception e1) 
         { 
          //ignore 
         } 
        } 
       } 
       catch (IOException e) 
       { 
        // Snackbar.make(AuthActivity.this.getView(), "ERROR", Snackbar.LENGTH_LONG).show(); 
        Log.d("ERROR", e.getMessage()); 
       } 
       catch (Exception e) 
       { 
        //Snackbar.make(AuthActivity.this.getView(), "ERROR", Snackbar.LENGTH_LONG).show(); 
        Log.d("ERROR", e.getMessage()); 
       } 
      } 
     }).start(); 
    } 
} 
+0

To nie rozwiązuje mojego problemu w żaden sposób. 'AccountManager.getAuthToken' służy tylko do operacji na pierwszym planie. Muszę użyć 'GoogleAuthUtil.getTokenWithNotification', ponieważ jest on wykonywany w usłudze w tle, a także umieszcza powiadomienie na pasku stanu, a getAuthToken nie. – vane

+0

o, teraz jest już za późno. Sprawdzę jutro usługę. Ale mam jedno pytanie, musisz użyć AccountManager tylko 1 raz, aby zdobyć token, wtedy nie ma takiej potrzeby. Czy to nie jest dobre dla ciebie, jeśli bierzesz token z interfejsu użytkownika? Również bez interfejsu użytkownika można wybrać konto? –

+0

Nie, muszę sprawdzić token w usłudze w tle, gdy usługa jest uruchomiona. Ma to na celu umożliwienie użytkownikowi powiadomienia o usunięciu autoryzacji aplikacji ze swoich ustawień konta Google, zanim usługa zostanie wywołana w późniejszym czasie. W przeciwnym razie nie można użyć tokena, ponieważ token nie jest już ważny. – vane

Powiązane problemy