Обмен текстом / простой строкой через Bluetooth преобразует данные в HTML
Я пытаюсь отправить простой текст через Bluetooth, но он где-то конвертируется в HTML.
Код, который я использую в основном это:
String content = "This is just a test";
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, content);
sendIntent.setType("text/plain");
String title = "Share with…";
startActivity(Intent.createChooser(sendIntent, title));
Когда я запускаю этот код и выбираю опцию Bluetooth, файл отправляется на удаленную систему с именем "bluetooth_content_share.html" и с таким содержимым:
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/></head><body>This is just a test</body></html>
Я пробовал звонить setType
перед добавлением EXTRA_TEXT
без изменения симптомов. Другие действия общего доступа (например, "Добавить в Dropbox") получают данные в виде простого текста. И я смог использовать другие приложения (например, "ES File Explorer") для успешной отправки простых текстовых файлов через Bluetooth.
Как я могу получить данные для отправки в виде простого текста, как я просил?
2 ответа
Я не мог заснуть, поэтому я решил взглянуть на stackru, чтобы узнать, есть ли что-нибудь интересное в теге android. Этот вопрос казался достаточно простым, но он оказался очень интересным, поскольку, как вы заметили в вопросе, он просто создает чертов HTML-файл со строкой в качестве содержимого.
Я предположил, что Bluetooth-связь хочет работать с файлами, и что Android выводит, что наш текст был html, даже если вы четко указали обычный текст.
Решение, которое я придумал, заключается в том, чтобы заставить приложение поделиться текстовым файлом, вместо того, чтобы делиться тестом. String
, Я был в состоянии проверить это и ваш код тоже, и я смог повторить волшебное создание HTML-файла. Это должно помочь вам.
Обновление Из-за опасений по поводу оставления файла в хранилище и невозможности использования временного файла, я обновил код для добавления FileObserver
к файлу, который позволяет нам отслеживать, когда файл изменяется и какой тип действия он испытывает. В этом случае все, что нам нужно для мониторинга, это FileObserver.CLOSE_NOWRITE
действие, которое будет инициировано только при обращении к файлу для его отправки и после того, как он завершит работу с ним. Устранение файла после него.
try {
//Create a file and write the String to it
BufferedWriter out;
final String filePath = Environment.getExternalStorageDirectory().getPath() + "/wadus.txt";
FileWriter fileWriter = new FileWriter(filePath);
out = new BufferedWriter(fileWriter);
out.write("I know you'll love me for finding the solution");
out.close();
//Access the file and share it through the original intent
File file = new File(filePath);
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
sendIntent.setType("text/plain");
String title = "Share with…";
//Create a file observer to monitor the access to the file
FileObserver fobsv = new FileObserver(filePath) {
@Override
public void onEvent(int event, String path) {
if (event == FileObserver.CLOSE_NOWRITE) {
//The file was previously written to, now it's been sent and closed
//we can safely delete it.
File file = new File(filePath);
file.delete();
}
}
};
fobsv.startWatching();
//Launch sharing intent
startActivity(Intent.createChooser(sendIntent, title));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Если кому-то интересно, почему мы устанавливаем FileObserver
это далеко внизу кода, чтобы избежать его запуска при создании и редактировании самого файла. Поскольку мы добавили после того, как файл был записан, мы будем запускать только те события, которые требуются для его отправки по Bluetooth (в данном случае).
TL;DR: Вы должны либо создать файл, либо реализовать ContentProvider и отправить его как EXTRA_STREAM
, но это ломает другие приложения, которые хотят получать данные в виде текста через EXTRA_TEXT
, Можно реализовать исключение для приложения "Bluetooth Share" с помощью EXTRA_REPLACEMENT_EXTRAS
,
Мне удалось найти этот код в исходном коде приложения Bluetooth для Android ( com / android / bluetooth / opp / BluetoothOppLauncherActivity.java):
if (action.equals(Intent.ACTION_SEND)) {
final String type = intent.getType();
final Uri stream = (Uri)intent.getParcelableExtra(Intent.EXTRA_STREAM);
CharSequence extra_text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT);
if (stream != null && type != null) {
// clipped
} else if (extra_text != null && type != null) {
if (V) Log.v(TAG, "Get ACTION_SEND intent with Extra_text = "
+ extra_text.toString() + "; mimetype = " + type);
final Uri fileUri = creatFileForSharedContent(this, extra_text);
// clipped
} else {
Log.e(TAG, "type is null; or sending file URI is null");
finish();
return;
}
Так что если есть EXTRA_TEXT
и нет EXTRA_STREAM
, а затем отправить его creatFileForSharedContent()
, который, в свою очередь, содержит это:
String fileName = getString(R.string.bluetooth_share_file_name) + ".html";
context.deleteFile(fileName);
/*
* Convert the plain text to HTML
*/
StringBuffer sb = new StringBuffer("<html><head><meta http-equiv=\"Content-Type\""
+ " content=\"text/html; charset=UTF-8\"/></head><body>");
// Escape any inadvertent HTML in the text message
String text = escapeCharacterToDisplay(shareContent.toString());
// Regex that matches Web URL protocol part as case insensitive.
Pattern webUrlProtocol = Pattern.compile("(?i)(http|https)://");
Pattern pattern = Pattern.compile("("
+ Patterns.WEB_URL.pattern() + ")|("
+ Patterns.EMAIL_ADDRESS.pattern() + ")|("
+ Patterns.PHONE.pattern() + ")");
// Find any embedded URL's and linkify
Matcher m = pattern.matcher(text);
while (m.find()) {
//clipped
}
m.appendTail(sb);
sb.append("</body></html>");
Другими словами, приложение Bluetooth явно преобразует все, что отправлено в виде текста, в HTML. Спасибо, Android!
Только две вещи, которые приложение Bluetooth примет как EXTRA_STREAM
Содержимое: и файл: URI ( com / android / bluetooth / opp / BluetoothOppSendFileInfo.java):
if ("content".equals(scheme)) {
//clipped
} else if ("file".equals(scheme)) {
//clipped
} else {
// currently don't accept other scheme
return SEND_FILE_INFO_ERROR;
}
Итак, пытаемся отправить данные: URI не работает.
Это означает, что вам нужно либо создать файл, либо реализовать ContentProvider. Просто чтобы отправить какой-нибудь чертов текст!
Но это может нарушить совместное использование с другими приложениями, которые хотят получать данные через EXTRA_TEXT
метод. К счастью, можно создать EXTRA_STREAM
который предоставляется только приложению Bluetooth Share с помощью EXTRA_REPLACEMENT_EXTRAS
:
String content = "This is just a test";
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, content);
sendIntent.setType("text/plain");
String title = "Share with…";
Intent shareChooser = Intent.createChooser(sendIntent, title);
// Add Bluetooth Share-specific data
try {
// Create file with text to share
final File contentFile = new File(getActivity().getExternalCacheDir(), "plain.txt");
FileWriter contentFileWriter = new FileWriter(contentFile, false);
BufferedWriter contentWriter = new BufferedWriter(contentFileWriter);
contentWriter.write(content);
contentWriter.close();
Uri contentUri = Uri.fromFile(contentFile);
Bundle replacements = new Bundle();
shareChooser.putExtra(Intent.EXTRA_REPLACEMENT_EXTRAS, replacements);
// Create Extras Bundle just for Bluetooth Share
Bundle bluetoothExtra = new Bundle(sendIntent.getExtras());
replacements.putBundle("com.android.bluetooth", bluetoothExtra);
// Add file to Bluetooth Share's Extras
bluetoothExtra.putParcelable(Intent.EXTRA_STREAM, contentUri);
} catch (IOException e) {
// Handle file creation error
}
startActivity(shareChooser);
Тем не менее, вам все равно придется обрабатывать удаление файла, что становится более сложным, когда пользователь выбирает для обмена что-то, кроме Bluetooth, так как файл никогда не будет открыт, что делает FileObserver
Решение в ответе Хуана станет неполным.