通过fileProvider接收外部App传递文件路径的一些坑

2018-10-16  本文已影响242人  kongzue

问题

由于Google的作死,现如今线版本的Android系统阻止了应用之间通过intent传递路径的行为,而通过此方法传递过来的路径会非常奇怪,直接获取会以类似如下形式表现:

 content://com.example.app.provider/storage/emulated/0/xxx...

如果将它丢到new File(path)里则会导致出错,那么如何解决这样的奇葩路径呢?

按照以往的方法,我们要读取到需要打开的文件的方法为:

Intent intent = getIntent();
if (intent != null) {
    String action = intent.getAction();
    if (action != null) {
        if (intent.ACTION_VIEW.equals(action)) {
            String uriPath = intent.getDataString();    //获取要打开文件的路径
            if (!isNull(uriPath)) {
                //执行打开操作...
            } else {
                //显示错误提示
            }
        }else if (intent.ACTION_SEND.equals(action)) {
            Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
            if (uri != null) {
                String file = uri.getPath();
                if (!isNull(file)) {
                    //执行打开操作...
                } else {
                   //显示错误提示
                }
            } else {
                //显示错误提示
            }
        }
    }
}

但是显然,fileProvider传递过来并非通常意义的路径,我们无法直接进行打开操作,那么此时正确的方法为首先我们需要在接收“打开”操作的Activity中接收到系统传递过来的Intent:

Uri data = getIntent().getData();

接下来直接通过ContentResolver获取读取流进行读取文件内容:

if (data != null) {
    InputStream inputStream = null;
    try {
        inputStream = getContentResolver().openInputStream(data);
        String content = readStreamToString(inputStream);
        //content 就是读取到的内容了,请直接食用
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException ignored) {
            }
        }
    }
}

此时通过ContentResolver获取到读取流就可以轻松读取到外部App传递过来的文档内容了。文中的content即读取到的文件所有内容,当然了,如果是图片也可以通过inputStream读取到,请按具体情况进行修改。

但是注意,如果遇到低版本的App,依然会传递以前方式正确路径过来,此时通过fileProvider法又无法读取内容,那么在这里我们就要做到新旧兼容,请参阅下述的完整代码:

完整代码

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

    //尝试使用fileProvider方式读取
    Uri data = getIntent().getData();
    if (data != null) {
        InputStream inputStream = null;
        try {
            inputStream = getContentResolver().openInputStream(data);
            String content = readStreamToString(inputStream);
            
            //请对读取到的内容content进行处理...

        } catch (Exception e) {
            //如果不支持,尝试老方法
            doTryOldReader(getIntent());
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException ignored) {
                }
            }
        }
    }else{
        //如果不支持,尝试老方法
        doTryOldReader(getIntent());
    }
}

//部分旧文件浏览器可以直接将路径发过来的情况执行下边的方法
private void doTryOldReader(Intent intent) {
    if (intent != null) {
        String action = intent.getAction();
        if (action != null) {
            if (intent.ACTION_VIEW.equals(action)) {
                String uriPath = intent.getDataString();
                
                if (!isNull(uriPath)) {
                    //在此处读取uriPath路径的文件即可
                } else {
                    //错误提示
                }
            }
            if (intent.ACTION_SEND.equals(action)) {
                Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
                if (uri != null) {
                    String file = uri.getPath();
                    
                    if (!isNull(file)) {
                        //在此处读取uriPath路径的文件即可
                    } else {
                        //错误提示
                    }
                } else {
                    //错误提示
                }
            }
        } else {
            //错误提示
        }
    } else {
        //错误提示
    }
    finish();
}

完。

上一篇下一篇

猜你喜欢

热点阅读