从内容提供者URI中查看意图?

11

我有一些要求来保护一些敏感数据。这些数据从一个URL以PDF格式下载并使用以下代码保存为应用程序私有文件:

public File downloadPDF(final Context fileContext, Uri reportUri, final String fileName)
{
    try
    {
        HttpGet get = new HttpGet(reportUri.toString());

        File file = httpClient.execute(get, new ResponseHandler<File>()
        {
            @Override
            public File handleResponse(HttpResponse response) throws ClientProtocolException, IOException
            {
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
                {
                    response.getEntity().writeTo(fileContext.openFileOutput(fileName, Context.MODE_WORLD_READABLE));
                    return fileContext.getFileStreamPath(fileName);
                }
                return null;
            }
        });

        return file;
    }
    catch (IOException e)
    {
        Log.e(TAG, "Unable to download report.", e);
    }

    return null;
}

现在,我想使用Context.MODE_PRIVATE来改变这个过程,并创建一个ContentProvider,以便我的应用程序完全控制将此文件共享给PDF阅读器(如Adobe Reader)。这是可行的吗?我当前使用以下代码将报告URI传递给当前配置的PDF阅读器。

    // Fire up a PDF viewer intent for the URL.
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setDataAndType(uri, "application/pdf");
    startActivity(intent);

同样的方法是否适用于ContentProvider类型的URI?如 content://package/fileid 这种类型的URI?我明天会尝试一下,看看能否实现,但如果有人知道只允许使用file:// URI,那么这将非常有帮助。


更新

我通过实现一个ContentProvider子类并覆盖以下方法,成功地解决了我的问题:

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException 
{
    // The filename is the path in the URI without the initial slash.
    String fileName = uri.getPath().substring(1);
    File file = getContext().getFileStreamPath(fileName);
    return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}

然后,当我启动查看intent时,它会被重写为类似于以下内容:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.withAppendedPath(Uri.parse("content://providername/"),filePath);
intent.setData(uri);
startActivity(intent);

在我的情况下,我使用 Adobe Reader,它可以正确地实现从 content:// URI 加载。

2个回答

5
同样的方法也适用于ContentProvider类型的URI吗?例如content://package/fileid这种类型的URI?
是的。您需要让您的ContentProvider在getType()方法中返回application/pdf。但是,一些PDF阅读器可能无法处理content:// Uri值。
您可以创建ContentProvider,然后使用PackageManager来查看是否有任何应用程序可以理解您在content:// Uri上的ACTION_VIEW Intent。如果有应用程序响应,则可以使用该方法。如果没有,您可以将文件设置为全局可读,并使用当前实现。或者,由于将文件更改为全局可读可能很麻烦,因此您可以在早期运行测试(例如,当您的应用启动时)使用ContentProvider支持的一些临时Uri,以便在下载时知道要采取哪种路线。

1
是的,看起来就是这样。我查看了Adobe Reader的“源代码”,以查看它是否会在VIEW content:// Intent的情况下使用Content Resolver,而实际上它确实会这样做。我现在正在努力弄清楚为什么我的ContentProvider没有被回调。 - Neal Sanche
好的,我刚刚意识到我需要覆盖ContentProvider实例上的openFile方法,以便拦截Adobe Reader对输入流的请求。这让我感到鼓舞。 - Neal Sanche
没问题,对我来说这有点学习曲线,所以很好我能自己解决。完成这个挑战后,我会更新“分辨率”的。我肯定已经让它工作并且按照预期设置了MODE_PRIVATE权限,所以我对结果感到满意。感谢您的帮助。 - Neal Sanche
@Thorinside +1 您明确地表示Adobe Reader支持内容提供程序,这点非常好。默认的三星应用程序没有支持,这就是我的问题。 :( - Peter
@PeterCarpenter 嗯,别告诉任何人,但我不得不反编译他们的应用程序才发现它支持内容提供程序。 - Neal Sanche
显示剩余2条评论

1

没有内容提供者不保护文件

实际上,应用程序从内容提供者获取文件时,可能会首先在其缓存目录中创建一个临时副本。我认为您应该重新考虑这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接