Android 系统自带分享功能【图片、文字、CSV和PDF文件】

前言:
调用系统自带的分享功能将文本,当前界面截图、CSV和PDF文件分享出去;

效果图【测试机型:小米10】:

在这里插入图片描述
在这里插入图片描述
添加依赖:

    implementation 'com.itextpdf:itextg:5.5.10'

1、代码部分
①:工具类:FileShareUtils

public class FileShareUtils {
    private static final String TAG = "FileShareUtils";
    //文件输出流
    private static OutputStream outputStream;
    /**
     * 维度。A4尺寸为210×297毫米或8.27×11.69英寸。
     * 在PostScript中,其尺寸四舍五入为595×842点。
     */
    private static final int A4_WIDTH = 2520 / 2; // 210 * 6
    private static final int A4_HEIGHT = 3564 / 2; // 297 * 6

    /**
     * 创建csv文件
     *
     * @param context 上下文
     * @param datas   Lists of csv data
     */
    public static void shareCsvFile(Context context, List<String> datas) {
        //应用路径:/storage/emulated/0/Android/data/你的应用包名/files/test
        File csvFile = context.getExternalFilesDir("HelloWord");
        if (!csvFile.exists()) {
            // 如果你想在已经存在的文件夹(zainar)下建立新的文件夹(database),就可以用此方法。
            // 此方法不能在不存在的文件夹下建立新的文件夹。假如想建立名字是"database"文件夹,那么它的父文件夹必须存在。
            csvFile.mkdir();
        }
        String fileName = getFileName();
        //时间戳.csv
        File file = new File(csvFile, fileName + ".csv");
        try {
            //创建一个文件夹
            file.createNewFile();
        } catch (IOException e) {
            Log.e(TAG, "createCsvFile: " + e.getMessage());
        }
        //分享CSV
        startIntent(context, getUriForFile(context, writeDataToFile(file, datas)), fileName, 0);
    }

    /**
     * 写数据至文件夹中,创建file
     *
     * @param file     创建CSV文件对象
     * @param dataList 分享的数组
     * @return
     */
    private static File writeDataToFile(final File file, List<String> dataList) {
        //目录是否存在该文件
        if (file.exists()) {
            try {
                outputStream = new FileOutputStream(file);
            } catch (FileNotFoundException e) {
                Log.e(TAG, "writeDataToFile: " + e.getMessage());
            }
            //文件输出流
            final OutputStream putStream = outputStream;
            try { //写入Utf-8文件头
                //在utf-8编码文件中BOM在文件头部,占用三个字节,用来标示该文件属于utf-8编码,
                //现在已经有很多软件识别bom头,但是还有些不能识别bom头,比如PHP就不能识别bom头,
                //这也是用记事本编辑utf-8编码后执行就会出错的原因了
                putStream.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
            } catch (IOException e) {
                e.printStackTrace();
            }
            //减去1的标题栏
            String[] headerArray = new String[dataList.size() - 1];
            headerArray = dataList.toArray(headerArray);
            //1、普通形式
            try {
                for (int i = 0; i < headerArray.length; i++) {
                    putStream.write(headerArray[i].getBytes());
                }
                putStream.close();//关闭流
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "writeDataToFile: " + e.getMessage());
            }
        } else {
            //无法创建CSV文件
            Log.e(TAG, "创建CSV文件失败");
        }
        return file;
    }

    /**
     * 创建Pdf
     */
    public static void sharePdfFile(Context mContext) {
        //1、关联布局
        View view = LayoutInflater.from(mContext).inflate(R.layout.layout_pdf_view, null);
        //设置宽高为A4纸大小
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(A4_WIDTH, A4_HEIGHT);
        view.setLayoutParams(params);

        //2、布局View转化为Bitmap
        view.measure(View.MeasureSpec.makeMeasureSpec(A4_WIDTH, View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(A4_HEIGHT, View.MeasureSpec.EXACTLY));
        Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        view.layout(0, 0, view.getLayoutParams().width, view.getLayoutParams().height);
        view.draw(canvas);

        //3、创建BitmapPDF
        String fileName = getFileName();
        File file = createBitmapPdf(mContext, fileName, bitmap);
        //4、Intent意图-分享PDF
        startIntent(mContext, getUriForFile(mContext, file), fileName, 1);
    }

    /**
     * 创建PDF文件
     * https://github.com/itext/itextpdf/tree/itextg
     * iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库。
     * 通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。
     * iText 官网:http://itextpdf.com/
     * iText 开发文档: http://developers.itextpdf.com/developers-home
     */
    public static File createBitmapPdf(Context context, String fileName, Bitmap bitmap) {
        if (null == bitmap) {
            return null;
        }
        File dir = getFileUrl(context);
        //是否存在该文件,不存在则创建
        if (!dir.exists()) {
            dir.mkdir();
        }
        File file = new File(dir, fileName + ".pdf");
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //Page大小,左右上下边距【注意依赖库的包】
        Document document = new Document(PageSize.A4, 0, 0, 0, 0);
        try {
            PdfWriter.getInstance(document, new FileOutputStream(file));
            document.open();
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            //png、质量100
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
            byte[] byteArray = stream.toByteArray();
            //Image注意导com.itextpdf.text的包
            Image image = Image.getInstance(byteArray);
            //将图像缩放到一定的百分比。
            image.scalePercent(50);
            document.add(image);
            document.close();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 创建Bitmap图片
     */
    public static void sharePicFile(Activity context) {
        String fileName = getFileName();
        File path = getFileUrl(context);
        saveBitmap(context, path, viewToBitmap(context), fileName);
        File file = new File(path + "/" + fileName + ".png");
        startIntent(context, getUriForFile(context, file), fileName, 2);
        Log.e(TAG, "sharePicFile: " + file.toString());
    }

    /**
     * 当前界面转化为Bitmap
     * 需要截取状态栏则将stateHeight设置为0
     */
    private static Bitmap viewToBitmap(Activity activity) {
        Bitmap bitmap;
        View view = activity.getWindow().getDecorView();
        //设置是否可以进行绘图缓存
        view.setDrawingCacheEnabled(true);
        //如果绘图缓存无法,强制构建绘图缓存
        view.buildDrawingCache();
        //返回这个缓存视图
        bitmap = view.getDrawingCache();
        //获取状态栏高度(90)
        Rect frame = new Rect();
        //测量屏幕宽和高
        view.getWindowVisibleDisplayFrame(frame);
        int stateHeight = frame.top;
        Display display = activity.getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int width = size.x;
        int height = size.y;
        Log.e(TAG, "stateHeight size:" + stateHeight);
        Log.e(TAG, "width size:" + width);
        Log.e(TAG, "height size:" + height);
        // 根据坐标点和需要的宽和高创建bitmap
        bitmap = Bitmap.createBitmap(bitmap, 0, stateHeight, width, height - stateHeight);
        return bitmap;
    }

    /**
     * 保存图片
     *
     * @param context
     * @param dir
     * @param bitmap
     * @param fileName
     */
    @SuppressLint("SdCardPath")
    public static void saveBitmap(Context context, File dir, Bitmap bitmap, String fileName) {
        if (!dir.exists()) {
            dir.mkdir();
        }
        File file = new File(dir, fileName + ".png");
        FileOutputStream out;
        try {
            out = new FileOutputStream(file);
            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                out.flush();//空方法体,此输出流并强制写出所有缓冲的输出字节
                out.close();//关闭流
                bitmap.recycle();
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "saveBitmap: " + e.getMessage());
        }
        //发送广播更新,扫描某个文件(文件绝对路径,必须是以 Environment.getExternalStorageDirectory() 方法的返回值开头)
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file.getAbsolutePath())));
    }

    /**
     * 分享文本
     */
    public static void shareText(Context context) {
        Intent intent = new Intent(Intent.ACTION_SEND);
        //指定包名:注意判断是否安装微信、QQ等;否则报错ActivityNotFoundException: No Activity found to handle Intent
        //微信:com.tencent.mm   QQ:com.tencent.mobileqq
        //intent.setPackage("com.tencent.mobileqq");//不指定包名则会显示所有可分享的应用
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT, "分享的内容");
        context.startActivity(intent);
    }

    /**
     * 当前时间戳作为分享的文件名
     */
    private static String getFileName() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime());
    }

    /**
     * 返回uri
     */
    private static Uri getUriForFile(Context context, File file) {
        //应用包名.fileProvider
        String authority = context.getPackageName().concat(".fileProvider");
        Uri fileUri = FileProvider.getUriForFile(context, authority, file);
        Log.e(TAG, "onSuccess: 文件路径:" + authority);
        Log.e(TAG, "onSuccess: 文件路径:" + fileUri.toString());
        Log.e(TAG, "onSuccess: 文件路径:" + file.toString());
        return fileUri;
    }

    /**
     * 返回文件夹
     */
    private static File getFileUrl(Context context) {
        File root = context.getFilesDir();
        File dir = new File(root, "hello/");
        if (!dir.exists()) {
            //创建失败
            if (!dir.mkdir()) {
                Log.e(TAG, "createBitmapPdf: 创建失败");
            }
        }
        return dir;
    }

    /**
     * 分享CSV文件
     * true:csv false:pdf
     */
    @SuppressLint("WrongConstant")
    private static void startIntent(Context context, Uri fileUri, String fileName, int isType) {

        Log.e(TAG, "startIntent: " + fileUri.toString());
        Log.e(TAG, "startIntent: " + fileName);

        Intent share = new Intent(Intent.ACTION_SEND);
        share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        share.putExtra(Intent.EXTRA_STREAM, fileUri);
        share.putExtra(Intent.EXTRA_SUBJECT, fileName);
        String title = "分享标题";
        if (isType == 0) {
            share.setType("application/vnd.ms-excel");
            context.startActivity(Intent.createChooser(share, title));
        } else if (isType == 1) {
            share.setType("application/pdf");
            //管理应用程序包
            PackageManager packageManager = context.getPackageManager();
            //该组件或应用程序处于默认开启状态(其在清单指定)。
            List<ResolveInfo> list = packageManager.queryIntentActivities(share, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
            if (null == list || list.size() == 0) {
                Toast.makeText(context, "没有找到可阅读PDF程序", Toast.LENGTH_SHORT).show();
            } else {
                context.startActivity(Intent.createChooser(share, title));
            }
        } else if (isType == 2) {
            share.setType("image/*");
            //安卓版本是否大于7.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                context.startActivity(Intent.createChooser(share, title));
            } else {
                share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(getFileUrl(context), title)));
                context.startActivity(share);
            }
        }
    }
}

②:使用方法:ShareActivity

public class ShareActivity extends AppCompatActivity {

    private static final String TAG = "ShareActivity";
    //CSV标题
    private List<String> listTitles = new ArrayList<>();
    //CSV每行list
    private List<String> listStrings = new ArrayList<>();
    //CSV内容
    private List<String> listContents = new ArrayList<>();
    //CSV合并后的list
    private List<String> mergeList = new ArrayList<>();

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

    /**
     * 分享CSV文件
     */
    public void onCsvClick(View view) {
        for (int i = 0; i < 5; i++) {
            listTitles.add("标题" + i + ",");
        }
        listTitles.add("标题4\n");
        for (int i = 0; i < 5; i++) {
            listStrings.add("内容" + i);
        }
        listStrings.add("内容4\n");
        //去除空格
        String str = listStrings.toString().replace(" ", "");
        //去除收尾[]符号
        String result = str.substring(1, str.length() - 1);
        for (int i = 0; i < 5; i++) {
            listContents.add(result);
        }
        //合并List
        for (String value : listTitles) {
            mergeList.add(value);
        }
        for (String value : listContents) {
            mergeList.add(value);
        }
        //分享CSV文件
        FileShareUtils.shareCsvFile(this, mergeList);
    }

    /**
     * 分享PDF文件
     */
    public void onPdfClick(View view) {
        String authority = getPackageName().concat(".fileProvider");
        Log.e(TAG, "onPdfClick: " + authority);
        FileShareUtils.sharePdfFile(this);
    }

    /**
     * 分享图片文件
     */
    public void onPicClick(View view) {
        FileShareUtils.sharePicFile(this);
    }

    /**
     * 分享文字
     */
    public void onTextClick(View view) {
        FileShareUtils.shareText(this);
    }
}

对应布局:activity_share

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ShareActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onCsvClick"
        android:text="CSV分享" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onPdfClick"
        android:text="PDF分享" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onPicClick"
        android:text="Picture分享" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onTextClick"
        android:text="Text分享" />

</LinearLayout>

对应PDF分享布局:layout_pdf_view

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@mipmap/ic_launcher" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:lineSpacingMultiplier="1.2"
        android:text="Android是由Google公司和开放手机联盟领导并开发的一种基于Linux的自由且开放源代码的操作系统,主要使用于移动设备。其最初由Andy Rubin开发,后被Google于2005年8月收购。之后Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟,共同研发改良Android系统,完成开发后,Google以Apache开源许可证的授权方式,发布了Android的源代码。"
        android:textSize="16sp" />
</LinearLayout>

③:app/res目录下新建provider_paths.xml文件

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external_files"
        path="Hello_Word/" />
    <external-path
        name="external_storage_root"
        path="." />
    <root-path name="root_path" path="."/>
</paths>

④:清单文件AndroidManifest.xml添加

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true"
    tools:replace="android:authorities">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值