2017-01-16 1 views
2

Ich suche nach Anleitungen zum Zugriff auf Google Drive mit einer Android-App.Android App + Drive API mit Vollzugriff ... Was ist das Verfahren?

1) Ich muss in der Lage sein, Dateien zu lesen, die von Benutzern außerhalb meiner App hochgeladen wurden. Bedeutet das, dass ich Vollzugriff brauche? (Wenn die App einen Ordner erstellen könnte und dann alle vom Benutzer hochgeladenen Dateien in diesem Ordner sehen würde, wäre das großartig, aber ich glaube nicht, dass es so funktioniert.)

2) Wenn ich voll brauche -Drive-Zugriff scheint es, dass Googles "Drive API für Android" dies nicht unterstützt, und ich muss die REST-API verwenden. Ich denke, das ist wahr.

3) Ich brauche eine Auth 2.0 Client ID von Google. Wenn ich die Rest-API verwende, bedeutet das, dass ich eine "Web Application" ID verwenden muss? Ich denke, ich brauche das, weil ich einen "Auth-Code" möchte. Ich konnte es nicht mit einer "Android" -Typ-ID arbeiten.

4) Ich verwende derzeit "Google Sign-In" für Android, um die Anmeldung zu verarbeiten und einen Authentifizierungscode bereitzustellen. Ich kann das dann in ein Token + Refresh Token umwandeln und diese speichern, damit ich neue Token nach einer Stunde auf irgendeine Weise bekommen kann. Ist das manuelle Bearbeiten von Aktualisierungstoken erforderlich?

Es wird hässlich, aber ich denke, dass, da ich (?) Vollen Laufwerkzugriff brauche, dies der Vorgang ist.

Danke für jede Anleitung.

Bearbeiten: Die Frage wurde als ein Duplikat identifiziert. Der angegebene Link gibt eine Antwort auf Frage 2, geht aber nicht auf die anderen Fragen ein.

Ich stimme die Frage ist etwas chaotisch ...

+1

Mögliches Duplikat von [Alle Dateien in Laufwerk auflisten] (http://stackoverflow.com/questions/34253889/list-all-files-in-drive) – Vyacheslav

+0

[Dieses Tool] (https://cloudrail.com/unified -cloud-storage-api /) sollte Ihnen beim Umgang mit der Rest-API auf Android im Allgemeinen helfen und löst das in 4) erwähnte Problem mit dem Aktualisierungstoken. – Tmm

Antwort

3

ich meine eigene Frage zu beantworten.

Ich hatte damit zu kämpfen, weil A) Googles REST-Beispiel einen veralteten Login-Prozess verwendet, B) Das "Anmelden" -Beispiel verwendet Code, der nicht mit "Vollzugriff" funktioniert, und C) die es auch gab viele völlig verschiedene Codebeispiele, wenn man versucht, alles zusammen zu setzen.

Um meine Fragen schnell zu beantworten, wie ich es jetzt sehe: 1) Ja, Vollzugriff ist erforderlich, um Dateien zu lesen, die außerhalb meiner App hochgeladen werden. 2) Ja, ich muss REST API verwenden. 3) Ja, ich brauche eine "Web Application" Client ID. 4) Die Anmeldung bei Google scheint derzeit der beste Weg zur Anmeldung zu sein. Wenn Sie ein GoogleCredential-Objekt zusammen mit dem Drive-API-Objekt verwenden, werden die Token automatisch aktualisiert, solange Sie ein Aktualisierungstoken verwenden.

Falls jemand mit dem Zugriff auf Drive mit vollem Zugriff von Android mit der neuesten "Sign-In" -Prozedur und REST v3 zu kämpfen hat, ist unten mein Beispielcode.

Zusätzlich zur OAuth-Client-ID "Webanwendung" müssen Sie auch eine "Android" -Typ-ID mit einem übereinstimmenden Paketnamen und Zertifikatfingerabdruck erstellen, damit die Anmeldung funktioniert. Beachten Sie auch, dass Sie unterschiedliche Zertifikate für Ihre Entwicklungs- und Produktionsversionen haben. Die IDs/Codes dieser Android-Clients müssen nicht in die App eingegeben werden.

bauen.gradle: app

// Google Sign In 
compile 'com.google.android.gms:play-services-auth:10.0.1' 

// Drive REST API 
compile('com.google.apis:google-api-services-drive:v3-rev54-1.22.0') { 
    exclude group: 'org.apache.httpcomponents' 
} 

Aktivität

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

    // Callback from Signin (Auth.GoogleSignInApi.getSignInIntent) 
    if (requestCode == 1) { 
     GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); 
     _googleApi.handleSignInResult(result); 
    } 
} 

A "GoogleApi" Klasse der Arbeit

import android.app.Activity; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.content.pm.ApplicationInfo; 
import android.os.Bundle; 
import android.os.Handler; 
import android.util.Log; 

import com.google.android.gms.auth.api.Auth; 
import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 
import com.google.android.gms.auth.api.signin.GoogleSignInOptions; 
import com.google.android.gms.auth.api.signin.GoogleSignInResult; 
import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.common.api.ResultCallback; 
import com.google.android.gms.common.api.Scope; 
import com.google.android.gms.common.api.Status; 
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest; 
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; 
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse; 
import com.google.api.client.http.HttpTransport; 
import com.google.api.client.http.javanet.NetHttpTransport; 
import com.google.api.client.json.JsonFactory; 
import com.google.api.client.json.jackson2.JacksonFactory; 
import com.google.api.services.drive.Drive; 
import com.google.api.services.drive.model.File; 
import com.google.api.services.drive.model.FileList; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Locale; 


public class GoogleApi implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { 

    private Context   _context; 
    private Handler   _handler; 
    private GoogleCredential _credential; 
    private Drive   _drive; 

    private GoogleApiClient _googleApiClient;  // only set during login process 
    private Activity  _activity;    // launch intent for login (UI) 

    // Saved to data store 
    private boolean   _loggedIn; 
    private String   _refreshToken;   // store, even if user is logged out as we may need to reuse 


    private static final String ClientID = "xxxxxx.apps.googleusercontent.com"; // web client 
    private static final String ClientSecret = "xxxxx"; // web client 

    private class FileAndErrorMsg { 
     public File file; 
     public String errorMsg; 
     public FileAndErrorMsg (File file_, String errorMsg_) { file = file_; errorMsg = errorMsg_; } 
    } 
    private class FileListAndErrorMsg { 
     public List<File> fileList; 
     public String errorMsg; 
     public FileListAndErrorMsg (List<File> fileList_, String errorMsg_) { fileList = fileList_; errorMsg = errorMsg_; } 
    } 

    // ------------------- 
    // Constructor 
    // ------------------- 


    public GoogleApi (Context context) { 

     _context = context; 
     _handler = new Handler(); 
     loadFromPrefs();  // loggedIn, refreshToken 

     // create credential; will refresh itself automatically (in Drive calls) as long as valid refresh token exists 
     HttpTransport transport = new NetHttpTransport(); 
     JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); 
     _credential = new GoogleCredential.Builder() 
       .setTransport(transport) 
       .setJsonFactory(jsonFactory) 
       .setClientSecrets(ClientID, ClientSecret)  // .addRefreshListener 
       .build(); 
     _credential.setRefreshToken(_refreshToken); 

     // Get app name from Manifest (for Drive builder) 
     ApplicationInfo appInfo = context.getApplicationInfo(); 
     String appName = appInfo.labelRes == 0 ? appInfo.nonLocalizedLabel.toString() : context.getString(appInfo.labelRes); 

     _drive = new Drive.Builder(transport, jsonFactory, _credential).setApplicationName(appName).build(); 
    } 

    // ------------------- 
    // Auth 
    // ------------------- 

    // https://developers.google.com/identity/sign-in/android/offline-access#before_you_begin 
    // https://developers.google.com/identity/sign-in/android/offline-access#enable_server-side_api_access_for_your_app 
    // https://android-developers.googleblog.com/2016/02/using-credentials-between-your-server.html 
    // https://android-developers.googleblog.com/2016/05/improving-security-and-user-experience.html 


    public boolean isLoggedIn() { 
     return _loggedIn; 
    } 

    public void startAuth(Activity activity) { 
     startAuth(activity, false); 
    } 

    public void startAuth(Activity activity, boolean forceRefreshToken) { 

     _activity = activity; 
     _loggedIn = false; 
     saveToPrefs(); 

     GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 
       .requestScopes(new Scope("https://www.googleapis.com/auth/drive")) 
       .requestServerAuthCode(ClientID, forceRefreshToken)  // if force, guaranteed to get back refresh token, but will show "offline access?" if Google already issued refresh token 
       .build(); 

     _googleApiClient = new GoogleApiClient.Builder(activity) 
       .addConnectionCallbacks(this) 
       .addOnConnectionFailedListener(this) 
       .addApi(Auth.GOOGLE_SIGN_IN_API, gso) 
       .build(); 

     _googleApiClient.connect(); 
    } 

    @Override 
    public void onConnected(Bundle connectionHint) { 
     // Called soon after .connect() 
     // This is only called when starting our Login process. Sign Out first so select-account screen shown. (OK if not already signed in) 
     Auth.GoogleSignInApi.signOut(_googleApiClient).setResultCallback(new ResultCallback<Status>() { 
      @Override 
      public void onResult(Status status) { 
       // Start sign in 
       Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(_googleApiClient); 
       _activity.startActivityForResult(signInIntent, 1); // Activity's onActivityResult will use the same code: 1 
      } 
     }); 
    } 

    @Override 
    public void onConnectionSuspended(int cause) { 
     authDone("Connection suspended."); 
    } 
    @Override 
    public void onConnectionFailed(ConnectionResult connectionResult) { authDone("Connection failed."); } 

    public void handleSignInResult(GoogleSignInResult result) { 

     // Callback from Activity > onActivityResult 
     if (result.isSuccess()) { 
      GoogleSignInAccount acct = result.getSignInAccount(); 
      String authCode = acct.getServerAuthCode(); 
      new Thread(new ContinueAuthWithAuthCode_Background(authCode)).start(); 
     } 
     else authDone("Login canceled or unable to connect to Google."); // can we get better error message? 
    } 

    private class ContinueAuthWithAuthCode_Background implements Runnable { 

     String _authCode; 
     public ContinueAuthWithAuthCode_Background (String authCode) { 
      _authCode = authCode; 
     } 
     public void run() { 

      // Convert authCode to tokens 
      GoogleTokenResponse tokenResponse = null; 
      String errorMsg = null; 
      try { 
       tokenResponse = new GoogleAuthorizationCodeTokenRequest(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), "https://www.googleapis.com/oauth2/v4/token", ClientID, ClientSecret, _authCode, "").execute(); 
      } 
      catch (IOException e) { errorMsg = e.getLocalizedMessage(); } 
      final GoogleTokenResponse tokenResponseFinal = tokenResponse; 
      final String errorMsgFinal = errorMsg; 

      _handler.post(new Runnable() { public void run() { 
       // Main thread 
       GoogleTokenResponse tokenResponse = tokenResponseFinal; 
       String errorMsg = errorMsgFinal; 
       if (tokenResponse != null && errorMsg == null) { 
        _credential.setFromTokenResponse(tokenResponse); // this will keep old refresh token if no new one sent 
        _refreshToken = _credential.getRefreshToken(); 
        _loggedIn = true; 
        saveToPrefs(); 
        // FIXME: if our refresh token is bad and we're not getting a new one, how do we deal with this? 
        Log("New refresh token: " + tokenResponse.getRefreshToken()); 
       } 
       else if (errorMsg == null) errorMsg = "Get token error."; // shouldn't get here 
       authDone(errorMsg); 
      } }); 
     } 
    } 

    private void authDone(String errorMsg) { 
     // Disconnect (we only need googleApiClient for login process) 
     if (_googleApiClient != null && _googleApiClient.isConnected()) _googleApiClient.disconnect(); 
     _googleApiClient = null; 
    } 

    /* 
    public void signOut() { 
     Auth.GoogleSignInApi.signOut(_googleApiClient).setResultCallback(new ResultCallback<Status>() { 
      @Override 
      public void onResult(Status status) { 
      } 
     }); 
    } 

    public void revokeAccess() { 
     // FIXME: I don't know yet, but this may revoke access for all android devices 
     Auth.GoogleSignInApi.revokeAccess(_googleApiClient).setResultCallback(new ResultCallback<Status>() { 
      @Override 
      public void onResult(Status status) { 
      } 
     }); 
    } 
    */ 

    public void LogOut() { 
     _loggedIn = false; 
     saveToPrefs();  // don't clear refresh token as we may need again 
    } 


    // ------------------- 
    // API Calls 
    // ------------------- 


    public void makeApiCall() { 
     new Thread(new TestApiCall_Background()).start(); 
    } 

    private class TestApiCall_Background implements Runnable { 
     public void run() { 

      FileAndErrorMsg fileAndErr = getFolderFromName_b("Many Files", null); 
      if (fileAndErr.errorMsg != null) Log("getFolderFromName_b error: " + fileAndErr.errorMsg); 
      else { 
       FileListAndErrorMsg fileListAndErr = getFileListInFolder_b(fileAndErr.file); 
       if (fileListAndErr.errorMsg != null) 
        Log("getFileListInFolder_b error: " + fileListAndErr.errorMsg); 
       else { 
        Log("file count: " + fileListAndErr.fileList.size()); 
        for (File file : fileListAndErr.fileList) { 
         //Log(file.getName()); 
        } 
       } 
      } 

      _handler.post(new Runnable() { public void run() { 
       // Main thread 
      } }); 
     } 
    } 

    private FileAndErrorMsg getFolderFromName_b (String folderName, File parent) { 

     // parent can be null for top level 
     // Working with folders: https://developers.google.com/drive/v3/web/folder 

     File folder = null; 
     folderName = folderName.replace("'", "\\'"); // escape ' 
     String q = String.format(Locale.US, "mimeType='application/vnd.google-apps.folder' and '%s' in parents and name='%s' and trashed=false", parent == null ? "root" : parent.getId(), folderName); 
     String errorMsg = null; 
     try { 
      FileList result = _drive.files().list().setQ(q).setPageSize(1000).execute(); 
      int foundCount = 0; 
      for (File file : result.getFiles()) { 
       foundCount++; 
       folder = file; 
      } 
      if (foundCount == 0) errorMsg = "Folder not found: " + folderName; 
      else if (foundCount > 1) errorMsg = "More than one folder found with name (" + foundCount + "): " + folderName; 
     } 
     catch (IOException e) { errorMsg = e.getLocalizedMessage(); } 
     if (errorMsg != null) folder = null; 
     return new FileAndErrorMsg(folder, errorMsg); 
    } 

    private FileListAndErrorMsg getFileListInFolder_b (File folder) { 

     // folder can be null for top level; does not return subfolder names 
     List<File> fileList = new ArrayList<File>(); 
     String q = String.format(Locale.US, "mimeType != 'application/vnd.google-apps.folder' and '%s' in parents and trashed=false", folder == null ? "root" : folder.getId()); 
     String errorMsg = null; 
     try { 
      String pageToken = null; 
      do { 
       FileList result = _drive.files().list().setQ(q).setPageSize(1000).setPageToken(pageToken).execute(); 
       fileList.addAll(result.getFiles()); 
       pageToken = result.getNextPageToken(); 
      } while (pageToken != null); 
     } 
     catch (IOException e) { errorMsg = e.getLocalizedMessage(); } 
     if (errorMsg != null) fileList = null; 
     return new FileListAndErrorMsg(fileList, errorMsg); 
    } 


    // ------------------- 
    // Misc 
    // ------------------- 

    private void Log(String msg) { 
     Log.v("ept", msg); 
    } 


    // ------------------- 
    // Load/Save Tokens 
    // ------------------- 


    private void loadFromPrefs() { 
     SharedPreferences pref = _context.getSharedPreferences("prefs", Context.MODE_PRIVATE); 
     _loggedIn = pref.getBoolean("GoogleLoggedIn", false); 
     _refreshToken = pref.getString("GoogleRefreshToken", null); 
    } 
    private void saveToPrefs() { 
     SharedPreferences.Editor editor = _context.getSharedPreferences("prefs", Context.MODE_PRIVATE).edit(); 
     editor.putBoolean("GoogleLoggedIn", _loggedIn); 
     editor.putString("GoogleRefreshToken", _refreshToken); 
     editor.apply();  // async 

    } 

} 
+0

Diese Lösung funktioniert wirklich! Mann, du hast meinen Tag gerettet! – mariotaku

+0

Umhüllen Sie einfach alle Android-Tutorial (https://developers.google.com/drive/v3/web/quickstart/android), um die Client-API zu aktivieren, fügen Sie dies zu Ihrer App hinzu. configurations.all { resolutionStrategy.force 'com.google.code.findbugs: jsr305: 1.3.9' } – Sprout

0

das jüngste Beispiel in https://developers.google.com/drive/v3/web/quickstart/android Werken aus der Box zu tun.

tun gerade folgendes:

1 - eine OAuth2 Client-ID mit Ihrem Paketnamen und Debug/Release-Schlüssel als Signing-Zertifikat Fingerabdruck Zur Google API-Konsole und erstellen.

2 - Aktivieren Sie Google Drive API

3 - Wenden Sie den folgenden Code

build.gradle: app

compile 'com.google.android.gms:play-services-auth:10.0.1' 
compile 'pub.devrel:easypermissions:0.2.1' 
compile('com.google.api-client:google-api-client-android:1.22.0') { 
     exclude group: 'org.apache.httpcomponents' 
} 
compile('com.google.apis:google-api-services-drive:v3-rev57-1.22.0') { 
     exclude group: 'org.apache.httpcomponents' 
} 

Aktivität

In diesem Code nur den Umfang ändern DriveScopes .DRIVE für vollen Laufwerkzugriff

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.GoogleApiAvailability; 
import com.google.api.client.extensions.android.http.AndroidHttp; 
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; 
import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException; 
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; 

import com.google.api.client.http.HttpTransport; 
import com.google.api.client.json.JsonFactory; 
import com.google.api.client.json.jackson2.JacksonFactory; 
import com.google.api.client.util.ExponentialBackOff; 

import com.google.api.services.drive.DriveScopes; 

import com.google.api.services.drive.model.*; 

import android.Manifest; 
import android.accounts.AccountManager; 
import android.app.Activity; 
import android.app.Dialog; 
import android.app.ProgressDialog; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.net.ConnectivityManager; 
import android.net.NetworkInfo; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.support.annotation.NonNull; 
import android.text.TextUtils; 
import android.text.method.ScrollingMovementMethod; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Button; 
import android.widget.LinearLayout; 
import android.widget.TextView; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

import pub.devrel.easypermissions.AfterPermissionGranted; 
import pub.devrel.easypermissions.EasyPermissions; 

public class MainActivity extends Activity 
    implements EasyPermissions.PermissionCallbacks { 
    GoogleAccountCredential mCredential; 
    private TextView mOutputText; 
    private Button mCallApiButton; 
    ProgressDialog mProgress; 

    static final int REQUEST_ACCOUNT_PICKER = 1000; 
    static final int REQUEST_AUTHORIZATION = 1001; 
    static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002; 
    static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003; 

    private static final String BUTTON_TEXT = "Call Drive API"; 
    private static final String PREF_ACCOUNT_NAME = "accountName"; 
    private static final String[] SCOPES = { DriveScopes.DRIVE }; 

    /** 
    * Create the main activity. 
    * @param savedInstanceState previously saved instance data. 
    */ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     LinearLayout activityLayout = new LinearLayout(this); 
     LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
       LinearLayout.LayoutParams.MATCH_PARENT, 
       LinearLayout.LayoutParams.MATCH_PARENT); 
     activityLayout.setLayoutParams(lp); 
     activityLayout.setOrientation(LinearLayout.VERTICAL); 
     activityLayout.setPadding(16, 16, 16, 16); 

     ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams(
       ViewGroup.LayoutParams.WRAP_CONTENT, 
       ViewGroup.LayoutParams.WRAP_CONTENT); 

     mCallApiButton = new Button(this); 
     mCallApiButton.setText(BUTTON_TEXT); 
     mCallApiButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       mCallApiButton.setEnabled(false); 
       mOutputText.setText(""); 
       getResultsFromApi(); 
       mCallApiButton.setEnabled(true); 
      } 
     }); 
     activityLayout.addView(mCallApiButton); 

     mOutputText = new TextView(this); 
     mOutputText.setLayoutParams(tlp); 
     mOutputText.setPadding(16, 16, 16, 16); 
     mOutputText.setVerticalScrollBarEnabled(true); 
     mOutputText.setMovementMethod(new ScrollingMovementMethod()); 
     mOutputText.setText(
       "Click the \'" + BUTTON_TEXT +"\' button to test the API."); 
     activityLayout.addView(mOutputText); 

     mProgress = new ProgressDialog(this); 
     mProgress.setMessage("Calling Drive API ..."); 

     setContentView(activityLayout); 

     // Initialize credentials and service object. 
     mCredential = GoogleAccountCredential.usingOAuth2(
       getApplicationContext(), Arrays.asList(SCOPES)) 
       .setBackOff(new ExponentialBackOff()); 
    } 



    /** 
    * Attempt to call the API, after verifying that all the preconditions are 
    * satisfied. The preconditions are: Google Play Services installed, an 
    * account was selected and the device currently has online access. If any 
    * of the preconditions are not satisfied, the app will prompt the user as 
    * appropriate. 
    */ 
    private void getResultsFromApi() { 
     if (! isGooglePlayServicesAvailable()) { 
      acquireGooglePlayServices(); 
     } else if (mCredential.getSelectedAccountName() == null) { 
      chooseAccount(); 
     } else if (! isDeviceOnline()) { 
      mOutputText.setText("No network connection available."); 
     } else { 
      new MakeRequestTask(mCredential).execute(); 
     } 
    } 

    /** 
    * Attempts to set the account used with the API credentials. If an account 
    * name was previously saved it will use that one; otherwise an account 
    * picker dialog will be shown to the user. Note that the setting the 
    * account to use with the credentials object requires the app to have the 
    * GET_ACCOUNTS permission, which is requested here if it is not already 
    * present. The AfterPermissionGranted annotation indicates that this 
    * function will be rerun automatically whenever the GET_ACCOUNTS permission 
    * is granted. 
    */ 
    @AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS) 
    private void chooseAccount() { 
     if (EasyPermissions.hasPermissions(
       this, Manifest.permission.GET_ACCOUNTS)) { 
      String accountName = getPreferences(Context.MODE_PRIVATE) 
        .getString(PREF_ACCOUNT_NAME, null); 
      if (accountName != null) { 
       mCredential.setSelectedAccountName(accountName); 
       getResultsFromApi(); 
      } else { 
       // Start a dialog from which the user can choose an account 
       startActivityForResult(
         mCredential.newChooseAccountIntent(), 
         REQUEST_ACCOUNT_PICKER); 
      } 
     } else { 
      // Request the GET_ACCOUNTS permission via a user dialog 
      EasyPermissions.requestPermissions(
        this, 
        "This app needs to access your Google account (via Contacts).", 
        REQUEST_PERMISSION_GET_ACCOUNTS, 
        Manifest.permission.GET_ACCOUNTS); 
     } 
    } 

    /** 
    * Called when an activity launched here (specifically, AccountPicker 
    * and authorization) exits, giving you the requestCode you started it with, 
    * the resultCode it returned, and any additional data from it. 
    * @param requestCode code indicating which activity result is incoming. 
    * @param resultCode code indicating the result of the incoming 
    *  activity result. 
    * @param data Intent (containing result data) returned by incoming 
    *  activity result. 
    */ 
    @Override 
    protected void onActivityResult(
      int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 
     switch(requestCode) { 
      case REQUEST_GOOGLE_PLAY_SERVICES: 
       if (resultCode != RESULT_OK) { 
        mOutputText.setText(
          "This app requires Google Play Services. Please install " + 
          "Google Play Services on your device and relaunch this app."); 
       } else { 
        getResultsFromApi(); 
       } 
       break; 
      case REQUEST_ACCOUNT_PICKER: 
       if (resultCode == RESULT_OK && data != null && 
         data.getExtras() != null) { 
        String accountName = 
          data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); 
        if (accountName != null) { 
         SharedPreferences settings = 
           getPreferences(Context.MODE_PRIVATE); 
         SharedPreferences.Editor editor = settings.edit(); 
         editor.putString(PREF_ACCOUNT_NAME, accountName); 
         editor.apply(); 
         mCredential.setSelectedAccountName(accountName); 
         getResultsFromApi(); 
        } 
       } 
       break; 
      case REQUEST_AUTHORIZATION: 
       if (resultCode == RESULT_OK) { 
        getResultsFromApi(); 
       } 
       break; 
     } 
    } 

    /** 
    * Respond to requests for permissions at runtime for API 23 and above. 
    * @param requestCode The request code passed in 
    *  requestPermissions(android.app.Activity, String, int, String[]) 
    * @param permissions The requested permissions. Never null. 
    * @param grantResults The grant results for the corresponding permissions 
    *  which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null. 
    */ 
    @Override 
    public void onRequestPermissionsResult(int requestCode, 
              @NonNull String[] permissions, 
              @NonNull int[] grantResults) { 
     super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
     EasyPermissions.onRequestPermissionsResult(
       requestCode, permissions, grantResults, this); 
    } 

    /** 
    * Callback for when a permission is granted using the EasyPermissions 
    * library. 
    * @param requestCode The request code associated with the requested 
    *   permission 
    * @param list The requested permission list. Never null. 
    */ 
    @Override 
    public void onPermissionsGranted(int requestCode, List<String> list) { 
     // Do nothing. 
    } 

    /** 
    * Callback for when a permission is denied using the EasyPermissions 
    * library. 
    * @param requestCode The request code associated with the requested 
    *   permission 
    * @param list The requested permission list. Never null. 
    */ 
    @Override 
    public void onPermissionsDenied(int requestCode, List<String> list) { 
     // Do nothing. 
    } 

    /** 
    * Checks whether the device currently has a network connection. 
    * @return true if the device has a network connection, false otherwise. 
    */ 
    private boolean isDeviceOnline() { 
     ConnectivityManager connMgr = 
       (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
     NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); 
     return (networkInfo != null && networkInfo.isConnected()); 
    } 

    /** 
    * Check that Google Play services APK is installed and up to date. 
    * @return true if Google Play Services is available and up to 
    *  date on this device; false otherwise. 
    */ 
    private boolean isGooglePlayServicesAvailable() { 
     GoogleApiAvailability apiAvailability = 
       GoogleApiAvailability.getInstance(); 
     final int connectionStatusCode = 
       apiAvailability.isGooglePlayServicesAvailable(this); 
     return connectionStatusCode == ConnectionResult.SUCCESS; 
    } 

    /** 
    * Attempt to resolve a missing, out-of-date, invalid or disabled Google 
    * Play Services installation via a user dialog, if possible. 
    */ 
    private void acquireGooglePlayServices() { 
     GoogleApiAvailability apiAvailability = 
       GoogleApiAvailability.getInstance(); 
     final int connectionStatusCode = 
       apiAvailability.isGooglePlayServicesAvailable(this); 
     if (apiAvailability.isUserResolvableError(connectionStatusCode)) { 
      showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode); 
     } 
    } 


    /** 
    * Display an error dialog showing that Google Play Services is missing 
    * or out of date. 
    * @param connectionStatusCode code describing the presence (or lack of) 
    *  Google Play Services on this device. 
    */ 
    void showGooglePlayServicesAvailabilityErrorDialog(
      final int connectionStatusCode) { 
     GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); 
     Dialog dialog = apiAvailability.getErrorDialog(
       MainActivity.this, 
       connectionStatusCode, 
       REQUEST_GOOGLE_PLAY_SERVICES); 
     dialog.show(); 
    } 

    /** 
    * An asynchronous task that handles the Drive API call. 
    * Placing the API calls in their own task ensures the UI stays responsive. 
    */ 
    private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> { 
     private com.google.api.services.drive.Drive mService = null; 
     private Exception mLastError = null; 

     MakeRequestTask(GoogleAccountCredential credential) { 
      HttpTransport transport = AndroidHttp.newCompatibleTransport(); 
      JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); 
      mService = new com.google.api.services.drive.Drive.Builder(
        transport, jsonFactory, credential) 
        .setApplicationName("Drive API Android Quickstart") 
        .build(); 
     } 

     /** 
     * Background task to call Drive API. 
     * @param params no parameters needed for this task. 
     */ 
     @Override 
     protected List<String> doInBackground(Void... params) { 
      try { 
       return getDataFromApi(); 
      } catch (Exception e) { 
       mLastError = e; 
       cancel(true); 
       return null; 
      } 
     } 

     /** 
     * Fetch a list of up to 10 file names and IDs. 
     * @return List of Strings describing files, or an empty list if no files 
     *   found. 
     * @throws IOException 
     */ 
     private List<String> getDataFromApi() throws IOException { 
      // Get a list of up to 10 files. 
      List<String> fileInfo = new ArrayList<String>(); 
      FileList result = mService.files().list() 
       .setPageSize(10) 
       .setFields("nextPageToken, files(id, name)") 
       .execute(); 
      List<File> files = result.getFiles(); 
      if (files != null) { 
       for (File file : files) { 
        fileInfo.add(String.format("%s (%s)\n", 
          file.getName(), file.getId())); 
       } 
      } 
      return fileInfo; 
     } 


     @Override 
     protected void onPreExecute() { 
      mOutputText.setText(""); 
      mProgress.show(); 
     } 

     @Override 
     protected void onPostExecute(List<String> output) { 
      mProgress.hide(); 
      if (output == null || output.size() == 0) { 
       mOutputText.setText("No results returned."); 
      } else { 
       output.add(0, "Data retrieved using the Drive API:"); 
       mOutputText.setText(TextUtils.join("\n", output)); 
      } 
     } 

     @Override 
     protected void onCancelled() { 
      mProgress.hide(); 
      if (mLastError != null) { 
       if (mLastError instanceof GooglePlayServicesAvailabilityIOException) { 
        showGooglePlayServicesAvailabilityErrorDialog(
          ((GooglePlayServicesAvailabilityIOException) mLastError) 
            .getConnectionStatusCode()); 
       } else if (mLastError instanceof UserRecoverableAuthIOException) { 
        startActivityForResult(
          ((UserRecoverableAuthIOException) mLastError).getIntent(), 
          MainActivity.REQUEST_AUTHORIZATION); 
       } else { 
        mOutputText.setText("The following error occurred:\n" 
          + mLastError.getMessage()); 
       } 
      } else { 
       mOutputText.setText("Request cancelled."); 
      } 
     } 
    } 
} 
+1

Meine Sorge mit dieser Methode war, dass es scheint, die GET_ACCOUNTS-Berechtigung, die sie in den Beispielcode dafür enthalten Seite. Von der untenstehenden Webseite scheint Google dies jetzt zu entmutigen. https://android-developers.googleblog.com/2016/05/improving-security-and-user-experience.html "Das Schlimmste ist die Berechtigung GET_ACCOUNTS. Auf Marshmallow und darüber wird diese Berechtigung dem Benutzer angezeigt als 'Kontakte'. Viele Benutzer sind nicht bereit, Zugriff auf diese Laufzeitberechtigung zu gewähren. Lösung: Wechseln Sie zu unserer neuen Auth.GOOGLE_SIGN_IN_API. " –

+0

@ErnieThomason Ich war mir dessen nicht bewusst, trotzdem werde ich darauf warten, dass ihre Dokumentation mit GOOGLE_SIGN_IN_API aktualisiert wird, da ich die Implementierung auf meinem Gerät nicht korrekt ausführen konnte – Steve

Verwandte Themen