Android Создание резидентного входного файла памяти, который может быть прикреплен к электронной почте

Конечная цель будет понятна в ближайшее время.

Я хочу создать файл-объект и вместо того, чтобы получать данные из реального физического файла, я хочу сам предоставить буфер.

Затем я хочу использовать этот файл, который на самом деле не существует в SD-карте или где-либо вне моего приложения, дайте ему имя и отправьте его по электронной почте в виде вложения (используя EXTRA_STREAM).

Я нашел следующий бит кода: Adriaan Koster (@adriaankoster), пост Write byte [] для файла в Java

// convert byte[] to File
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
File fileFromBytes = (File) ois.readObject();
bis.close();
ois.close();

System.out.println(fileFromBytes);

Я использовал его для создания этой функции

private File fileFromBytes(byte[] buf) {
    File f = null;
    try {
        ByteArrayInputStream bis = new ByteArrayInputStream(buf);
        ObjectInputStream ois = new ObjectInputStream(bis);
        f = (File) ois.readObject();
        bis.close();
        ois.close();
    }
    catch (Exception e) {}
    return f;
}

и вот где я застреваю, потому что когда я его использую:

// When sent as body the mail is sent OK
// emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, dump());

// When I try to attach the mail is empty
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, fileFromBytes(dump().getBytes()));

Я знаю из примеров, которые я видел, второй аргумент должен быть URI, но: Как создать URI виртуальный, чтобы соответствовать моему файлу?

EDIT: Возможность прикрепления данных непосредственно из приложения важна для определенных приложений. А именно, приложения безопасности и банковского обслуживания, которые не хотят слишком сильно перемещать конфиденциальные данные. Разумеется, если данные не доходят до SD-карты и переходят непосредственно в почтовую вставку, ее сложнее нюхать, чем в памяти приложения.
Это не мой конкретный случай, но я хотел бы указать, что эта возможность важна.

Ответ 1

Первое, что вы захотите сделать, я думаю, это создать ContentProvider. Вы можете увидеть пример реализации здесь

https://github.com/dskinner/AndroidWeb/blob/master/src/org/tsg/web/WebContentProvider.java

где в приведенном выше примере ссылки вы добавили бы это в свой AndroidManifest.xml

<provider
    android:name="org.tsg.web.WebContentProvider"
    android:authorities="your.package.name" />

Теперь у вас будет доступный uri для контента, content://your.package.name/.

Часть вышеприведенного ContentProvider, которого вы заинтересовали, я полагаю, это метод openFile. При совместном использовании данных по намерениям в приложениях ожидаются определенные вещи. В вашем случае вы хотите поделиться некоторыми байтовыми данными, которые должны быть прикреплены к электронной почте.

Итак, если вы передадите контент uri в приложение электронной почты, например content://your.package.name/foo, с соответствующими флагами намерений, тогда openFile будет вызываться на вашем ContentProvider. В этом случае вы можете проверить конец сегмента uri, чтобы увидеть, что запрос foo был запрошен, и вернуть его соответствующим образом.

Следующая проблема, которую вы вызываете, - это отсутствие файла на диске. Хотя я не могу ручаться за метод, который вы использовали выше (хотя он выглядит кошерным), то, что вам нужно вернуть, это ParcelFileDescriptor из вашего ContentProvider. Если вы посмотрите на ссылку, которую я предоставил, вы можете попробовать использовать это как образец, чтобы получить дескриптор файла из вашего объекта File (мои знания об отказе здесь), но я полагаю, что данные просто не будут доступны в этом пункте.

То, что вы делаете, это безопасность. Важно отметить, что вы можете записывать данные на диск конфиденциально, так что только приложение имеет доступ к данным. Я полагаю, но вы можете дважды проверить это, если эти данные являются приватными для приложения, вы можете открыть его через ContentProvider и, возможно, заблокировать, кто и как поставщик будет использоваться, кто может его назвать и т.д. Вы можете захотите вникнуть в андроидные документы для этой части или посмотреть на некоторые другие вопросы SO.

В любом случае, удачи.

Ответ 2

Создайте файл в каталоге кэша приложений. Он будет создан во внутренней файловой системе. Используйте API getCacheDir() для получения пути к директории кеша. Запишите данные в этот каталог, а затем получите URI из объекта File с помощью "Uri.fromFile(File file)". Когда вы закончите с файлом, удалите его.

Кэш приложений доступен только для вашего приложения, следовательно, он безопасен для использования в ваших целях.

Вы можете сделать некоторое шифрование, если данные слишком критичны.

Ответ 3

Я думаю, для этого вам придется разоблачить ContentProvider, который позволит вам обрабатывать URI. Затем приложение электронной почты должно открытьInputStream в вашем URI, после чего вы возвращаете InputStream в свои данные в памяти.

Я не пробовал, но теоретически это должно работать.