有任何想法吗?
Android Beam 使用 Beam Uri
数组中的第一个文件的文件扩展名在内部映射表中查找相应的 MIME 类型,然后将其与通过蓝牙对象推送配置文件(OPP)启动文件传输的 Intent
一起发送。
如果未找到文件扩展名或匹配的 MIME 类型,则 Intent
的 MIME 类型将设置为null
,并且根本不会启动蓝牙 OPP 文件传输。
解决方法
当发送一个扩展名不在
MimeUtils
列表中的文件时,请使用一个包含两个元素的Beam
Uri
数组:
uris[0]
:一个带有
.txt
扩展名的虚拟文本文件(稍后将被删除)
uris[1]
:您要传输的文件(具有不被识别的扩展名)
在您的特定情况下:
adapter.setBeamPushUris(
new Uri[] { dummyTxtFileUri, data.getData() },
this);
Android Beam会向蓝牙发送一个MIME类型为
text/plain
的意图,同时传递两个文件的
Uri
以及蓝牙OPP文件传输将正常进行。请注意,当一次传输多个文件时,接收设备将把文件存储在
beam/
子目录中,通常命名为
beam-YYYY-MM-DD/
。
背景
我比较了发送设备上发送具有
.json
扩展名的文件和该文件的副本具有
.txt
扩展名之间的日志。首先值得注意的区别在这里:
日志:传输
test.json
03-02 13:19:34.665: D/BluetoothOppHandover(32332): Handing off outging transfer to BT
日志:正在传输 test.txt
03-02 15:32:19.437: D/BluetoothOppHandover(3268): Handing off outging transfer to BT
03-02 15:32:19.445: D/BluetoothOppUtility(3309): putSendFileInfo: uri=file:///storage/emulated/0/Download/test.txt@2cb672fa sendFileInfo=com.android.bluetooth.opp.BluetoothOppSendFileInfo@2cb672fa
搜索AOSP中的“将传出转移交给BT”:
platform/packages/apps/Nfc/src/com/android/nfc/handover/BluetoothOppHandover.java
void sendIntent() {
Intent intent = new Intent();
intent.setPackage("com.android.bluetooth");
String mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, mUris[0]);
intent.setType(mimeType);
if (DBG) Log.d(TAG, "Handing off outging transfer to BT");
mContext.sendBroadcast(intent);
complete();
}
在继续之前,请注意仅将数组中的第一个Uri
的MIME类型发送到Intent
中。根据MimeTypeUtil.getMimeTypeForUri()
的结果:
platform/packages/apps/Nfc/src/com/android/nfc/handover/MimeTypeUtil.java
public static String getMimeTypeForUri(Context context, Uri uri) {
String extension = MimeTypeMap.getFileExtensionFromUrl(uri.getPath()).toLowerCase();
if (extension != null) {
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
} else {
return null;
}
因此,如果它无法识别扩展名,则会将null
作为MIME类型返回。在执行MimeTypeMap.getSingleton().getMimeTypeFromExtension()
之后...
frameworks/base/core/java/android/webkit/MimeTypeMap.java
public String getMimeTypeFromExtension(String extension) {
return MimeUtils.guessMimeTypeFromExtension(extension);
}
platform/libcore/luni/src/main/java/libcore/net/MimeUtils.java
public final class MimeUtils {
private static final Map<String, String> mimeTypeToExtensionMap = new HashMap<String, String>();
private static final Map<String, String> extensionToMimeTypeMap = new HashMap<String, String>();
public static String guessMimeTypeFromExtension(String extension) {
if (extension == null || extension.isEmpty()) {
return null;
}
return extensionToMimeTypeMap.get(extension);
}
在继续之前,请注意 MimeUtils
类 包含 Android 可识别的 MIME 类型列表。它是一个很好的参考。
我们使用 extensionToMimeTypeMap.get()
到达了堆栈的末尾:
platform/libcore/luni/src/main/java/java/util/HashMap.java
public V get(Object key) {
因此,如果没有找到匹配项,则最终将MIME类型返回为
null
。更深入的挖掘表明,这在以下情况下很重要:
platform/packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
@Override
public void onReceive(Context context, Intent intent) {
if (action.equals(Constants.ACTION_HANDOVER_SEND)) {
String type = intent.getType();
Uri stream = (Uri)intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (stream != null && type != null) {
BluetoothOppManager.getInstance(context).saveSendingFileInfo(type,
stream.toString(), true);
} else {
if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
}
BluetoothOppManager.getInstance(context).startTransfer(device);
由于在保存文件信息和开始传输之前对MIME类型进行了空值检查,因此蓝牙OPP文件传输从未启动。请注意,当存在null时,其他两个条件块都会返回,因此似乎这个条件块在
Log.d()
调用后缺少一个
return
可能是一个bug。
.json
文件只是在结尾处使用了不同的扩展名的.txt
文件。就是这样。 - gatlingxyz