- 现象:使用下面的代码发送文件报错
ContentValues cv = new ContentValues();
String uri = "file://"
+ mSendFileNameTV.getText().toString().trim();
cv.put("uri", uri);
cv.put("destination",
mTouchObject.bluetoothDevice.getAddress());
cv.put("direction", 0);
Long ts = System.currentTimeMillis();
cv.put("timestamp", ts);
getContentResolver()
.insert(Uri
.parse("content://com.android.bluetooth.opp/btopp"),
cv);
报错内容如下:
java.lang.SecurityException: Permission Denial: writing com.android.bluetooth.opp.BluetoothOppProvider uri
content://com.android.bluetooth.opp/btopp from pid=8004, uid=10066 requires android.permission.ACCESS_BLUETOOTH_SHARE,
or grantUriPermission()
- 根据提示在AndroidManifest.xml中添加如下权限,但是无效
<uses-permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE" />
- 查找ACCESS_BLUETOOTH_SHARE的来历,找到如下,发现其android:protectionLevel为"signature"
packages/apps/Bluetooth/AndroidManifest.xml
<!-- Allows access to the Bluetooth Share Manager -->
<permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE"
android:label="@string/permlab_bluetoothShareManager"
android:description="@string/permdesc_bluetoothShareManager"
android:protectionLevel="signature" />
- 查找资料,发现android:protectionLevel的定义如下:
a. normal:这是最低风险的权限,如果应用声明了此权限,也不会提示安装应用的用户授权(例如,如果声明了定位权限,则应用到定位功能时,会明确提示用户,是否授予定位权限,但是 protectionLevel 为 normal 的不会明确提示,直接默认授予),系统直接默认该应用有此权限;
b. dangerous:这种级别的权限风险更高,拥有此权限可能会访问用户私人数据或者控制设备,给用户带来负面影响,这种类型的权限一般不会默认授权(但是我测了好多次,有时候还是会默认授权);
c. signature:这种权限级别,只有当发请求的应用和接收此请求的应用使用同一签名文件,并且声明了该权限才会授权,并且是默认授权,不会提示用户授权
d. signatureOrSystem:这种权限应该尽量避免使用,偏向系统级
- 查找系统bluetooth.apk的签名
查看系统SDK/packages/apps/Bluetooth的Android.mk,发现其签名文件为platform
LOCAL_CERTIFICATE := platform
- 使用SDK中的platform.x509.pem和platform.pk8签名程序,异常报错消失。
**PS:**虽然报错解决,但是最后依旧没发送成功,分析了下,发现此方法调用的时候不会调用BluetoothOppUtility::putSendFileInfo,而直接调用BluetoothOppUtility::getSendFileInfo,导致读取文件的时候,发现文件名不存在,从而提示“蓝牙发送未知文件:文件不存在”