【问题标题】:Xamarin app crashes when discovering BLE peripherals发现 BLE 外围设备时 Xamarin 应用程序崩溃
【发布时间】:2015-06-25 17:52:27
【问题描述】:

我正在 Xamarin 中制作一个跨平台应用程序,目前我正忙于尝试启动并运行一个简单的 BLE 扫描。该应用程序崩溃得很丑,我已将问题符号化并追查到文件“mini-exceptions.c”的第 2360 行。

基本上,它说;

find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
{  
    int i;
    gpointer ip;
    FindHandlerBlockData *pdata = data;
    MonoJitInfo *ji = frame->ji;

    if (!ji)
        return FALSE;

所以,简而言之;我错过了“MonoJitInfo”,返回 false 进而引发异常,我完成了。

但是——我不明白。为什么是这种“单声道”的东西?我正在为新的 Xamarin Unified 开发,而 AFAIK 项目中没有任何经典 MonoTouch 材料的单一参考?

我是 Xamarin 新手,所以我正在尽我最大的努力把拼图放在一起......

至于我的应用程序,当我创建我的 CBCentralManager 以使用“DefaultGlobalQueue”时发生崩溃,但是当我将 MainQueue 用作 DispatchQueue 时我没有遇到任何崩溃——但我也没有发现任何外围设备所以我猜这与我的 DispatchQueue 相关......?

我想我迷路了……任何提示都受到高度重视。 Xamarin.iOS 中的 CoreBluetooth 是否需要 Mono?

编辑;

在我的原生崩溃之前,我实际上遇到了一个严重错误,而且我也看到了一些奇怪的单点触控引用...;

critical: Stacktrace:
critical:   at <unknown> <0xffffffff>
critical:   at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <0xffffffff>
critical:   at UIKit.UIApplication.Main (string[],intptr,intptr) [0x00005] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:62
critical:   at UIKit.UIApplication.Main (string[],string,string) [0x0001c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:45
critical:   at iOSMyApp.Application.Main (string[]) [0x00008] in /Users/markus/Xamarin/MyApp/iOS/iOSMyApp/Main.cs:17
critical:   at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) <0xffffffff> 

编辑 -- 使用代码 sn-ps

我的 BLE 实现是 iOS 原生类,它在管理所有业务逻辑的共享项目设置中实现接口。

我尝试了两种 lambda 变体;

private CBCentralManager Central;

readonly AutoResetEvent stateChanged = new AutoResetEvent (false);
async Task WaitForState (CBCentralManagerState state)
{
    Console.WriteLine ("Waiting for state: " + state);

    while (Central.State != state) {
        await Task.Run (() => stateChanged.WaitOne ());
    }
}

internal NativeBleCentralTransport ()
{
    Central = new CBCentralManager (DispatchQueue.MainQueue);

    Central.DiscoveredPeripheral += (object sender, CBDiscoveredPeripheralEventArgs e) => {
        Console.WriteLine ("DiscoveredPeripheral: " + e.Peripheral.Name);
    };

    Central.UpdatedState += (object sender, EventArgs e) => {
        Console.WriteLine ("UpdatedState: " + Central.State);
        stateChanged.Set();
    };

    Central.ConnectedPeripheral += (object sender, CBPeripheralEventArgs e) => {
        Console.WriteLine ("ConnectedPeripheral: " + e.Peripheral.Name);
    };

    Central.DisconnectedPeripheral += (object sender, CBPeripheralErrorEventArgs e) => {
        Console.WriteLine ("DisconnectedPeripheral: " + e.Peripheral.Name);
    };

    Central.FailedToConnectPeripheral += (object sender, CBPeripheralErrorEventArgs e) => {
    };
}

public async Task<bool> SetupTransport ()
{
    //Wait for state...
    WaitForState(CBCentralManagerState.PoweredOn);

    //Scan for *any* peripheral at the moment...
    CBUUID[] uuids = null;
    Central.ScanForPeripherals (uuids);

    //Wait for things to happen...
    await Task.Delay (10000);

    return true;
}

...和其他“扩展CBCentralManagerDelegate类”的方法;

internal class NativeBleCentralTransport : CBCentralManagerDelegate, ISessionTransport
{
    private CBCentralManager BleManager;

    internal NativeBleCentralTransport ()
    {
        //Create BLE manager and hook-up ourselves as delegate
        BleManager = new CBCentralManager(this, DispatchQueue.MainQueue);
    }

    public async Task<bool> SetupTransport ()
    {
        //The manager will automatically kick "UpdateState" for us to indicate the status of the native BLE-interface (e.g., enabled or disabled?),
        //so let's just sit back and await completion of discovery

        Task.Delay (10000);

        return true;
    }

    #region BLE delegate overrides

    override public void UpdatedState (CBCentralManager mgr)
    {
        //State change occured! Let's see if we should start 
        if (BleManager.State == CBCentralManagerState.PoweredOn) 
        {
            CBUUID[] uuids = null;
            BleManager.ScanForPeripherals (uuids);
        } 
    }

    public override void DiscoveredPeripheral (CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
    {
        Console.WriteLine ("Discovered: " + peripheral.Name);
    }

    #endregion
}

问题总结

这个想法本质上是,当设置 transport (SetupTransport) 时,BLE 接口应该启动并通过阻塞调用线程来发现/连接到外围设备直到它完成并准备好采取行动。

但是——当我的应用在 iOS 原生端发现外围设备时,它会崩溃。不在我的代码中——我从来没有在控制台上看到我的调试消息,但我在符号化本机崩溃日志时发现了它......

所以,本质上;我没有做任何奇怪的事情,我会说它非常直截了当,但它是一个共享项目设置,这是我的第一个 Xamarin 项目,这让我对术语不太满意。我正在使用 Unity API。我目前怀疑这实际上是一个项目设置/约束/引用的东西,因此我正在重建一个新的测试项目,它不是一个共享项目,而是一个原生 iOS 的东西,只是为了看看我可以做一个简单的 BLE 发现而不会崩溃,然后我想我会从那里拿走它。

感谢任何见解和建议! /马库斯

结果

我在 Xamarin 中做了一个测试解决方案,只有一个项目;一个单页iOS模板的东西,只是在视图控制器的“DidAppear”方法中添加了我的类,一切正常......

因此,这不是代码/语法问题(除非有我不知道的共享项目设置规则?),而是共享项目问题/Xamarin-设置问题。关于如何设置共享项目的任何建议。有经验的一双眼睛可以通过查看碰撞痕迹找到任何缺失的参考资料吗?

【问题讨论】:

    标签: xamarin xamarin.ios core-bluetooth


    【解决方案1】:

    问题解决了。是的,它与共享项目设置有关,更具体地说,我的 BLE 本机传输类的创建位置

    事实证明,CBCentralManager 必须由主线程创建,我从具有 async 属性的函数创建了一个实例。

    因此,只需将我的 NativeBleCentralTransport 实例作为应用程序启动时创建的私有变量,并在我的 async 函数中使用该对象引用,一切正常(这也是为什么当我创建一个原生 iOS 项目时一切都运行良好的原因,因为我只是直接从 ViewDidAppear 函数蛮力玩了一个 NativeBleCentralTransport 的实例。

    【讨论】:

      猜你喜欢
      • 2018-04-29
      • 2012-07-29
      • 2011-04-08
      • 2023-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-18
      相关资源
      最近更新 更多