Android 尝试使用cwac提供程序发送pdf
我无法让cwac正常工作,查看演示代码也没有帮助。我只是想通过共享意图导出pdf。当前输出为“无法附加空文件”错误。但该文件确实存在,我无法判断问题是否出在文件名、位置或cwac提供程序的使用上 下面是我如何设置提供者的Android 尝试使用cwac提供程序发送pdf,android,commonsware-cwac,share-intent,Android,Commonsware Cwac,Share Intent,我无法让cwac正常工作,查看演示代码也没有帮助。我只是想通过共享意图导出pdf。当前输出为“无法附加空文件”错误。但该文件确实存在,我无法判断问题是否出在文件名、位置或cwac提供程序的使用上 下面是我如何设置提供者的 <provider android:name="com.commonsware.cwac.provider.StreamProvider" android:authorities="com.anothergamedesign
<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>
方法定义:
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));
编辑:
正在尝试删除空前缀:
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());
对于文件,它返回“my.pdf”和“33528”;对于文件,它返回“my.pdf”和“FileNotFoundException”
content://com.anothergamedesigner.CatVimeoTest/null/assets%2FCEGA%20OnBoard%20Support%201.6.compressed.pdf
我可以看到这里有两个问题
首先,StreamProvider.getUriPrefix(AUTHORITY)
正在返回null
。我不知道为什么,因为您似乎没有子类化StreamProvider
。也就是说,您应该检查null
并跳过appendPath()
语句(如果它是null
)
其次,使用两条appendPath()
语句,而不是ASSET\u path+pdfName
。这将防止/
转换为%2F
请注意,我没有尝试过名称中带有空格的文件,也没有尝试过像文件名中那样必须转义的任何其他文件。可能存在与此相关的bug。如果更改上述两项没有帮助,请尝试将PDF临时重命名为简单的名称。如果这样做有效,我有一个bug需要修复
我可以看到这里有两个问题
首先,StreamProvider.getUriPrefix(AUTHORITY)
正在返回null
。我不知道为什么,因为您似乎没有子类化StreamProvider
。也就是说,您应该检查null
并跳过appendPath()
语句(如果它是null
)
其次,使用两条appendPath()
语句,而不是ASSET\u path+pdfName
。这将防止/
转换为%2F
请注意,我没有尝试过名称中带有空格的文件,也没有尝试过像文件名中那样必须转义的任何其他文件。可能存在与此相关的bug。如果更改上述两项没有帮助,请尝试将PDF临时重命名为简单的名称。如果这样做有效,我有一个bug需要修复。最终代码
问题似乎在于资产路径。由于某些原因,将pdfName附加到“资产”中被证明是有问题的。因此,我选择从final更改ASSET_路径,然后在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());
}
}最终代码
问题似乎在于资产路径。由于某些原因,将pdfName附加到“资产”中被证明是有问题的。因此,我选择从final更改ASSET_路径,然后在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());
}
}我将首先修复您的MIME类型。您没有共享纯文本。您正在共享
application/pdf
,并且正在调用setType()
两次。另外,在你开始工作之前,不要使用额外的文本ACTION\u SEND
支持EXTRA\u TEXT
或EXTRA\u STREAM
,因此根据ACTION\u SEND
活动的实施情况,您可能会得到一个或另一个,但不能同时得到两个。除此之外,您从getURI()
中得到的整个Uri
是什么样子的?我已经注释掉了这些行,是的,注意到了setType并删除了它。同样的问题,但最好按照你的建议去做。URI是:content://com.anothergamedesigner.CatVimeoTest/null/assets%2FCEGA%20OnBoard%20Support%201.6.compressed.pdfAny 知道空部分是如何产生的吗?我将从修复MIME类型开始。您没有共享纯文本。您正在共享application/pdf
,并且正在调用setType()
两次。另外,在你开始工作之前,不要使用额外的文本ACTION\u SEND
支持EXTRA\u TEXT
或EXTRA\u STREAM
,因此根据ACTION\u SEND
活动的实施情况,您可能会得到一个或另一个,但不能同时得到两个。除此之外,您从getURI()
中得到的整个Uri
是什么样子的?我已经注释掉了这些行,是的,注意到了setType并删除了它。同样的问题,但最好按照你的建议去做。URI是:content://com.anothergamedesigner.CatVimeoTest/null/assets%2FCEGA%20OnBoard%20Support%201.6.compressed.pdfAny 知道空部分是如何产生的吗?我试着按照你说的做,但我注意到的第一件事是返回的URI是空的"content://com.anothergamedesigner.CatVimeoTest/assets%2F/CEGA%20OnBoard%20Support%201.6.compressed.pdf“因此,/仍在被转换。@NappyXIII:抱歉,您还应该从资产路径中删除该斜杠。
。是的,也意识到了这一点,只是修复了它。所以我尝试硬编码my.pdf并将其中一个pdf重命名为该格式。我的新URI是:”content://com.anothergamedesigner.CatVimeoTest/assets/my.pdf“我仍然得到一个空文件。所以我下一个猜测是我必须解决URIPrefix问题,因为似乎不是空格导致了问题。我也尝试将my.pdf放在子目录中,以查看(path=”“)是否存在错误。”路径xml的一部分,没有骰子。我试着按照你说的做,但我注意到的第一件事是URI retu
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());
}