Обмен текстом / простой строкой через 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 Решение в ответе Хуана станет неполным.

Другие вопросы по тегам