通过 OBEX Object PushProfile 通过蓝牙接收文件
Posted
技术标签:
【中文标题】通过 OBEX Object PushProfile 通过蓝牙接收文件【英文标题】:Receive file by Bluetooth via OBEX Object PushProfile 【发布时间】:2012-08-17 18:24:35 【问题描述】:我的设备使用 OBEX 对象推送配置文件 (OPP) 通过蓝牙发送数据。
使用 adb logcat 我看到我的 android 设备收到了一个连接(但中止了这个连接?)
08-22 11:14:37.939: I/BtOppRfcommListener(22586): Accepted connectoin from 00:07:CF:5F:52:A0
08-22 11:14:37.939: I/BtOpp Service(22586): Start Obex Server
08-22 11:14:38.109: D/Obex ServerSession(22586): java.io.IOException: Software caused connection abort
08-22 11:14:38.109: D/PowerManagerService(180): @PowerManagement: 'BtOppObexServer' releaseWakeLock when screen locked
08-22 11:14:39.219: D/BluetoothEventLoop(180): Device property changed: 00:07:CF:5F:52:A0 property: Connected value: false
当我安装蓝牙文件传输(市场上的免费应用程序)时,我就可以接收文件了。 但我不想安装其他应用程序。
【问题讨论】:
您能否发布有问题的代码,以便有关 SO 的 android 专家可以查看该问题? 这有帮助吗? ***.com/questions/3625959/… @domsom 我已经尝试过类似的代码但没有成功。 IMO 的问题似乎是本机蓝牙仍在接受传入的 OPP 数据并且自定义代码没有被触发。因此,该解决方案不仅涉及侦听传入连接,还涉及向本机蓝牙“注册”,以便调用自定义 OPP 处理程序。 @DavidO'Meara 我同意:如果监听蓝牙套接字/通道绑定到系统服务,你不能重新注册到你自己的代码(它只能绑定一次,你无法从您的无根应用程序中终止系统服务)。据我所知(但实际上没有搜索过),您也无法使用系统服务注册“传入的 OBEX 传输”事件。这就是为什么链接中的人想出了适用于他的特定场景(即知道远程设备)的解决方法。 【参考方案1】:我相信我有(至少是部分)解决方案,然后应该允许通过 OPP 拦截文件并添加自定义代码。第一步是进入设置>应用>运行>蓝牙共享并杀死BluetoothOppService
然后我使用反射访问BluetoothAdapter
(下面的代码)上的一个方法,该方法允许侦听特定端口。之后我们可以拦截传入的 OPP 通信并与输入和输出流进行交互。 This SO 线程将帮助 OPP 通信部分,但作为初始步骤,我读取数据流并回复 OPP 'OK' 消息,即os.writeByte(ObexSession.OBEX_SUCCESS | ObexSession.OBEX_FINAL_BIT);
// simplified exception handling
public class BluetoothAdapterProxy
public static final int CHANNEL_OPP = 12;
final BluetoothAdapter target;
static final Class<?> targetClass = BluetoothAdapter.class;
Method listenOn;
public BluetoothAdapterProxy(BluetoothAdapter target)
this.target = target;
Class<?>[] args = new Class[] int.class ;
try
this.listenOn = targetClass.getDeclaredMethod(
"listenUsingRfcommOn", args);
catch (NoSuchMethodException e)
e.printStackTrace();
public BluetoothServerSocket listenUsingRfcommOn(int channel)
try
return (BluetoothServerSocket) (listenOn.invoke(target,
new Object[] channel ));
catch (Exception e)
// complain loud, complain long
throw new RuntimeException(ex);
用法:初始化使用
serverSocket = new BluetoothAdapterProxy(BluetoothAdapter.getDefaultAdapter())
.listenUsingRfcommOn(BluetoothAdapterProxy.CHANNEL_OPP);
之后,使用单独的Thread
中的以下内容(以防止阻塞),远程设备可以通过socket = serverSocket.accept();
进行连接
【讨论】:
我不明白为什么你需要一个包装类,但无论如何:你可以使用公共的BluetoothDevice.listenUsingRfcommWithServiceRecord()
方法,使用 OPP UUID 00001105-0000-1000-8000-00805f9b34fb
。您问题的关键可能是另一个(系统)服务已经在侦听 OBEX 频道。所以要么你可以接受你所说的“杀死”解决方案,要么你使用系统服务并像这里一样监控它:***.com/questions/3625959/…
包装类用于从“隐藏的 android api”访问方法,该代码在运行时可见,但从已发布的 API 和 android.jar 中排除。我有大量测试代码来探测已发布的 API - 侦听不是问题,但是没有一个试验使自定义代码能够响应外部 OPP 数据。
我还应该提到发布的示例代码不是一个完整的解决方案,因为我发现它在不同设备上的行为仍然不同。它能够在我的 HTC One X 上通过 OPP 接收数据,但在三星 Nexus S 和 Galaxy Tab 2 上表现不同,而且并不完全成功。
“不完全成功”是什么意思?您是否查看了现有的蓝牙 OPP 资源(例如 grepcode.com/file/repository.grepcode.com/java/ext/…)?
@domsom 忽略这一点,我昨天做了更多测试,看来上述解决方案中的不一致是由远程设备上的旧固件引起的。更新固件后,我能够验证上述解决方案是否适用于我们所有可用的设备。以上是关于通过 OBEX Object PushProfile 通过蓝牙接收文件的主要内容,如果未能解决你的问题,请参考以下文章