且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

通过蓝牙共享文本/纯文本字符串将数据转换为HTML

更新时间:2023-02-03 08:15:59

TL; DR::您必须创建文件或实现ContentProvider并将其作为EXTRA_STREAM发送,但这会中断其他想要通过EXTRA_TEXT以文本形式接收数据的应用程序.通过使用EXTRA_REPLACEMENT_EXTRAS,可以为蓝牙共享"应用实现例外.

TL;DR: You either have to create a file or implement a ContentProvider and send it as EXTRA_STREAM, but this breaks other apps that want to receive the data as text via EXTRA_TEXT. It's possible to implement an exception for the "Bluetooth Share" app by using EXTRA_REPLACEMENT_EXTRAS.

我能够在Android蓝牙应用程序的源代码中找到此代码(

I was able to find this code in the source for the Android Bluetooth app (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(),该文件又包含以下内容:

So if there's EXTRA_TEXT and no EXTRA_STREAM, then send it to creatFileForSharedContent(), which, in turn contains this:

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

换句话说,蓝牙应用程序将任何以文本形式发送的内容显式转换为HTML.谢谢,Android!

In other words, the Bluetooth app explicitly converts anything sent as text to HTML. Thanks, Android!

蓝牙应用程序将接受为EXTRA_STREAM的仅有两件事是内容:和文件:URI(

The only two things that the Bluetooth app will accept as an EXTRA_STREAM are content: and file: URIs (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不起作用.

So trying to send a data: URI doesn't work.

这意味着您必须创建文件或实现ContentProvider. 只发送一些该死的纯文本!

This means you either have to create a file or implement a ContentProvider. Just to send some damned plain text!

但这可能会中断与其他希望通过EXTRA_TEXT方法接收数据的应用程序的共享.幸运的是,可以使用EXTRA_REPLACEMENT_EXTRAS创建一个仅提供给Bluetooth Share应用程序的EXTRA_STREAM:

But this has the potential to break sharing with other apps that want to receive the data via the EXTRA_TEXT method. Fortunately, it's possible to create an EXTRA_STREAM that is only provided to the Bluetooth Share app by using 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);

但是,您仍然必须处理删除文件,当用户选择蓝牙以外的其他内容与之共享时,这将变得更加复杂,因为该文件将永远不会打开,这使得Juan回答中的FileObserver解决方案变得不完整.

You still have to handle deleting the file, though, which becomes more complicated when the user chooses something other than Bluetooth to share with, since the file will never be opened, making the FileObserver solution in Juan's answer become incomplete.