安卓實現分享圖片與文本,適配7.0以上文件訪問權限問題

引言:
今天看官方文檔,分享簡單數據,即在app內實現分享文本和圖片到其他應用。文本分享着還沒有毛病,幾行代碼就解決了:

        Intent intent=new Intent();
        intent.setAction(Intent.ACTION_SEND);
        /*發送文本時使用*/
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT,MESSAGE);//發送的文本
        Intent share=Intent.createChooser(intent,"MyTitle");
        startActivity(share);

至於詳細呢,建議先去看看官方文檔:
將簡單數據發送到其他應用

然後呢,我看了之後,準備分享一張圖片,然後問題就來了:我如何將項目中的圖片轉成uri呢?
查閱相關資料(百度)後我發現可以先將Bitmap處理爲二進制流,然後寫入到文件裏,最後將文件轉成Uri。
然後剩下操作就與上面文本的類似了,類型換成圖片,就可以實現分享了。
1.將Bitmap處理爲二進制流:

//先轉化爲二進制流
        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.mipmap.test);
        bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
        byte[] bytes=outputStream.toByteArray();

2.將二進制流寫入到文件裏:

//再存入到文件中
		final String path=getFilesDir().getCanonicalPath()+"/"+"test.png";
        File file=new File(path);
        FileOutputStream fileOutputStream=new FileOutputStream(file);
        fileOutputStream.write(bytes);
        fileOutputStream.flush();
        fileOutputStream.close();

3.文件轉uri:

//再從文件獲取Uri
        if(file.exists()){
            //7.0開始,需通過FileProvider共享文件
            if(Build.VERSION.SDK_INT>=24){
                Uri uri= FileProvider.getUriForFile(MainActivity.this,"com.example.mydrawabletest.fileprovider",file);
               // intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.putExtra(Intent.EXTRA_STREAM,uri);
            }else{
                Uri uri=Uri.fromFile(file);
                intent.putExtra(Intent.EXTRA_STREAM,uri);
            }
        }

這也是最坑的點,此時你會發現,若你對7.0以上設備不進行處理,則會得到如下結果:
在這裏插入圖片描述
大概意思就是不能直接訪問文件,那麼就需要用到FileProvider了,詳細用法參照官方文檔:
設置文件分享
好了,那我先給出我的配置:
清單文件:

<provider
            android:authorities="com.example.mydrawabletest.fileprovider"
            android:name="androidx.core.content.FileProvider"
            android:grantUriPermissions="true"
            >
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths"/>
        </provider>

res/xml文件:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path
        name="files_path"
        path="/"/>
</paths>

paths標籤對裏面子元素可以是:
external-path,代表外部存儲目錄
cache-path,app私有存儲緩存目錄
files-path,app私有存儲文件目錄
看下面這張圖可能更好理解,由於我最初定義的保存圖片的目錄就是下面的files下,因此我選擇了files-path,這便是最底層目錄,所以我path屬性的值就只有一個‘/’,其實可以什麼都不要。
在這裏插入圖片描述
溫馨提示:
由於Uri解析和文件寫入都涉及到了文件訪問,權限一定要給上對吧,爲了兼容高版本要動態申請哦,給出完整實例代碼吧(與分享功能實現無關的部分請都忽略,帶來不便,請諒解):

package com.example.mydrawabletest;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static final String MESSAGE="www.baidu.com";

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

    private void judgePermission() {
        /**
         * 先檢查權限是否打開,打開了就可以直接訪問,未打開則先申請一波權限
         */
        if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE)!=
        PackageManager.PERMISSION_GRANTED||(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.READ_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED)){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                makeAnExtraRequest();
            }
        }else{
            shareMessage();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void makeAnExtraRequest() {
        int code = 100;
        String[] permissions = {
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };

        for (String string : permissions) {
            if (this.checkSelfPermission(string) != PackageManager.PERMISSION_GRANTED) {
                this.requestPermissions(permissions, code);
                code++;
                return;
            }
        }
    }

    private void shareMessage() {
        Intent intent=new Intent();
        intent.setAction(Intent.ACTION_SEND);
        /*
        發送文本時使用
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT,MESSAGE);
        Intent share=Intent.createChooser(intent,"MyTitle");
        startActivity(share);
         */

        /*
        發送圖片時使用
         */
        //getUriOne(intent);
        try {
            getUriTwo(intent);
        } catch (IOException e) {
            e.printStackTrace();
        }
        intent.setType("image/png");
        Intent share=Intent.createChooser(intent,"MyTitle");
        startActivity(share);
    }

    private void getUriTwo(Intent intent) throws IOException {
        final String path=getFilesDir().getCanonicalPath()+"/"+"test.png";
        //先轉化爲二進制流
        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.mipmap.test);
        bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
        byte[] bytes=outputStream.toByteArray();

        //再存入到文件中
        File file=new File(path);
        FileOutputStream fileOutputStream=new FileOutputStream(file);
        fileOutputStream.write(bytes);
        fileOutputStream.flush();
        fileOutputStream.close();


        //再從文件獲取Uri
        if(file.exists()){
            //7.0開始,需通過FileProvider共享文件
            if(Build.VERSION.SDK_INT>=24){
                Uri uri= FileProvider.getUriForFile(MainActivity.this,"com.example.mydrawabletest.fileprovider",file);
               // intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.putExtra(Intent.EXTRA_STREAM,uri);
            }else{
                Uri uri=Uri.fromFile(file);
                intent.putExtra(Intent.EXTRA_STREAM,uri);
            }
        }

    }

    private void getUriOne(Intent intent) {
        /*
        此方法雖然可行,但是MediaStore.Images.Media.insertImage這個方法已經廢棄,不推薦
         */
        Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.mipmap.test);
        Uri uri=Uri.parse(MediaStore.Images.Media.insertImage(getContentResolver(),bitmap,null,null));
        intent.putExtra(Intent.EXTRA_STREAM,uri);
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        shareMessage();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章