【问题标题】:Share .mp3 file located in /res/raw/ to WhatsApp将位于 /res/raw/ 的 .mp3 文件分享到 WhatsApp
【发布时间】:2020-08-09 22:46:14
【问题描述】:

我正在用 Android (API 29) 编写一个铃声应用程序,我想通过 WhatsApp 分享以 MP3 格式存储在 /res/raw/ 文件夹中的声音。我正在使用此代码:

    Intent share = new Intent(Intent.ACTION_SEND);
    Uri path = Uri.parse("android.resource://"+ getPackageName() + "/" + R.raw.yeah);
    share.setPackage("com.whatsapp");
    share.setType("audio/mp3");
    share.putExtra(Intent.EXTRA_STREAM, path);
    startActivity(Intent.createChooser(share, "Share"));

但每次我选择聊天来发送音频文件时,我都会收到一个 WhatsApp 错误,告诉我无法共享文件。我已经看到其他应用程序执行我想要的操作没有请求写入外部存储的权限。任何线索是如何做到的?

【问题讨论】:

    标签: android audio mp3 share whatsapp


    【解决方案1】:

    最后我设法通过混合 CommonsWare 答案 this answerthis one 解决了这个问题。在此先感谢大家!

    分步解决方案:

    首先,让我们从一些 XML 开始。

    1. 配置AndroidManifest.xml 并在<application> 部分中添加以下行。我将它们放在我的 </activity></application> 结束标记之间,但请将此位置作为我个人的选择:根据您的清单布局,它可能不适合您。

    AndroidManifest.xml

    <provider
       android:name="androidx.core.content.FileProvider"
       android:authorities="${applicationId}.provider"
       android:exported="false"
       android:grantUriPermissions="true">
       <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/file_paths" />
    </provider>
    

    当我使用 API 29 时,我是 AndroidX 库。如果您也想使用它,请考虑通过在 Android Studio 中单击 Refactor &gt; Migrate to AndroidX... 来运行 AndroidX 迁移向导,风险自负。

    1. 现在在/res/xml 中创建一个名为file_paths.xml 的文件并填写如下:

    file_paths.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <cache-path name="my_sounds" path="/"/>
    </paths>
    

    注意my_sounds 名称是任意的。 path 字段中的 / 是您的文件将存储在缓存路径中的位置。为了方便起见,我只是让它这样。如果您不想使用缓存路径,here 是您可以使用的可用标签的完整列表。

    现在我们将回到 Java 并开始编写处理共享的方法。首先,我们需要将资源文件夹中的文件复制到File 对象。然而,这个File 需要指向我们在 XML 部分中配置的文件提供程序创建的路径。让我们划分任务:

    1. 用您的文件数据创建一个InputStream,并用一个辅助过程用它填充一个File

    public void handleMediaSend(int position)

    File sound;
    try {
        InputStream inputStream = getResources().openRawResource(sounds.get(position).getSound()); // equivalent to R.raw.yoursound
        sound = File.createTempFile("sound", ".mp3");
        copyFile(inputStream, new FileOutputStream(sound));
    } catch (IOException e) {
        throw new RuntimeException("Can't create temp file", e);
    }
    

    辅助程序:

    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);
    }
    

    现在您的资源已成功传输到内部存储中的缓存目录(使用调试器查看是哪一个)。

    1. 获取Uri 并分享File
    final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";
    Uri uri = getUriForFile(getApplicationContext(), AUTHORITY, sound);
    Intent share = new Intent(Intent.ACTION_SEND);
    share.setType("audio/mp3"); // or whatever.
    share.putExtra(Intent.EXTRA_STREAM, uri);
    share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    startActivity(Intent.createChooser(share, "Share"));
    

    把它们放在一起,我们最终会得到这个方法:

    完整方法

    public void handleMediaSend(int position) { // Depends on your implementation.
        File sound;
        try {
            InputStream inputStream = getResources().openRawResource(sounds.get(position).getSound()); // equivalent to R.raw.yoursound
            sound = File.createTempFile("sound", ".mp3");
            copyFile(inputStream, new FileOutputStream(sound));
        } catch (IOException e) {
            throw new RuntimeException("Can't create temp file", e);
        }
    
        final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";
        Uri uri = getUriForFile(getApplicationContext(), AUTHORITY, sound);
        Intent share = new Intent(Intent.ACTION_SEND);
        share.setType("audio/mp3"); // or whatever.
        share.putExtra(Intent.EXTRA_STREAM, uri);
        share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        startActivity(Intent.createChooser(share, "Share"));
    }
    

    【讨论】:

      【解决方案2】:

      但是每次我选择一个聊天来发送音频文件时,我都会收到一个 WhatsApp 错误,告诉我文件无法共享

      很少有应用能很好地支持不起眼的android.resource 方案。另外,EXTRA_STREAM is documented to take a content Uri,而不是 android.resource Uri

      任何线索是如何做到的?

      将原始资源复制到internal storage 上的文件中,例如getCacheDir() 中。您可以使用通过调用getResources()Context 获得的Resources 对象来访问原始资源(使用openRawResource())。然后,configure FileProvider 从那里服务,并使用FileProvider.getUriForFile() 获得UriACTION_SEND 一起使用。请务必在Intent 上添加FLAG_GRANT_READ_URI_PERMISSION

      This sample Java app(和its Kotlin equivalent)演示了基本技术。就我而言,我将 PDF 存储为资产,而不是将 MP3 存储为原始资源,因此这部分需要进行一些细微的调整。

      或者,您可以从头开始编写自己的ContentProvider 来提供原始资源,然后在您的Intent 中使用该提供商支持的Uri

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-27
        • 1970-01-01
        • 1970-01-01
        • 2018-06-30
        • 2017-02-07
        • 2011-12-20
        • 1970-01-01
        相关资源
        最近更新 更多