List files from Google Drive and get downloadUrl for selected file in Android

霸气de小男生 提交于 2019-12-21 21:38:29

问题


I am trying to show a list of files the user has on their Google Drive from my Android app and once the user has selected a file, I want to get the downloadUrl and the Bearer token for that account to give it to my application server to download it.

I have been looking around and it seems very confusing. There are 2 SDKs, Android SDK and Java SDK (REST based) for Google Drive.

I successfully was able to get the list of files and display it using the Android SDK (I did not have to build any UI), and when the user selects a file, I got all the metadata about the file but the downloadUrl. I did get some links like the webContentLink and the alternateLink, but it turns out that because the file was not shared, I cannot pass these links to my server to download it.

Upon some more research I found out that the downloadUrl is accessible by using the Java SDK. My question is, do I have to build my own UI to display a list of files I obtain? How do I handle the folder hierarchy if I have to build my UI to show these files?

Below is the code which prints the data about the File. I have implemented this code based on the tutorial.

public class GoogleDriveActivity extends Activity {

private GoogleApiClient mGoogleApiClient;
public com.google.api.services.drive.Drive mService;
public GoogleAccountCredential credential;
public static final int REQUEST_AUTHORIZATION = 3;
public static final int REQUEST_ACCOUNT_PICKER = 4;

private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = {DriveScopes.DRIVE_METADATA_READONLY};
final HttpTransport transport = AndroidHttp.newCompatibleTransport();
final JsonFactory jsonFactory = GsonFactory.getDefaultInstance();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_google_drive);

    SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
    credential = GoogleAccountCredential.usingOAuth2(
            getApplicationContext(), Arrays.asList(SCOPES))
            .setBackOff(new ExponentialBackOff())
            .setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, "abc.test@gmail.com"));

    mService = new com.google.api.services.drive.Drive.Builder(
            transport, jsonFactory, credential)
            .setApplicationName("My Application")
            .build();
}

@Override
public void onResume() {
    super.onResume();
    refreshResults();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case REQUEST_AUTHORIZATION:
            if (resultCode != RESULT_OK) {
                chooseAccount();
            }
            break;
        case REQUEST_ACCOUNT_PICKER:
            Log.w("gd", "in account picker");
            if (resultCode == RESULT_OK && data != null &&
                    data.getExtras() != null) {
                String accountName =
                        data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
                if (accountName != null) {
                    credential.setSelectedAccountName(accountName);
                    SharedPreferences settings =
                            getPreferences(Context.MODE_PRIVATE);
                    SharedPreferences.Editor editor = settings.edit();
                    editor.putString(PREF_ACCOUNT_NAME, accountName);
                    editor.commit();
                }
            } else if (resultCode == RESULT_CANCELED) {
                Log.W("gd", "in cancelled");
            }
            break;

        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    }
}

private void chooseAccount() {
    startActivityForResult(
            credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
}

private void refreshResults() {
    new GoogleDriveAsync(this).execute();
}

public class GoogleDriveAsync extends AsyncTask<Void, Void, Void> {

    private GoogleDriveActivity activity;

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            getDataFromApi();

        } catch (final GooglePlayServicesAvailabilityIOException availabilityException) {
            Log.w("gd", "GPS unavailable");

        } catch (UserRecoverableAuthIOException userRecoverableException) {
            Log.w("gd", "user recoverable");
            activity.startActivityForResult(
                    userRecoverableException.getIntent(),
                    GoogleDriveActivity.REQUEST_AUTHORIZATION);

        } catch (Exception e) {
            Log.w("gd", "general exception " + e.getMessage());
        }
        return null;
    }

    GoogleDriveAsync(GoogleDriveActivity activity) {
        this.activity = activity;
    }

    /**
     * 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 = activity.mService.files().list()
                .setMaxResults(10)
                .execute();
        List<File> files = result.getItems();
        if (files != null) {
            for (File file : files) {
                fileInfo.add(String.format("%s (%s) (%s)\n",
                        file.getTitle(), file.getId(), file.getDownloadUrl()));
            }
        }
        Log.w("gd", "file info is " + fileInfo.toString());
        return fileInfo;

    }
}
}

EDIT: Please see my answer (not the accepted one) for a working sample. The use case is: list all the Google Drive files for the user and when selected one, get the downloadUrl and the access_token for the file.


回答1:


In order to use the file/folder outside of your GDAA based app, you need so-called ResourceID. This ResourceId is a string that uniquely identifies the object of Google Drive (see here)

Turn DriveId into ResourceId:

        DriveId driveId = metadata.getDriveId();
        String resourceId = driveId.getResourceId();

Once you have ResourceId, you can construct 'download URL' for your server app from it. The ResourceID string is the one found if you go to drive.google.com, select a file/folder and perform rightbutton > getLink.
(looks like 'https://drive.google.com/open?id=0B1mQUW2__I_am_the_resource_id')

Just take this string '0B1mQUW2__I_am_the_resource_id' to the 'TryIt' playground here and paste it to the 'fileId' field.

So, the short answer is that you don't need RESTful Api to get the file/folder identifier you can use elsewhere.

Second part of your question, 'How do I handle the folder hierarchy if I have to build my UI to show these files?' is answered (somewhat) in the 'createTree()/testTree()' methods of MainActivity of these 2 demos (GDAADemo, RESTDemo). These are the same tasks implemented on the GDAA as well as the REST Apis and the choice depends mainly on the SCOPE your app needs (GDAA supports only the FILE scope, whereas REST supports both the FILE and the DRIVE scopes)

Good Luck




回答2:


The Activity:

public class GoogleDriveActivity extends Activity implements
GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {

private GoogleApiClient mGoogleApiClient;
final HttpTransport transport = AndroidHttp.newCompatibleTransport();
final JsonFactory jsonFactory = GsonFactory.getDefaultInstance();

public static final int REQUEST_CODE_RESOLUTION = 1;
public static final int REQUEST_CODE_SELECT = 2;

private static final String[] SCOPES = { DriveScopes.DRIVE_FILE};
private static final String TAG = "GoogleDrive";
private String accountName;


@Override
protected void onResume() {
    super.onResume();
    setupGoogleClient();
}


@Override
protected void onPause() {
    super.onPause();
    if (mGoogleApiClient != null) {
        mGoogleApiClient.disconnect();
    }
}

@Override
public void onConnected(Bundle bundle) {
    IntentSender intentSender = Drive.DriveApi
            .newOpenFileActivityBuilder()
            .build(mGoogleApiClient);

    AccountManager manager = (AccountManager) getSystemService(ACCOUNT_SERVICE);
    Account[] list = manager.getAccountsByType("com.google");
    //Getting the first account because that is the primary account for that user
    accountName = list[0].name;

    try {
        startIntentSenderForResult(intentSender, REQUEST_CODE_SELECT, null, 0, 0, 0);
    } catch (IntentSender.SendIntentException e) {
        Log.w(TAG, "Unable to send intent to connect to Google API client " + e.getMessage());
    }

}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    if (!connectionResult.hasResolution()) {
        return;
    }
    try {
        connectionResult.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
    } catch (IntentSender.SendIntentException e) {
        Log.w(TAG, "Unable to send intent to connect to Google API client " + e.getMessage());
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case REQUEST_CODE_SELECT:
            if (resultCode == RESULT_OK) {
                DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);
                String resourceId = driveId.getResourceId();
                new GoogleDriveAsync(this).execute(resourceId);
            }
            finish();
            break;
        case REQUEST_CODE_RESOLUTION:
            if (resultCode == RESULT_OK) {
                mGoogleApiClient.connect();
            }
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    }
}

@Override
public void onConnectionSuspended(int i) {
    Log.w(TAG, "Connection to Google API client suspended");
}

private void setupGoogleClient() {
    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }
    mGoogleApiClient.connect();
}



class GoogleDriveAsync extends AsyncTask<String, Void, Void> {
    private GoogleDriveActivity activity;

    GoogleDriveAsync(GoogleDriveActivity activity) {
        this.activity = activity;
    }

    @Override
    protected Void doInBackground(String... args) {
        try {
            String id = args[0];
            GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Arrays.asList(SCOPES));
            credential.setBackOff(new ExponentialBackOff());
            credential.setSelectedAccountName(accountName);
            com.google.api.services.drive.Drive service = new com.google.api.services.drive.Drive.Builder(transport, jsonFactory, credential).build();
            File file = service.files().get(id).setFields("downloadUrl").execute();
            if (file != null) {
                String strUrl = file.getDownloadUrl();
                String token = GoogleAuthUtil.getToken(activity, accountName, "oauth2: " + Drive.SCOPE_FILE);
//This is your downloadUrl and token
                Log.w(TAG, "download link is " + strUrl + " and token is " + token);
            }
        } catch (final GooglePlayServicesAvailabilityIOException availabilityException) {
            Log.w(TAG, "Google Play Services not available to get downloadUrl of selected file");
        } catch (UserRecoverableAuthIOException userRecoverableException) {
            Log.w(TAG, "User authorization error in getting downloadUrl " + userRecoverableException.getMessage());
        } catch (Exception e) {
            Log.w(TAG, "Exception in getting downloadUrl " + e.getMessage());
        }
        return null;
    }
}
}

The AndroidManifest (relevant lines) :

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

<activity
            android:name="com.myapp.GoogleDriveActivity"
            android:label="@string/app_name"
            <meta-data android:name="com.google.android.apps.drive.APP_ID" android:value="id=<your-gogole-project-id>"/>
</activity>

The build.gradle (relevant lines):

compile 'com.google.android.gms:play-services-drive:7.8.0'
compile 'com.google.api-client:google-api-client:1.20.0'
compile 'com.google.api-client:google-api-client-android:1.20.0'
compile 'com.google.api-client:google-api-client-gson:1.20.0'
compile 'com.google.apis:google-api-services-drive:v2-rev170-1.20.0'


来源:https://stackoverflow.com/questions/32210970/list-files-from-google-drive-and-get-downloadurl-for-selected-file-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!