简体   繁体   English

如何将视频格式文件从 Android 应用推送到 Google Drive?

[英]How to push a video format file to the Google Drive from an Android app?

I'm trying to make my Android app to upload a Video format file to my Google Drive account.我正在尝试让我的 Android 应用程序将视频格式文件上传到我的 Google Drive 帐户。 The whole code:整个代码:

import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
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.client.util.ExponentialBackOff;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.FileList;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLConnection;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static net.fortuna.ical4j.util.ResourceLoader.getResourceAsStream;

public class ManagerUploadFragment extends Fragment {
    private final static int APP_PERMISSION_REQUEST = 100;
    private final static int ACTIVITY_CHOOSE_FILE = 1;

    private static final String APPLICATION_NAME = "Google Drive API Java Quickstart";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String TOKENS_DIRECTORY_PATH = "tokens";


    private static final List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE_METADATA_READONLY);
    private static final String CREDENTIALS_FILE_PATH = "/credentials.json";


    private View fragmentView;

    private Button uploadButton;

    private Drive driveService;

    // Required empty public constructor for fragments
    public ManagerUploadFragment() {}

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        fragmentView = inflater.inflate(R.layout.fragment_manager_upload, container, false);

        uploadButton = (Button) fragmentView.findViewById(R.id.upload_view_browse_button);

        // Set upload button
        uploadButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                uploadImage();
            }
        });

        // Connect to drive
        try {
            driveService = createService();
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return fragmentView;
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == APP_PERMISSION_REQUEST) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                for (int grantResult : grantResults) {
                    if (grantResult != PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(getActivity(), R.string.enable_required_permissions, Toast.LENGTH_LONG).show();
                        return; // Permissions were not granted
                    }
                }
            }
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == AppCompatActivity.RESULT_OK) {
            if (requestCode == ACTIVITY_CHOOSE_FILE && getActivity() != null) {
                Uri uri = data.getData();
                System.out.println("URI " + uri.toString());
                if (!(isVideoFile(uri))) {
                    Toast.makeText(getActivity(), "File is not in a valid video format", Toast.LENGTH_LONG).show();
                    return;
                }
                if (getFileSizeInMB(uri.getPath()) > 1) {
                    Toast.makeText(getActivity(), "File size is bigger than 20MB", Toast.LENGTH_LONG).show();
                    return;
                }
            }
        }
    }

    private static long getFileSizeInMB(final String file_path) {
        final File file = new File(file_path);
        long sizeInBytes = file.length();
        return sizeInBytes / (1024 * 1024);
    }

    private boolean isVideoFile(Uri uri) {
        ContentResolver cR = getContext().getContentResolver();
        String type = cR.getType(uri);
        return type != null && (type.equals("video/mp4") || type.equals("video/avi"));
    }

    private void uploadImage() {
        if (getActivity() != null) {
            final int writeStoragePermission = ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
            final int readStoragePermission = ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE);
            if (writeStoragePermission != PackageManager.PERMISSION_GRANTED || readStoragePermission != PackageManager.PERMISSION_GRANTED) {
                final String[] permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
                ActivityCompat.requestPermissions(getActivity(), permissions, APP_PERMISSION_REQUEST);
                return;
            }

            Intent chooseFile;
            Intent intent;
            chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
            chooseFile.addCategory(Intent.CATEGORY_OPENABLE);
            chooseFile.setType("*/*");
            intent = Intent.createChooser(chooseFile, "Choose a file");
            startActivityForResult(intent, ACTIVITY_CHOOSE_FILE);
        }
    }

    private Drive createService() throws GeneralSecurityException, IOException {
        final NetHttpTransport HTTP_TRANSPORT = new com.google.api.client.http.javanet.NetHttpTransport();
        Drive mService = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(getContext(), HTTP_TRANSPORT))
                .setApplicationName(APPLICATION_NAME)
                .build();

        // Print the names and IDs for up to 10 files.
        FileList result = mService.files().list()
                .setPageSize(10)
                .setFields("nextPageToken, files(id, name)")
                .execute();
        List<com.google.api.services.drive.model.File> files = result.getFiles();
        if (files == null || files.isEmpty()) {
            System.out.println("No files found.");
        } else {
            System.out.println("Files:");
            for (com.google.api.services.drive.model.File file : files) {
                System.out.printf("%s (%s)\n", file.getName(), file.getId());
            }
        }
        return mService;
    }

    private static Credential getCredentials(final Context context, final NetHttpTransport HTTP_TRANSPORT) throws IOException {
        // Load client secrets.
        InputStream in = context.getClass().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));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
        return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
    }
}

In order to upload the video to the Dirve, I need to connect to the Drive first.为了将视频上传到 Dirve,我需要先连接到 Drive。 I followed the steps on how to create to use the API ( docs ).我按照有关如何创建使用 API ( docs ) 的步骤进行操作。 Then I followed this example , which should show how to connect to the Google Drive and list the content.然后我按照这个例子,它应该展示如何连接到谷歌驱动器并列出内容。

But, before even pressing the "upload" button, I get an error to connect to the Google Drive:但是,在按下“上传”按钮之前,连接到 Google Drive 时出现错误:

java.io.IOException: unable to create directory: /tokens java.io.IOException:无法创建目录:/tokens

On line:在线的:

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();

Please correct me if I'm wrong, but as I understand, it tries to create the token directory locally and not in the remote - but why does it need it?如果我错了,请纠正我,但据我所知,它试图在本地而不是在远程创建token目录 - 但为什么需要它? I just want to be able to push the video I got from the user to the Drive.我只是希望能够将我从用户那里获得的视频推送到云端硬盘。 How can I connect to the Google Drive and push the video to the Drive (if you will take a look into a code, I have the uri of the file, that should be pushed to the Drive).如何连接到 Google 云端硬盘并将视频推送到云端硬盘(如果您要查看代码,我有文件的uri ,应该将其推送到云端硬盘)。

I fell victim to this as well.我也因此成为受害者。 Unfortunately, the tutorial you're following is for a "simple Java command line application" (stated on the first sentence of the quickstart example).不幸的是,您所遵循的教程是针对“简单的 Java 命令行应用程序” (在快速入门示例的第一句话中说明)。 So you are correct, the issue is that it tries create the token directory in order to store the access token, which you need in order to make requests to the Google Drive API.所以你是对的,问题在于它尝试创建令牌目录以存储访问令牌,这是向 Google Drive API 发出请求所需的。

If you are ok with using GoogleSignInClient to initiate authentication, I believe this should help.如果您同意使用 GoogleSignInClient 启动身份验证,我相信应该会有所帮助。 Start at the "The Future: Using GoogleApi" section.“未来:使用 GoogleApi”部分开始。

If you want to follow the low-level protocol instead you can follow this doc on OAuth2.0 for mobile.如果您想遵循低级协议,则可以在 OAuth2.0 for mobile 上遵循此文档

I hope this helps or, at the very least, saves some time.我希望这会有所帮助,或者至少可以节省一些时间。

This works for me:这对我有用:

  1. Implement these libraries in your gradle file(app level)在您的 gradle 文件(应用程序级别)中实现这些库

    implementation 'com.google.android.gms:play-services-auth:19.0.0' implementation 'com.google.http-client:google-http-client-gson:1.26.0' implementation('com.google.api-client:google-api-client-android:1.26.0') { exclude group: 'org.apache.httpcomponents' } implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0') { exclude group: 'org.apache.httpcomponents' }实现 'com.google.android.gms:play-services-auth:19.0.0' 实现 'com.google.http-client:google-http-client-gson:1.26.0' 实现('com.google.api -client:google-api-client-android:1.26.0') { exclude group: 'org.apache.httpcomponents' } implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25 .0') { 排除组:'org.apache.httpcomponents' }

  2. In your manifest add these permissions在您的清单中添加这些权限

  3. Go to Google Cloud Console and make a new project then go to the Library tab and add Google Drive API in it.转到 Google Cloud Console 并创建一个新项目,然后转到 Library 选项卡并在其中添加 Google Drive API。 Now you have to register your app for OAuthConsent Screen.现在您必须为 OAuthConsent Screen 注册您的应用程序。 It is required as When you use OAuth 2.0 for authorization, your app requests authorizations for one or more scopes of access from a Google Account.这是必需的,因为当您使用 OAuth 2.0 进行授权时,您的应用程序会请求对来自 Google 帐户的一个或多个访问范围的授权。

  4. There will be 2 options on OAuth consent screen page 1) Internal 2) External. OAuth 同意屏幕页面上将有 2 个选项 1) 内部 2) 外部。 I used external as only test users wanted to test the Consent screen so click on external and add scopes whatever you want add test users and your work is complete on the console.我使用外部因为只有测试用户想要测试同意屏幕所以点击外部并添加任何你想要添加测试用户的范围,你的工作在控制台上完成。

  5. Now come to your Android App for handling Google signing activity现在来到您的 Android 应用程序来处理 Google 签名活动

Code:代码:

 private static final int REQUEST_CODE_SIGN_IN = 1;

    static GoogleDriveServiceHelper mDriveServiceHelper;

    GoogleSignInClient googleSignInClient;

  /**
     * Starts a sign-in activity using {@link #REQUEST_CODE_SIGN_IN}.
     */
    private void requestSignIn() {
        Log.d(TAG, "Requesting sign-in");

        GoogleSignInOptions signInOptions =
                new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                        .requestScopes(new Scope(DriveScopes.DRIVE))
                        .requestEmail()
                        .build();
        googleSignInClient = GoogleSignIn.getClient(this, signInOptions);

        // The result of the sign-in Intent is handled in onActivityResult.
        startActivityForResult(googleSignInClient.getSignInIntent(), REQUEST_CODE_SIGN_IN);
    }


    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {

        switch (requestCode) {
            case REQUEST_CODE_SIGN_IN:
                if (resultCode == Activity.RESULT_OK && resultData != null) {
                    handleSignInResult(resultData);
                }
                break;

        }

        super.onActivityResult(requestCode, resultCode, resultData);
    }

    /**
     * Handles the {@code result} of a completed sign-in activity initiated from {@link
     * #requestSignIn()}.
     */
    private void handleSignInResult(Intent result) {
        GoogleSignIn.getSignedInAccountFromIntent(result)
                .addOnSuccessListener(googleAccount -> {
                    Log.d(TAG, "Signed in as " + googleAccount.getEmail());

                    // Use the authenticated account to sign in to the Drive service.
                    GoogleAccountCredential credential =
                            GoogleAccountCredential.usingOAuth2(
                                    this, Collections.singleton(DriveScopes.DRIVE));
                    credential.setSelectedAccount(googleAccount.getAccount());
                    Drive googleDriveService =
                            new Drive.Builder(
                                    AndroidHttp.newCompatibleTransport(),
                                    new GsonFactory(),
                                    credential)
                                    .setApplicationName("Whaterver the name is")
                                    .build();

                    // The DriveServiceHelper encapsulates all REST API and functionality.
                    // Its instantiation is required before handling any onClick actions.
                    mDriveServiceHelper = new GoogleDriveServiceHelper(googleDriveService);

                                                   
                    showMessage("Sign-In done...!!");
                 

                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception exception) {
                        Log.e(TAG, "Unable to sign in.", exception);
                        showMessage("Unable to sign in.");
                       
                    }
                });
    }

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

相关问题 如何仅使用Google Android应用中的Google Drive API在Google云端硬盘上创建和编辑电子表格文件? - How do I create & edit a spreadsheet file on google drive using Google Drive APIs only from my Android app? Android,如何从Google云端硬盘文件选择器获取“ fileID” - Android, how to get “fileID” from Google Drive File picker 如何使用Google Drive Android API删除Google Drive上的文件 - How to delete a file on google drive using Google Drive Android API 从 Android 将文件保存到 Google Drive - Saving a file in Google Drive from Android 使用java将文件从谷歌应用引擎上传到谷歌驱动器 - Upload file from google app engine to google drive using java Android Studio和Google Drive API(将视频上传到Google Drive) - Android Studio and Google Drive API (Uploading video to Google Drive) 如何使用drive api java从谷歌驱动器下载文件? - How to download a file from google drive using drive api java? 如何从 Google Drive 读取 txt 文件? - How to read txt file from Google Drive? 如何将图像从我的Android应用程序上传到Google驱动器上的特定文件夹 - how to upload an image from my android app to a specific folder on google drive 从Android应用程序保存和检索谷歌驱动器中的数据 - Saving and retrieving data in google drive from android app
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM