【问题标题】:How to download file from Google Drive with link in Android?如何通过 Android 中的链接从 Google Drive 下载文件?
【发布时间】:2018-02-08 05:50:14
【问题描述】:

我想从谷歌驱动器下载文件,我正在使用 compile 'com.google.android.gms:play-services:8.4.0' 的依赖项,并使用它可以从下面的示例中获取元数据的链接。

mFileId = (DriveId) data.getParcelableExtra(
                        OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);


                final DriveFile file = Drive.DriveApi.getFile(mGoogleApiClient, mFileId);


                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // DO your work here
                        DriveResource.MetadataResult mdRslt = file.getMetadata(mGoogleApiClient).await();
                        if (mdRslt != null && mdRslt.getStatus().isSuccess()) {
                           String  link = mdRslt.getMetadata().getWebContentLink();
                            String name=mdRslt.getMetadata().getTitle();
                            Log.d("LINK", link);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && getApplication().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
                            {
                                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                            }
                            else
                            {

                              new  get_download_data(link,name).execute();
                            }
                        }
                    }
                }).start();
                }

从 Google Drive 获取链接后,我正在调用异步任务从链接下载该文件。所以我的问题是当我下载文件时,它没有打开。经过检查和调试,我发现我的文件没有正确下载。

例如,我有文件名abc.pdf,大小为 400kb。我在我的 SD 卡上下载了,但 abc.pdf 只有 56 kb。我正在使用以下代码进行下载。我不知道我在哪里做错了。请帮忙。谢谢。

 public class get_download_data extends AsyncTask<Void,Void,String>
{
    File apkStorage = null;
    File outputFile = null;
    String link1="";
    String name1="";

    public get_database_data(String link, String name) {
        this.link1=link;
        this.name1=name;
    }
    protected void onPreExecute() {
        super.onPreExecute();



    }
    @Override
    protected String doInBackground(Void... params) {

        try {

            URL url = new URL(link1);//Create Download URl

            HttpURLConnection c = (HttpURLConnection) url.openConnection();//Open Url Connection
            c.setRequestMethod("GET");//Set Request Method to "GET" since we are grtting data


            c.setDoInput(true);

            c.connect();//connect the URL Connection

            //If Connection response is not OK then show Logs
            if (c.getResponseCode() != HttpURLConnection.HTTP_OK) {
                Log.e(TAG, "Server returned HTTP " + c.getResponseCode()
                        + " " + c.getResponseMessage());

            }else{
                Log.e(TAG, "Server returned HTTP " + c.getResponseCode()
                        + " " + c.getResponseMessage());
            }


            //Get File if SD card is present
            if (new CheckForSDCard().isSDCardPresent()) {

                apkStorage = new File(
                        Environment.getExternalStorageDirectory() + "/"
                                + "checkdb");
            } else
                Toast.makeText(getApplication(), "Oops!! There is no SD Card.", Toast.LENGTH_SHORT).show();

            //If File is not present create directory
            if (!apkStorage.exists()) {
                apkStorage.mkdir();
                Log.e(TAG, "Directory Created.");
            }

            outputFile = new File(apkStorage, name1);//Create Output file in Main File

            //Create New File if not present
            if (!outputFile.exists()) {
                outputFile.createNewFile();
                Log.e(TAG, "File Created");
            }

            OutputStream fos = new FileOutputStream(outputFile);//Get OutputStream for NewFile Location

            InputStream is = c.getInputStream();//Get InputStream for connection
            BufferedInputStream inStream = new BufferedInputStream(is, 1024);

            byte[] buffer = new byte[1024];//Set buffer type
            int len1 = 0;//init length
            while ((len1 = inStream.read(buffer)) != -1) {
                fos.write(buffer, 0, len1);//Write new file
            }

            //Close all connection after doing task
            fos.flush();
            fos.close();
            is.close();

        } catch (Exception e) {

            //Read exception if something went wrong
            e.printStackTrace();
            outputFile = null;
            Log.e(TAG, "Download Error Exception " + e.getMessage());
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result_1) {
        super.onPostExecute(result_1);
        String downlodepath = Environment.getExternalStorageState()+"/"+name1;
        Log.e("Sdpath",""+imagePath);
        Toast.makeText(getApplication(), "download"+downlodepath, Toast.LENGTH_SHORT).show();

    }
}

我找到了这个链接here,但有些我不知道如何实现它。请让我知道我错在哪里。谢谢。

【问题讨论】:

    标签: android android-fragments google-drive-api


    【解决方案1】:

    经过一些工作并尝试了这么多示例后,我找到了答案。 以下是我在项目中添加的依赖项:

    compile 'com.google.android.gms:play-services-auth:11.8.0'
    compile 'com.google.android.gms:play-services-drive:11.8.0'
    

    这是我的清单文件:

    <?xml version="1.0" encoding="utf-8"?>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_api_key" />
    
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
    </application>
    
    </manifest>
    

    这是我的 MainActivity:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
    private ActivityMainBinding binding;
    
    private static final String TAG = "Google drive";
    private static final String SIGN_IN = "Sign In";
    private static final String DOWNLOAD_FILE = "Download file";
    
    private static final int REQUEST_CODE_SIGN_IN = 0;
    private static final int REQUEST_CODE_OPEN_ITEM = 1;
    private static final int REQUEST_WRITE_STORAGE = 112;
    
    
    private GoogleSignInAccount signInAccount;
    private Set<Scope> requiredScopes;
    private DriveClient mDriveClient;
    private DriveResourceClient mDriveResourceClient;
    
    private OpenFileActivityOptions openOptions;
    private TaskCompletionSource<DriveId> mOpenItemTaskSource;
    private File storageDir;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    
        initialize();
        requestPermission();
        signInAccount = GoogleSignIn.getLastSignedInAccount(this);
    
        binding.btnSubmit.setOnClickListener(this);
        if (signInAccount != null && signInAccount.getGrantedScopes().containsAll(requiredScopes)) {
            initializeDriveClient(signInAccount);
            binding.btnSubmit.setText(DOWNLOAD_FILE);
        } else {
            binding.btnSubmit.setText(SIGN_IN);
        }
    
    }
    
    private void showMessage(String message) {
        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_CODE_SIGN_IN:
                if (resultCode == RESULT_OK) {
                    Task<GoogleSignInAccount> getAccountTask = GoogleSignIn.getSignedInAccountFromIntent(data);
                    if (getAccountTask.isSuccessful()) {
                        initializeDriveClient(getAccountTask.getResult());
                        showMessage("Sign in successfully.");
                        binding.btnSubmit.setText(DOWNLOAD_FILE);
                    } else {
                        showMessage("Sign in failed.");
                    }
                } else {
                    showMessage("Sign in failed.");
                }
                break;
            case REQUEST_CODE_OPEN_ITEM:
                if (resultCode == RESULT_OK) {
                    DriveId driveId = data.getParcelableExtra(OpenFileActivityOptions.EXTRA_RESPONSE_DRIVE_ID);
                    mOpenItemTaskSource.setResult(driveId);
                } else {
                    mOpenItemTaskSource.setException(new RuntimeException("Unable to open file"));
                }
                break;
        }
    }
    
    
    private void initialize() {
    
        requiredScopes = new HashSet<>(2);
        requiredScopes.add(Drive.SCOPE_FILE);
        requiredScopes.add(Drive.SCOPE_APPFOLDER);
    
        openOptions = new OpenFileActivityOptions.Builder()
                .setSelectionFilter(Filters.eq(SearchableField.MIME_TYPE, "application/pdf"))
                .setActivityTitle("Select file")
                .build();
    }
    
    private void initializeDriveClient(GoogleSignInAccount signInAccount) {
        mDriveClient = Drive.getDriveClient(getApplicationContext(), signInAccount);
        mDriveResourceClient = Drive.getDriveResourceClient(getApplicationContext(), signInAccount);
    }
    
    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.btnSubmit) {
            String text = (String) ((Button) view).getText();
            if (text.equals(SIGN_IN)) {
                signIn();
            } else {
                onDriveClientReady();
            }
        }
    }
    
    private void signIn() {
        GoogleSignInOptions signInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestScopes(Drive.SCOPE_FILE)
                .requestScopes(Drive.SCOPE_APPFOLDER)
                .build();
        GoogleSignInClient googleSignInClient = GoogleSignIn.getClient(this, signInOptions);
        startActivityForResult(googleSignInClient.getSignInIntent(), REQUEST_CODE_SIGN_IN);
    }
    
    private void onDriveClientReady() {
        mOpenItemTaskSource = new TaskCompletionSource<>();
        mDriveClient.newOpenFileActivityIntentSender(openOptions)
                .continueWith(new Continuation<IntentSender, Void>() {
                    @Override
                    public Void then(@NonNull Task<IntentSender> task) throws Exception {
                        startIntentSenderForResult(
                                task.getResult(), REQUEST_CODE_OPEN_ITEM, null, 0, 0, 0);
                        return null;
                    }
                });
    
        Task<DriveId> tasks = mOpenItemTaskSource.getTask();
        tasks.addOnSuccessListener(this,
                new OnSuccessListener<DriveId>() {
                    @Override
                    public void onSuccess(DriveId driveId) {
                        retrieveContents(driveId.asDriveFile());
                    }
                })
                .addOnFailureListener(this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        showMessage("File not selected.");
                    }
                });
    }
    
    private void retrieveContents(final DriveFile file) {
        // [START open_file]
        final Task<DriveContents> openFileTask = mDriveResourceClient.openFile(file, DriveFile.MODE_READ_ONLY);
        // [END open_file]
        // [START read_contents]
        openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
            @Override
            public Task<Void> then(@NonNull Task<DriveContents> task) throws Exception {
                DriveContents contents = task.getResult();
    
                Log.v(TAG, "File name : " + contents.toString());
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
                    InputStream input = contents.getInputStream();
    
                    try {
                        File file = new File(getExternalFilesDir(null), "umesh.pdf");
                        Log.v(TAG, storageDir + "");
                        OutputStream output = new FileOutputStream(file);
                        try {
                            try {
                                byte[] buffer = new byte[4 * 1024]; // or other buffer size
                                int read;
    
                                while ((read = input.read(buffer)) != -1) {
                                    output.write(buffer, 0, read);
                                }
                                output.flush();
                            } finally {
                                output.close();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            input.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                showMessage("Download file successfully.");
                return mDriveResourceClient.discardContents(contents);
            }
        })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        showMessage("Unable to download file.");
                    }
                });
        // [END read_contents]
    }
    
    private void requestPermission() {
        String dirPath = getFilesDir().getAbsolutePath() + File.separator + "PDF";
        storageDir = new File(dirPath);
        if (!storageDir.exists())
            storageDir.mkdirs();}}
    

    这里是 API 密钥的字符串文件:

    <resources>
        <string name="app_name">GoogleDriveDemo</string>
    
        <string name="google_api_key">"your-key"</string>
    </resources>
    

    【讨论】:

    • 我尝试通过此代码下载 Google Doc 和电子表格,但无法下载。你有什么主意吗?如何下载 Google Doc、Spreadsheet 和 Presentation?
    • @shailesh 您是否更改了代码中的 MIME_TYPE??...请检查此代码,它是唯一的 pdf 文件。
    • 您好 Umesh,感谢您的回复,我知道这一点,并且我已成功处理 .docx、.doc、.ppt 和 .txt 文件。甚至为 Google Doc、Spreadsheet 和 Presentation 使用了正确的 MIME_TYPE,之后,它向我显示了列表中的所有类型的文档,但下载此文档的问题。没问题,我找到了解决方案。
    • @Shailesh 很高兴听到你找到了解决方案。快乐的编码。
    • @umeshvashisth 您是否需要创建凭据才能使您的代码正常工作?另外,您是否愿意帮助我克服您在设法使 Drive API 正常工作时遇到的相同问题?提前谢谢你。
    【解决方案2】:

    我在 Drive API 中下载文件时使用 webContentLink 的方式是在 Javascript 中打开一个新的浏览器窗口。

    var webcontentlink = 'https://docs.google.com/a/google.com/uc?id='+fileId+'&export=download'
    window.open( webcontentlink);
    

    我建议你在 Android 中这样做,就像 post 中提到的那样:

    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webcontentlink));
    startActivity(browserIntent);
    

    【讨论】:

    • 我很欣赏你的回答,但我不想在网络浏览器中打开。我想在获得 url 时直接下载。
    • 好的,祝你好运。如果你找到了,分享你的答案,好吗?
    • 检查我的答案。
    【解决方案3】:

    对于仍然陷入此问题的人。 不知何故,在driveResourceClient.createFile()之后无法返回下载网址

    driveResourceClient?.createFile(appFolder, metadataChangeSet, contents)
                }?.addOnSuccessListener(this
                ) { driverFile -> //we cannot get webContentLink here }
    

    此时我们只能获取文件名(这个可能已经定义好了)

    就我而言,上传后我并不真正需要 URL,但当用户单击复制 URL 按钮时

    driveResourceClient?.query(Query.Builder()
                    .addFilter(Filters.eq(SearchableField.TITLE, sharedFileName))
                    .build())
                    ?.addOnSuccessListener {
                        url = it.first().webContentLink
                    }
                    ?.{
                    }
    

    我刚刚成功了。

    【讨论】:

      【解决方案4】:

      您可以使用 chrome 自定义选项卡轻松做到这一点,只需将 url 粘贴到自定义选项卡中,它就会显示驱动器网站,并且可以下载文件 请参阅此官方文档以获取 chrome 自定义标签 https://developer.chrome.com/multidevice/android/customtabs 这是一个非常棒的功能,也是 webview 的最佳替代品

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多