Android 蓝牙无法发送或接收某些类型文件

embedded/2024/9/25 2:31:36/

Android 蓝牙应用使得用户能够在蓝牙设备之间进行文件传输。用户可以通过蓝牙连接两台设备,并在它们之间传输文件,如照片、音乐、视频等。这对于用户来说是非常便利的,无需使用数据线或互联网连接,可以直接在附近的设备之间进行文件共享。

文章目录

  • 1. 蓝牙无法发送某些类型文件
  • 2. 蓝牙无法接收某些类型文件
  • 3. 蓝牙权限问题

从 Andorid 13 后蓝牙模块位置从 packages/apps/Bluetooth/变成了 packages/modules/Bluetooth

server@dev-fj-srv:/work/AndrodU/packages/modules/Bluetooth/android/app$ tree -L 1
.
|-- Android.bp
|-- AndroidManifest.xml
|-- OWNERS
|-- app.iml
|-- certs
|-- jni
|-- lib
|-- proguard.flags
|-- res
|-- services
|-- src
|-- tests
`-- tools8 directories, 5 files

1. 蓝牙无法发送某些类型文件

原生蓝牙的ACTION_SEND_MULTIPLEACTION_SEND二种action分享类型做了限制,所以会导致部分类型的文件无法通过蓝牙分享,为了解除这种限制,可以将数据类型设置成*/*,即<data android:mimeType="*/*" />

packages/modules/Bluetooth/android/app/AndroidManifest.xml

<activity android:name="com.android.bluetooth.opp.BluetoothOppLauncherActivity"android:process="@string/process"android:theme="@style/opp_launcher_activity"android:label="@string/bt_share_picker_label"android:enabled="false"android:exported="true"><intent-filter><action android:name="android.intent.action.SEND"/><category android:name="android.intent.category.DEFAULT"/><!-- @{ support sending all types of files.<data android:mimeType="image/*"/><data android:mimeType="video/*"/><data android:mimeType="audio/*"/><data android:mimeType="text/x-vcard"/><data android:mimeType="text/x-vcalendar"/><data android:mimeType="text/calendar"/><data android:mimeType="text/plain"/><data android:mimeType="text/html"/><data android:mimeType="text/xml"/><data android:mimeType="application/zip"/><data android:mimeType="application/vnd.ms-excel"/><data android:mimeType="application/msword"/><data android:mimeType="application/vnd.ms-powerpoint"/><data android:mimeType="application/pdf"/><data android:mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"/><data android:mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document"/><data android:mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation"/><data android:mimeType="application/x-hwp"/>--><data android:mimeType="*/*" /><!-- @} --></intent-filter><intent-filter><action android:name="android.intent.action.SEND_MULTIPLE"/><category android:name="android.intent.category.DEFAULT"/><!-- @{ support sending all types of files.<data android:mimeType="image/*"/><data android:mimeType="video/*"/><data android:mimeType="x-mixmedia/*"/><data android:mimeType="text/x-vcard"/>--><data android:mimeType="*/*" /><!-- @} --></intent-filter><intent-filter><action android:name="android.btopp.intent.action.OPEN"/><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="vnd.android.cursor.item/vnd.android.btopp"/></intent-filter>
</activity>

2. 蓝牙无法接收某些类型文件

log 报错分析

04-20 19:27:10.928 23480 12218 D BtOppObexClient: Start!
04-20 19:27:11.031 23480 12224 D BtOppObexClient: Create ClientSession with transport com.android.bluetooth.BluetoothObexTransport@c894e88
04-20 19:27:11.227 23480 12224 D BtOppObexClient: OBEX session created
04-20 19:27:11.808 23480 12224 I BtOppObexClient: Remote reject, Response code is 207
04-20 19:27:11.810 23480 12224 I BtOppObexClient: Remote reject file type application/vnd.android.package-archive
04-20 19:27:11.810 23480 12224 I BtOppObexClient: Response error code is 207
04-20 19:27:11.824 23480 12224 D BtOppObexClient: Client thread waiting for next share, sleep for 500
04-20 19:27:11.825 23480 12218 D BtOppObexClient: Stop!
04-20 19:27:11.917 23480 12224 D BtOppObexClient: OBEX session disconnected
04-20 19:27:12.932 23480 12231 D BtOppObexClient: Stop!

BtOppObexClient: Remote reject file type application/vnd.android.package-archive 根据log信息找到代码位置:src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java

@VisibleForTesting
int sendFile(BluetoothOppSendFileInfo fileInfo) {
...} else if (responseCode == ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE) {Log.i(TAG, "Remote reject file type " + fileInfo.mMimetype);status = BluetoothShare.STATUS_NOT_ACCEPTABLE;} 
...
}

src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java 中的 public int onPut(Operation op)

// Reject anything outside the "acceptlist" plus unspecified MIME Types.
if (mimeType == null || (!isAcceptlisted && !Constants.mimeTypeMatches(mimeType,Constants.ACCEPTABLE_SHARE_INBOUND_TYPES))) {if (D) {Log.w(TAG, "mimeType is null or in unacceptable list, reject the transfer");}return ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE;
}

此处定义了常量Constants.ACCEPTABLE_SHARE_INBOUND_TYPES,来过滤可接收的文件类型的mimeType

/*** The MIME type(s) of we could accept from other device.* This is in essence a "acceptlist" of acceptable types.* Today, restricted to images, audio, video and certain text types.*/
static final String[] ACCEPTABLE_SHARE_INBOUND_TYPES = new String[]{"image/*","video/*","audio/*","text/x-vcard","text/x-vcalendar","text/calendar","text/plain","text/html","text/xml","application/epub+zip","application/zip","application/vnd.ms-excel","application/msword","application/vnd.ms-powerpoint","application/pdf","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.openxmlformats-officedocument.presentationml.presentation","application/x-hwp",
};

因此,如果需要接收所有文件类型,可以修改此ACCEPTABLE_SHARE_INBOUND_TYPES

static final String[] ACCEPTABLE_SHARE_INBOUND_TYPES = new String[]{"*/*"
};

3. 蓝牙权限问题

部分应用的图片无法通过蓝牙分享,蓝牙通知显示文件传输失败:未知文件,无法正确处理请求。log输出报错如下:

12-02 02:12:22.290  5046  6302 E DatabaseUtils: Writing exception to parcel
12-02 02:12:22.290  5046  6302 E DatabaseUtils: java.lang.SecurityException: com.android.bluetooth has no access to content://media/external/images/media/1000000037
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at com.android.providers.media.MediaProvider.enforceCallingPermissionInternal(MediaProvider.java:10014)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at com.android.providers.media.MediaProvider.enforceCallingPermission(MediaProvider.java:9911)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at com.android.providers.media.MediaProvider.checkAccess(MediaProvider.java:10035)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at com.android.providers.media.MediaProvider.openFileAndEnforcePathPermissionsHelper(MediaProvider.java:8294)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at com.android.providers.media.MediaProvider.openFileCommon(MediaProvider.java:7901)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at com.android.providers.media.MediaProvider.openTypedAssetFileCommon(MediaProvider.java:7969)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at com.android.providers.media.MediaProvider.openTypedAssetFile(MediaProvider.java:7913)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:562)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:327)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at android.os.Binder.execTransactInternal(Binder.java:1285)
12-02 02:12:22.290  5046  6302 E DatabaseUtils: 	at android.os.Binder.execTransact(Binder.java:1244)

log表明蓝牙无法获取此媒体文件,缺少权限,由于Android 13后新增了媒体文件的细分权限,蓝牙的AndroidManifest.xml中没有添加这些细分权限,遇到的images文件出现的此问题,添加READ_MEDIA_IMAGES权限后测试成功。

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

STATUS_OBEX_DATA_ERROR:由于在 OBEX 级别接收或处理数据时出现错误,因此无法完成此传输。

/*** Get status description according to status code.*/
public static String getStatusDescription(Context context, int statusCode, String deviceName) {String ret;if (statusCode == BluetoothShare.STATUS_PENDING) {ret = context.getString(R.string.status_pending);} else if (statusCode == BluetoothShare.STATUS_RUNNING) {ret = context.getString(R.string.status_running);} else if (statusCode == BluetoothShare.STATUS_SUCCESS) {ret = context.getString(R.string.status_success);} else if (statusCode == BluetoothShare.STATUS_NOT_ACCEPTABLE) {ret = context.getString(R.string.status_not_accept);} else if (statusCode == BluetoothShare.STATUS_FORBIDDEN) {ret = context.getString(R.string.status_forbidden);} else if (statusCode == BluetoothShare.STATUS_CANCELED) {ret = context.getString(R.string.status_canceled);} else if (statusCode == BluetoothShare.STATUS_FILE_ERROR) {ret = context.getString(R.string.status_file_error);} else if (statusCode == BluetoothShare.STATUS_ERROR_NO_SDCARD) {int id = deviceHasNoSdCard()? R.string.status_no_sd_card_nosdcard: R.string.status_no_sd_card_default;ret = context.getString(id);} else if (statusCode == BluetoothShare.STATUS_CONNECTION_ERROR) {ret = context.getString(R.string.status_connection_error);} else if (statusCode == BluetoothShare.STATUS_ERROR_SDCARD_FULL) {int id = deviceHasNoSdCard() ? R.string.bt_sm_2_1_nosdcard : R.string.bt_sm_2_1_default;ret = context.getString(id);} else if ((statusCode == BluetoothShare.STATUS_BAD_REQUEST) || (statusCode== BluetoothShare.STATUS_LENGTH_REQUIRED) || (statusCode== BluetoothShare.STATUS_PRECONDITION_FAILED) || (statusCode== BluetoothShare.STATUS_UNHANDLED_OBEX_CODE) || (statusCode== BluetoothShare.STATUS_OBEX_DATA_ERROR)) {ret = context.getString(R.string.status_protocol_error);} else {ret = context.getString(R.string.status_unknown_error);}return ret;
}

无法查询到传输的文件信息,所以显示为未知文件。

if (info.mFileName == null) {info.mFileName = context.getString(R.string.unknown_file);
}

http://www.ppmy.cn/embedded/12935.html

相关文章

filebeat 设置elasticsearch索引的 max_result_window

在 Filebeat 中设置索引的 max_result_window 需要修改 Elasticsearch 的索引模板。max_result_window 参数定义了在 Elasticsearch 中执行搜索时&#xff0c;最大返回文档的数量。默认情况下&#xff0c;该值为 10000。 答案来着gpt demo&#xff1a;http://124.220.104.235/ …

Linux 安装 JDK

通过 Yum 安装&#xff08;推荐&#xff09; 确保系统包列表是最新的。这将帮助确保安装的是最新版本的软件包。 sudo yum update -y确定要安装哪个 JDK 版本&#xff1a; yum list java*确定 Linux 系统架构&#xff1a; [rootlavm-zzgegfex4j ~]# uname -a Linux lavm-zz…

热门婴儿洗衣机希亦、小吉、鲸立测评对比!实验室客观实测!

随着大家生活的提高&#xff0c;越来越多人追求品质化生活。从洗衣服这件基础小事中就能看出&#xff0c;从比较早的解放双手&#xff0c;到追求衣物的洗护&#xff0c;再到近些年来&#xff0c;大人小孩衣服分区洗衣的精致生活理念。如今&#xff0c;洗衣机市场根据消费者的需…

深入了解 Gitea:轻量级的自托管 Git 服务

在软件开发和团队协作中&#xff0c;版本控制系统是不可或缺的工具。Git 是目前最流行的分布式版本控制系统之一&#xff0c;而 Gitea 则是基于 Git 的一个轻量级、自托管的 Git 服务。本文将介绍 Gitea 的特点、功能和使用方法&#xff0c;帮助读者更好地了解和使用这一工具。…

JAVA学习-行为抽象和Lambda.流

一、行为抽象与Lambda 1. 行为抽象&#xff1a; 行为抽象是指将方法作为参数传递给其他方法&#xff0c;从而实现将方法作为一种行为进行传递与调用的能力。在Java中&#xff0c;行为抽象常常使用接口来定义具体的行为。 2. Lambda表达式&#xff1a; Lambda表达式是Java 8…

YOLOv8 训练自己的数据集(20240423)

环境搭建请参考&#xff1a;Win10 搭建 YOLOv8 运行环境&#xff08;20240423&#xff09;-CSDN博客 环境测试请参考&#xff1a;本地运行测试 YOLOv8&#xff08;20240423&#xff09;-CSDN博客 一、使用 YOLOv8 的 coco128 数据集熟悉一下如何训练和预测 1.1、在项目根目录…

CSS3新增特性(二)

四、2D 转换 • 属性名&#xff1a;transform &#xff08;可用于制作2D转换&#xff0c;也可用于制作3D转转换&#xff1b;2D转换是平面上的转换&#xff0c;3D转换是在三维立体空间的转换&#xff09; • 作用&#xff1a;对元素进行水平或垂直方向的移动、缩放、旋转、拉长…

Spring AOP 切面编程

1.切面编程 无需改变原有类的情况下对业务功能实现扩展或增强。 2.目前最流行的AOP框架有两个&#xff0c;分别为Spring AOP 和 AspectJ。 3.Spring AOP使用纯java实现&#xff0c;不需要专门的编译过程和类加载器&#xff0c;在运行期间通过代理方式向目标类织入增强的代码。 …