通过 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 通过蓝牙接收文件的主要内容,如果未能解决你的问题,请参考以下文章

蓝牙的OBEX协议

使用 Bluez-obex 和 pydbus 的 Python opp obex 服务器?

带有 IOKit 的 USB 上的 OBEX

Android 蓝牙使用 OBEX 发送私有/内部文件

OBEX OPP 特定转账

通过 bluez 浏览文件