Android поделиться аудиофайлом из папки активов

Я не могу поделиться аудиофайлом из ресурсов. Каждое приложение говорит, что не может отправить файл.

Метод преобразования входного потока во временный файл

    public File getFile(String Prefix, String Suffix) throws IOException {

    File tempFile = File.createTempFile(Prefix, Suffix);
    AssetFileDescriptor tempafd = FXActivity.getInstance().getAssets().openFd(filepath);
    tempFile.deleteOnExit();
    FileOutputStream out = new FileOutputStream(tempFile);
    IOUtils.copy(tempafd.createInputStream(), out);


    return tempFile;
}

Общий доступ к файлу

        item2.setOnAction(n ->{
            try {
                Uri uri = Uri.fromFile(tekst.getFile(tekst.getFilename(), ".mp3"));
                Intent share = new Intent();
                share.setType("audio/*");
                share.setAction(Intent.ACTION_SEND);
                share.putExtra(Intent.EXTRA_STREAM, uri);
                FXActivity.getInstance().startActivity(share);
            } catch (IOException ex) {
                Logger.getLogger(MainCategoryCreator.class.getName()).log(Level.SEVERE, null, ex);
            }

        });

person siemaeniu500    schedule 18.11.2016    source источник
comment
Можете ли вы проверить, существует ли файл tekst.getFilename().mp3. Я имею в виду, что ваш временный файл существует или нет, и проверьте размер файла, чтобы убедиться, что он не поврежден?   -  person Raghavendra    schedule 18.11.2016
comment
Да, он существует, потому что он имеет тот же размер, что и исходный из активов.   -  person siemaeniu500    schedule 18.11.2016
comment
@Raghavendra, так что может быть причиной этого?   -  person siemaeniu500    schedule 18.11.2016
comment
Можете ли вы сказать мне, где вы создаете временный файл? Можете ли вы опубликовать образец пути?   -  person Raghavendra    schedule 18.11.2016
comment
Вы проверили этот ответ? Я не уверен, что создание временного файла во внешней общей папке может работать.   -  person José Pereda    schedule 18.11.2016
comment
Я не размещаю временный файл ни в каком каталоге. Я должен сначала импортировать активы во внешнее хранилище.   -  person siemaeniu500    schedule 18.11.2016
comment
Я протестировал аудиофайл, помещенный в папку ресурсов приложения, а временный файл создается в локальном частном пути приложения. Распечатай Ури и увидишь. Это не может быть доступно извне.   -  person José Pereda    schedule 18.11.2016
comment
Поэтому мне нужно поместить временный файл во внешний каталог.   -  person siemaeniu500    schedule 18.11.2016
comment
Да и нет: не обязательно во внешнем хранилище, но, по крайней мере, во внутренней папке с файлами (через Context.getFilesDir()). Оттуда в мире Android есть сложные средства для обмена вашим контентом. Смотрите мой ответ ниже.   -  person dzim    schedule 02.12.2016


Ответы (1)


Так случилось, что я столкнулся с почти такой же проблемой: мне нужно было поделиться видеофайлом. Проблема в том, что теперь есть способ поделиться внутренним файлом. Никогда. Вам либо нужен ContentProvider, либо, поскольку с ним немного проще, это расширение FileProvider.

Во-первых: вам нужно обновить вас AndroidManifest.xml:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="my.package.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

Это нужно добавить в <application>tag.

Затем вам нужен файл XML file_paths.xml в подкаталоге Android res/xml/

Должно получиться что-то вроде этого:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="objects" path="objects/"/>
</paths>

И чтобы, наконец, запустить его, мне нужно было вызвать его так:

Uri uri = Uri.parse("content://my.package.fileprovider/" + fn); 
Intent intent = new Intent(Intent.ACTION_VIEW, uri); // or parse uri each time
intent.setDataAndType(uri, "video/*"); // all video type == * - alternative: mp4, ...
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_GRANT_READ_URI_PERMISSION);
List<ResolveInfo> resInfoList = FXActivity.getInstance().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
    String packageName = resolveInfo.activityInfo.packageName;
    FXActivity.getInstance().grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
FXActivity.getInstance().startActivity(intent);

Но что мне нужно было сделать, чтобы иметь возможность использовать его следующим образом: мне нужно было скопировать все активы в каталог личных файлов, потому что сам FileProvider не имеет возможности доступа к вашим активам (я думаю, вы могли бы добиться этого с помощью пользовательского ContentProvider , но я нашел способ сложным и не имел столько времени).

Дополнительные сведения см. в этом справочнике для разработчиков Android по FileProvider. .

Мое простое решение для этого выглядит так:

public boolean copyAssetsToStorage() throws NativeServiceException {
    try {
        String[] assets = getContext().getAssets().list(DIR_NAME);
        if (assets == null || assets.length == 0) {
            LOG.warning("No assets found in '" + DIR_NAME + "'!");
            return false;
        }
        File filesDir = getContext().getFilesDir();
        File targetDir = new File(filesDir, DIR_NAME);
        if (!targetDir.isDirectory()) {
            boolean b = targetDir.mkdir();
            if (!b) {
                LOG.warning("could not create private directory with the name '" + DIR_NAME + "'!");
                return false;
            }
        }
        for (String asset : assets) {
            File targetFile = new File(targetDir, asset);
            if (targetFile.isFile()) {
                LOG.info("Asset " + asset + " already present. Nothing to do.");
                continue;
            } else {
                LOG.info("Copying asset " + asset + " to private files.");
            }
            InputStream is = null;
            OutputStream os = null;
            try {
                is = getContext().getAssets().open(DIR_NAME + "/" + asset);
                os = new FileOutputStream(targetFile.getAbsolutePath());
                byte[] buff = new byte[1024];
                int len;
                while ((len = is.read(buff)) > 0)
                    os.write(buff, 0, len);
            } catch (IOException e) {
                LOG.log(Level.SEVERE, e.getMessage(), e);
                continue;
            }
            if (os != null) {
                os.flush();
                os.close();
            }
            if (is != null)
                is.close();
        }
        return true;
    } catch (IOException e) {
        LOG.log(Level.SEVERE, e.getMessage(), e);
        return false;
    }
}

Как видите, я пока поддерживаю только плоскую иерархию...

По крайней мере, это помогло мне.

С уважением, Даниэль


ДОПОЛНИТЕЛЬНЫЙ ВОПРОС. Почему вы отправляете намерение, а не реализуете простой элемент управления аудиопроигрывателем JavaFX? Это то, что я делал до видео материала.

person dzim    schedule 02.12.2016