Android 10以及以上文件访问

①:android10以下检查文件,通常会调用if (file.exists())来判断,android10失效,需要通过查询Uri来获取:

@RequiresApi(Build.VERSION_CODES.Q)
fun getDownloadUri(filename:String,contentResolver:ContentResolver) :Uri?{

      //根据传入的文件名参数查询。注意这里的MediaStore.Downloads,要和存入时的相对路径一样。
    val cursor=contentResolver.query(
        MediaStore.Downloads.EXTERNAL_CONTENT_URI,
        arrayOf(MediaStore.Files.FileColumns._ID),
        MediaStore.Downloads.DISPLAY_NAME + "=?",
        arrayOf(filename),
        null
    )

    if (cursor != null && cursor.moveToFirst()) {
        //查出id
        val id: Int = cursor.getInt(cursor.getColumnIndex(MediaStore.Downloads._ID))
        //根据id查询URI
        return ContentUris.withAppendedId(
            MediaStore.Downloads.EXTERNAL_CONTENT_URI,
            id.toLong()
        )
    }
    //关闭查询
    //关闭查询
    cursor?.close()
    return null
}

uri如果为空,表明文件不存在,注意:android10 存储文件时文件名如果重复,会自动变成aa.png(1),aa.png(2),aa.png(3)等这种形式,超过一定数量,查询文件同样失败。

接着根据查询到的uri来获取绝对路径,代码如下:

var path=PathUtils.getPath(this,uri)

工具类:
public class PathUtils {

    public static final String DOC = "application/msword";
    public static final String DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    public static final String XLS = "application/vnd.ms-excel application/x-excel";
    public static final String XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    public static final String PPT = "application/vnd.ms-powerpoint";
    public static final String PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
    public static final String PDF = "application/pdf";
    /**
     * 文件Uri转路径(兼容各品牌手机)
     *
     *             val i = Intent(
     *                                 Intent.ACTION_GET_CONTENT
     *                             ).apply {
     *                                 val mimeTypes = arrayOf<String>(
     *                                     PathUtils.DOC,
     *                                     PathUtils.DOCX,
     *                                     PathUtils.PDF,
     *                                     PathUtils.PPT,
     *                                     PathUtils.PPTX,
     *                                     PathUtils.XLS,
     *                                     PathUtils.XLSX
     *                                 )
     *                                 setType("application/*");
     *                                 addCategory(Intent.CATEGORY_OPENABLE);
     *                                 putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
     *                                 startActivityForResult(this, GALLERY)
     *                             }
     */

    /**
     * android7.0以上处理方法
     */
    private static String getFilePathForN(Context context, Uri uri) {
        try {
            Cursor returnCursor = context.getContentResolver().query(uri, null, null, null, null);
            int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            returnCursor.moveToFirst();
            String name = (returnCursor.getString(nameIndex));
            File file = new File(context.getFilesDir(), name);
            InputStream inputStream = context.getContentResolver().openInputStream(uri);
            FileOutputStream outputStream = new FileOutputStream(file);
            int read = 0;
            int maxBufferSize = 1 * 1024 * 1024;
            int bytesAvailable = inputStream.available();

            int bufferSize = Math.min(bytesAvailable, maxBufferSize);

            final byte[] buffers = new byte[bufferSize];
            while ((read = inputStream.read(buffers)) != -1) {
                outputStream.write(buffers, 0, read);
            }
            returnCursor.close();
            inputStream.close();
            outputStream.close();
            return file.getPath();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 全平台处理方法
     */
    public static String getPath(final Context context, final Uri uri) throws Exception {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        final boolean isN = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;

        if (isN) {
            return getFilePathForN(context, uri);
        }

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }

            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                };

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }

    /**
     * 获取此Uri的数据列的值。这对于MediaStore uri和其他基于文件的内容提供程序非常有用。
     */
    public static String getDataColumn(Context context, Uri uri, String selection,
                                       String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {
                column
        };

        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                    null);
            if (cursor != null && cursor.moveToFirst()) {
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } catch (IllegalArgumentException e) {
            //do nothing
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }
}

android10存储时的文件路径:

getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) //类似的相对路径。

android10以上写入文件:

        val bis = BufferedInputStream(inputStream)
         val values = ContentValues()
       //这里的file.name,和MediaStore.Downloads,需要和之前的查询uri方法对应。
         values.put(MediaStore.Downloads.DISPLAY_NAME, file.name)
         values.put(MediaStore.Downloads.RELATIVE_PATH,Environment.DIRECTORY_DOWNLOADS)
         val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI,values)
          if (uri != null) {
                            val outputStream = contentResolver.openOutputStream(uri)
                            if (outputStream != null) {
                                val bos = BufferedOutputStream(outputStream)
                                val buffer = ByteArray(1024)
                                var bytes = bis.read(buffer)
                                while (bytes >= 0) {
                                    bos.write(buffer, 0, bytes)
                                    bos.flush()
                                    bytes = bis.read(buffer)
                                }
                                bos.close()
                            }
                        } else {
                            progressListener.failed("下载失败")
                        }
                        bis.close()

文件写入完成后,需要在手机文件夹“最近文件”里显示,需要刷新:

       MediaScannerConnection.scanFile(
                                        context,
                                        arrayOf<String>(file.absolutePath),
                                        null
                                    ) { path, uri ->

                                    }

②以前在文件下载后,需要预览,使用腾讯的Tbs服务,android10以下:旧版的tbs正常使用,新版貌似去掉该功能;

android10以上:Tabs文件服务无法使用,可以使用微软的工具:


//webview打开如下链接,后面是文件在线地址。
"http://view.officeapps.live.com/op/view.aspx?src="+fileUrl

或者使用手机自带第三方软件查看文件:

fun Activity.openFileScanViewer(file: File) {
    var uri: Uri?=null
    if (isAndroid7Above()) {
        uri = FileProvider.getUriForFile(this, packageName, file)
    }else{
        uri = Uri.fromFile(file)
    }
    val intent =
        Intent(Intent.ACTION_VIEW, uri)
    intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
    intent.addCategory(Intent.CATEGORY_DEFAULT)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent)
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值