简体   繁体   English

使用 Android java 应用程序中的服务帐户连接到 google Drive API v3

[英]Connecting to google Drive API v3 with a service account in Android java app

I'm developing an Android app for internal use in the company I work for.我正在开发一个 Android 应用程序供我工作的公司内部使用。 I need to save a text file on a shared drive, on Google Drive.我需要在 Google Drive 的共享驱动器上保存一个文本文件。 I've done this several times before using a service account in the web appications I developed, but I can't seem to set the connection up correctly in an Android application environment.在我开发的 Web 应用程序中使用服务帐户之前,我已经这样做了几次,但我似乎无法在 Android 应用程序环境中正确设置连接。

I've tried the example provided by google https://developers.google.com/drive/api/v3/quickstart/java but it seems that this isn't compatible with Android, because it tries to use a library only available in desktop environment.我已经尝试过谷歌https://developers.google.com/drive/api/v3/quickstart/java提供的示例,但似乎这与 Android 不兼容,因为它尝试使用仅在桌面环境。

Here is the code of what I implemented:这是我实现的代码:

// Implements OnClick for sendData button
public void onClickSendData(View view) {
    try {
        // Build a new authorized API client service.
        final NetHttpTransport HTTP_TRANSPORT = new com.google.api.client.http.javanet.NetHttpTransport();
        Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                .setApplicationName(APPLICATION_NAME)
                .build();

        // Upload file to google drive
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss", Locale.forLanguageTag("hu-HU")).format(new java.util.Date());
        File fileMetadata = new File();
        fileMetadata.setName("scan_" + timeStamp + ".txt");
        fileMetadata.setParents(new ArrayList<String>(Arrays.asList(TARGET_FOLDER_ID)));
        java.io.File filePath = new java.io.File(getFilesDir() + java.io.File.separator + BARCODE_CONTAINER_TEMP_FILE);
        FileContent mediaContent = new FileContent("text/plain", filePath);
        File file = service.files().create(fileMetadata, mediaContent)
                .setFields("id")
                .execute();

        barcodeContainer.setText(R.string.tarhely_ures);
        barcodContainerEmptyFlag = true;

    }
    catch(Exception ex) {
        // Handle any exception
        ex.printStackTrace();

    }

}

private Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
    // Load client secrets.
    InputStream in = MainActivity.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
    if (in == null)
        throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);

    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

    java.io.File tokenFile = new java.io.File(getFilesDir() + java.io.File.separator + TOKENS_DIRECTORY_PATH);
    if(!tokenFile.isDirectory())
        tokenFile.mkdirs();

    // Build flow and trigger user authorization request.
    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
            .setDataStoreFactory(new FileDataStoreFactory(tokenFile))
            .setAccessType("offline")
            .build();
    LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();

    return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");

}

And the runtime error is the following: java.lang.ClassNotFoundException: Didn't find class “java.awt.Desktop” in Android运行时错误如下: java.lang.ClassNotFoundException: Didn't find class “java.awt.Desktop” in Android

I finally figured it out the answer to my problem, here is my solution using the GoogleCredential.Builder() documented here :我终于找到了我的问题的答案,这是我使用此处记录的GoogleCredential.Builder()解决方案:

    //  Upload file to google drive
    public void uploadBarcodeFileToDrive() throws IOException, GeneralSecurityException {
        // Get service account secret
        InputStream inputStream = MainActivity.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (inputStream == null)
            throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);

        // Convert inputStream to file
        java.io.File clientSecret = new java.io.File(getFilesDir() + java.io.File.separator + "credentials.p12");
        OutputStream outputStream = new FileOutputStream(clientSecret);
        IOUtils.copy(inputStream, outputStream);
        if (!clientSecret.exists())
            throw new FileNotFoundException("Credentials (credentials.p12) not created from: " + CREDENTIALS_FILE_PATH);

        // Http transport creation
        HttpTransport httpTransport = AndroidHttp.newCompatibleTransport();
        // Instance of the JSON factory
        JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
        // Instance of the scopes required
        List<String> scopes = new ArrayList<>();
        scopes.add(DriveScopes.DRIVE);
        // Build Google credential
        GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                .setServiceAccountId(SERVICE_ACCOUNT_PROVIDER)
                .setServiceAccountScopes(scopes)
                .setServiceAccountPrivateKeyFromP12File(clientSecret)
                .setServiceAccountUser(SERVICE_ACCOUNT_USER)
                .build();
        // Build Drive service
        Drive service = new Drive.Builder(httpTransport, jsonFactory, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();

        // Parents
        List<String> parents = new ArrayList<>();
        parents.add(TARGET_FOLDER_ID);
        // Setup file
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss", Locale.forLanguageTag("hu-HU")).format(new java.util.Date());
        File fileMetadata = new File();
        fileMetadata.setName("scan_" + timeStamp + ".txt");
        fileMetadata.setParents(parents);
        java.io.File filePath = new java.io.File(getFilesDir() + java.io.File.separator + BARCODE_CONTAINER_TEMP_FILE);
        FileContent mediaContent = new FileContent("text/plain", filePath);
        // Upload file to google drive
        service.files().create(fileMetadata, mediaContent)
                .setFields("id")
                .execute();

    }

The key differences in the example described in the question, and the current solution is the following:问题中描述的示例与当前解决方案的主要区别如下:

  • For the GoogleCredential.Builder() I needed to create an .p12 type key in the dev.console for the existing service account.对于GoogleCredential.Builder()我需要在 dev.console 中为现有服务帐户创建一个.p12类型的密钥。
  • The key is stored in the project's assets/credentials folder.密钥存储在项目的 assets/credentials 文件夹中。
  • This new key needs to be set up as a java.io.File instead of an InputStream , so I read it from the project assets and copied it to internal storage when the method called.这个新密钥需要设置为java.io.File而不是InputStream ,所以我从项目资产中读取它并在方法调用时将其复制到内部存储。
  • The SERVICE_ACCOUNT_USER should be the [..]@[..].iam.gserviceaccount.com style email address of the service account. SERVICE_ACCOUNT_USER应该是服务帐户的[..]@[..].iam.gserviceaccount.com样式的电子邮件地址。
  • And the setServiceAccountUser(SERVICE_ACCOUNT_USER) is necessary, if you want to use a 'real' account as the uploader, for example if you want to upload to a user's drive, or a folder shared with a specific user.并且setServiceAccountUser(SERVICE_ACCOUNT_USER)是必要的,如果您想使用“真实”帐户作为上传者,例如,如果您想上传到用户的驱动器或与特定用户共享的文件夹。
  • This user should have access granted for the service account in the dev.console.该用户应该具有在 dev.console 中为服务帐户授予的访问权限。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM