1

我不能让 cwac 工作,查看演示代码也没有帮助。我只是想通过共享意图导出 pdf。当前输出是“无法附加空文件”错误。但该文件确实存在,我无法判断问题是否与文件名、位置或 cwac 提供程序的使用有关。

这是我设置提供程序的方式。

        <provider
        android:name="com.commonsware.cwac.provider.StreamProvider"
        android:authorities="com.anothergamedesigner.CatVimeoTest.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="com.commonsware.cwac.provider.STREAM_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
    </provider>

这是提供商正在使用的我的 xml 资源。我将路径设置为“”,因为我没有任何子目录。我不知道是否需要这些,但理想情况下,我不想为了将文件放入子目录所需的文件重组而在其他地方切换我的代码。虽然,如果这是问题所在,我想我可以,但我不明白为什么 root 不应该工作。

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

这是我的 PDFActivity(扩展 AppCompatActivity):

变量:

private String pdfName //set in onCreate; ex. "This is my.pdf"

private static final String AUTHORITY = "com.anothergamedesigner.CatVimeoTest";
private static final Uri PROVIDER = Uri.parse("content://"+AUTHORITY);
private static final String ASSET_PATHS ="assets/";

方法定义:

private Intent getOpenPDFShareIntent(String name){
    Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
    shareIntent.setType("application/pdf");

    shareIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {""});
    shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.default_share_subject));
    shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, getResources().getString(R.string.default_share_text));

    shareIntent.putExtra(Intent.EXTRA_STREAM, getURI());
    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    shareIntent.setType("text/plain");
    return shareIntent;
}

private Uri getURI(){
    String path = ASSET_PATHS + pdfName;
    return(PROVIDER
            .buildUpon()
            .appendPath(StreamProvider.getUriPrefix(AUTHORITY))
            .appendPath(path)
            .build());

}

在 getURI() 中,System.out.println(path) 的示例返回是:“assets/my.pdf”

代码通过选择时的菜单按钮运行:

Intent shareIntent = getOpenPDFShareIntent(pdfName);
StartActivity(Intent.createChooser(shareIntent, getResources().getString(R.string.contact_send_mail));

编辑:尝试删除空 URIPrefix:

    private Uri getURI(){
    //String path = ASSET_PATHS + pdfName;

    if(StreamProvider.getUriPrefix(AUTHORITY) != null){
        return(PROVIDER
                .buildUpon()
                .appendPath(StreamProvider.getUriPrefix(AUTHORITY))
                .appendPath(ASSET_PATHS)
                .appendPath(pdfName)
                .build());
    } else{
        return(PROVIDER
                .buildUpon()
                .appendPath(ASSET_PATHS)
                .appendPath(pdfName)
                .build());
    }
}

编辑 2 - 使用 DocumentFile 进行测试:

我从另一个 SO 答案中使用了这些新方法,并对其进行了更改以返回文件。

private File CopyReadAssets()
{
    AssetManager assetManager = getAssets();

    InputStream in = null;
    OutputStream out = null;
    File file = new File(getFilesDir(), "my.pdf");
    try
    {
        in = assetManager.open("my.pdf");
        out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);

        copyFile(in, out);
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
    } catch (Exception e)
    {
        Log.e("tag", e.getMessage());
    }

    return file;
}

private void copyFile(InputStream in, OutputStream out) throws IOException
{
    byte[] buffer = new byte[1024];
    int read;
    while ((read = in.read(buffer)) != -1)
    {
        out.write(buffer, 0, read);
    }
}

然后我使用以下方法进行了测试:

DocumentFile aFile = DocumentFile.fromFile(CopyReadAssets());
DocumentFile file = DocumentFile.fromSingleUri(this, getURI());
System.out.println(aFile.getName());
System.out.println(aFile.length());
System.out.println(file.getName());
System.out.println(file.length());

它为 aFile 返回“my.pdf”和“33528”,为文件返回“my.pdf”和“FileNotFoundException”。

4

2 回答 2

0
content://com.anothergamedesigner.CatVimeoTest/null/assets%2FCEGA%20OnBoard%20Su‌​pport%201.6.compressed.pdf

我可以看到这里有两个问题。

一是StreamProvider.getUriPrefix(AUTHORITY)回归null。我不知道为什么,因为你似乎没有 subclassing StreamProvider。话虽如此,您应该检查null并跳过该appendPath()语句,如果它是null.

其次,而不是ASSET_PATHS + pdfName,使用两个appendPath()语句。这应该可以防止/被转换为%2F.

请注意,我没有尝试过名称中带有空格的文件,或者任何其他必须转义的文件,就像您在文件名中所使用的那样。可能存在与此相关的错误。如果更改上述两项没有帮助,请尝试将 PDF 临时重命名为简单的名称。如果这样可行,我有一个需要修复的错误。

于 2016-07-22T15:54:11.760 回答
0

最终代码

问题似乎出在 ASSET_PATHS 上。由于某种原因,将 pdfName 附加到“资产”被证明是有问题的。因此,我选择从 final 更改 ASSET_PATHS,然后在 onCreate 方法中设置它。这将是一种方法,或者您可以在不同的 pdf 中进行硬编码,例如在演示项目中。

public class PDFViewActivity extends AppCompatActivity {

private String pdfName;
...

private static final String AUTHORITY = "com.your.provider";
private static final Uri PROVIDER = Uri.parse("content://"+AUTHORITY);
private static String ASSET_PATHS;

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

    Bundle extras = getIntent().getExtras();
    pdfName = extras.getString("pdfName");
    ...

    ASSET_PATHS = "assets/" + pdfName;

    // Place an PDFViewFragment as our content pane
    PDFViewFragment f = new PDFViewFragment();
    getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_pdf, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
        case R.id.menu_button_share:
            Intent shareIntent = getOpenPDFShareIntent();
            startActivity(Intent.createChooser(shareIntent, "Send Email"));
            return true;
        ...
        default:
            return super.onOptionsItemSelected(item);
    }
}

private Intent getOpenPDFShareIntent(){
    Intent shareIntent = new Intent(Intent.ACTION_SEND);
    shareIntent.setType("application/pdf");

    shareIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {""});
    shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.default_share_subject));
    shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, getResources().getString(R.string.default_share_text));
    shareIntent.putExtra(Intent.EXTRA_STREAM, getURI());
    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    shareIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

    return shareIntent;
}

private Uri getURI(){
    return(PROVIDER
            .buildUpon()
            .appendPath(StreamProvider.getUriPrefix(AUTHORITY))
            .appendPath(ASSET_PATHS)
            .build());
}

}

于 2016-07-28T14:12:34.500 回答