【问题标题】:Android Problem with sharing temporary file共享临时文件的Android问题
【发布时间】:2019-11-13 00:09:54
【问题描述】:

我正在尝试创建一个临时文件并共享它。 所以我创建了这个类:

public class GenerateFile {

    public static File writeToFile(Context mcoContext, String sBody) {

        String fileName = "LOG FILE_" + String.valueOf(System.currentTimeMillis()) +".txt";
        File file = new File(mcoContext.getCacheDir(), fileName);

        try{
            FileWriter writer = new FileWriter(file);
            writer.append(sBody);
            writer.flush();
            writer.close();
            return  file;

        }catch (Exception e){
            Toast.makeText(mcoContext, "File write failed: " + e.toString(), Toast.LENGTH_LONG).show();
        }
        return null;
    }
}

生成一个文件,之后我会在这里分享:

String logContent = "123";
File filePath = new File(file.getAbsolutePath(), "external_files");
filePath.mkdir();
Uri uri = FileProvider.getUriForFile(StatusActivity.this, getPackageName(), filePath);

Intent intent = ShareCompat.IntentBuilder.from(StatusActivity.this)
       .setStream(uri) // uri from FileProvider
        .setType("text/html")
        .getIntent()
        .setAction(Intent.ACTION_VIEW) //Change if needed
        .setDataAndType(uri, "text/*")
        .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

并且在清单中已经有这个权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE"/>
<uses-permission android:name="com.sec.android.provider.badge.permission.READ"/>

和提供者声明

 <provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="android.getqardio.com.gmslocationtest"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

provider_paths 类是这样定义的:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path
        name="share"
        path="external_files"/>
</paths>

但是当我尝试通过邮件或电报共享“无法附加文件”或“不支持的附件”时,它会生成消息。在我看来,该文件还没有创建。

【问题讨论】:

    标签: android temporary-files share-intent sharefile


    【解决方案1】:

    其他应用无权访问您应用的getCacheDir()FLAG_GRANT_READ_URI_PERMISSIONFLAG_GRANT_WRITE_URI_PERMISSION 用于 content Uri 值,而不是 file Uri 值。而且,在 Android 7.0+ 设备上,您的代码应该会崩溃并显示 FileUriExposedException

    Use FileProvider 将您的内容提供给其他应用,使用FileProvider.getUriForFile() 获取Uri 以放入Intent

    【讨论】:

    • 我更新了我的代码,所以问题是:我在清单中插入了提供程序并创建了 provider_paths。我还更改了有关文件发送的代码。但不幸的是现在我有另一个错误:NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
    • @TheOldBlackbeard:该错误表明getPackageName()android.getqardio.com.gmslocationtest 不同。您在getUriForFile() 中用于权限名称的值需要与您在android:authorities 属性中使用的值相匹配。另外,请停止在问题中将“sn-p”内容添加到您的源代码中,因为它不是 JavaScript 并且无法运行。
    • @TheOldBlackbeard:另外,您将文件保存在getCacheDir(),但您在元数据中使用&lt;files-path&gt;。那些也不匹配。请改用&lt;cache-path&gt;
    • 抱歉sn-p,我不知道如何避免它。非常感谢您的建议,我将尝试编辑代码。
    【解决方案2】:

    所以我遵循@CommonsWare 的建议,并编辑了我的代码。这是最终结果:

    public class GenerateFile {
    
        public static Uri getFileURI(Context context, String nameFile, String content, String fileExtension) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd");
            Date date = new Date();
            String fileName = dateFormat.format(date)+nameFile+fileExtension;
            File file = new File(context.getCacheDir(), fileName);
    
            try{
                FileWriter writer = new FileWriter(file);
                writer.append(content);
                writer.flush();
                writer.close();
                //Toast.makeText(context, "Writing to the file completed successfully", Toast.LENGTH_LONG).show();
            }catch (Exception e){
                Toast.makeText(context, "File writing failed: " + e.toString(), Toast.LENGTH_LONG).show();
            }
    
            File filePath = new File(context.getCacheDir(), "");
            File newFile = new File(filePath, fileName);
            return FileProvider.getUriForFile(context, "MYPACKAGE.fileprovider", newFile);
        }
    }
    

    在另一个班级:

    private void sendFile(String nameFile, String logContent,  String fileExtension) {
            Uri contentUri = GenerateFile.getFileURI(getApplicationContext(), nameFile, logContent, fileExtension);
    
            Intent intent = ShareCompat.IntentBuilder.from(StatusActivity.this)
                    .setStream(contentUri) // uri from FileProvider
                    .setType("text/plain")
                    .getIntent()
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            startActivity(Intent.createChooser(intent, "send"));
    }
    

    所以发送文件。我还删除了清单中的权限(前面提到过),因为我不再需要它了。

    我还像这样编辑了我的 provider 和 provider_path 文件:

    <provider
       android:name="android.support.v4.content.FileProvider"
       android:authorities="MYPACKAGE.fileprovider"
       android:exported="false"
       android:grantUriPermissions="true">
       <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
     </provider>
    
    <?xml version="1.0" encoding="utf-8"?>
    <cache-path
        name="my_files"
        path=""
    />
    

    现在可以了!非常感谢大家的帮助!

    【讨论】:

      【解决方案3】:

      您是否专门要求用户授予这些权限?仅将权限放在目标 SDK 的清单中低于 28 是不够的。此外,在 Android Q 中,您将需要完全解决外部存储权限,因为这是不允许的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-17
        • 1970-01-01
        • 2021-05-26
        • 2017-01-20
        • 1970-01-01
        • 2011-09-13
        • 2015-12-16
        相关资源
        最近更新 更多