I implemented push notifications in android work will, in ios token return but when try to test notifications not received, no error return to fix and didn't know what the problem please any help
I use this plugin to implement firebase Plugin.FirebasePushNotification Version 3.4.35 Xamarin.Forms Version 5.0.0.2515
this Code in
Add GoogleService-Info.plist file make build action BundleResources
Mark in Entitlements.plist push notifications to enable
Mark in info.plist Enable BackgroundMode (Remote notification), Add
<key>FirebaseAppDelegateProxyEnabled</key> <false/>
in Shared project add this
CrossFirebasePushNotification.Current.RegisterForPushNotifications();
CrossFirebasePushNotification.Current.OnTokenRefresh += (s, p) =>
{
System.Diagnostics.Debug.WriteLine($"TOKEN : {p.Token}");
if (p.Token != null)
{
AppData.Token = p.Token;
Api.CustomerService.UpdateTokenbynumber();
}
};
CrossFirebasePushNotification.Current.OnNotificationReceived += (s, p) =>
{
System.Diagnostics.Debug.WriteLine("Received");
System.Console.WriteLine($"**********Received : ");
};
CrossFirebasePushNotification.Current.OnNotificationOpened += (s, p) =>
{
System.Diagnostics.Debug.WriteLine("Opened");
};
CrossFirebasePushNotification.Current.OnNotificationAction += (s, p) =>
{
System.Diagnostics.Debug.WriteLine("Action");
};
CrossFirebasePushNotification.Current.OnNotificationError += (s, p) =>
{
System.Diagnostics.Debug.WriteLine("Errrrrrrroooooooorrrr");
};
this Code in AppDelegate
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Xamarin.FormsGoogleMaps.Init("AIzaSyAFh07QpEGWHSecHRTxImrctCZAge0WK5o");
Xamarin.Forms.Forms.SetFlags("IndicatorView_Experimental");
Rg.Plugins.Popup.Popup.Init();
global::Xamarin.Forms.Forms.Init();
Firebase.Core.App.Configure();
Plugin.LocalNotification.LocalNotificationCenter.RequestNotificationPermission();
FirebasePushNotificationManager.Initialize(options, true);
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
FirebasePushNotificationManager.DidRegisterRemoteNotifications(deviceToken);
Console.WriteLine($"Firebase registration token: {AppData.Token}");
}
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
FirebasePushNotificationManager.RemoteNotificationRegistrationFailed(error);
}
// To receive notifications in foregroung on iOS 9 and below.
// To receive notifications in background in any iOS version
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired 'till the user taps on the notification launching the application.
// If you disable method swizzling, you'll need to call this method.
// This lets FCM track message delivery and analytics, which is performed
// automatically with method swizzling enabled.
FirebasePushNotificationManager.DidReceiveMessage(userInfo);
// Do your magic to handle the notification data
System.Console.WriteLine(userInfo);
completionHandler(UIBackgroundFetchResult.NewData);
}
}
this log data
2022-11-21 14:17:32.772818+0200 Najd.iOS[17253:179449] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSNumber' (0x7ff863b6e4d0) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework]' for key 'NS.keys', even though it was not explicitly included in the client allowed classes set: '{(
"'NSMutableSet' (0x7ff863b571d0) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]",
"'GDTCOREvent' (0x1019a5168) [/Users/raitotec/Library/Developer/CoreSimulator/Devices/D39EF3A7-186B-4AA8-B1B6-7068F966D261/data/Containers/Bundle/Application/6E5BD3FC-B9A7-41F2-95D4-99EE7783B900/Najd.iOS.app/Frameworks/GoogleDataTransport.framework]",
"'N
SMutableDictionary' (0x7ff863b585f8) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future.
Thread started: <Thread Pool> #2
Thread started: <Thread Pool> #3
Thread started: <Thread Pool> #4
Thread started: <Thread Pool> #5
Loaded assembly: /Users/raitotec/Library/Developer/CoreSimulator/Devices/D39EF3A7-186B-4AA8-B1B6-7068F966D261/data/Containers/Bundle/Application/6E5BD3FC-B9A7-41F2-95D4-99EE7783B900/Najd.iOS.app/ar/Najd.resources.dll [External]
2022-11-21 14:18:11.996099+0200 Najd.iOS[17253:180223] 6.22.0 - [Firebase/Core][I-COR000003] The default Firebase app has not yet been configured. Add `[FIRApp configure];` (`FirebaseApp.configure()` in Swift) to your application initialization.
2022-11-21 14:18:12.071362+0200 Najd.iOS[17253:180223] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSString' (0x7ff863b6d698) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework]' for key 'NS.keys', even though it was not explicitly included in the client allowed classes set: '{(
"'NSDictionary' (0x7ff863b589e0) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]",
"'NSDate' (0x7ff863b58878) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This w
ill be disallowed in the future.
Thread started: #7
2022-11-21 14:18:19.031547+0200 Najd.iOS[17253:179449] **********TOKEN : er8MQGevkkV7rSosJS9_NP:APA91bETxB3GAJQxR728lmHm9rMTaa3jS06nXFDkNcdXJ7pkEi1t3JwxSzqyYk8nH5k90UgZ16WtxDmrzuCA81AzsnTOdh6h_fkVtkmZCgYbaU0cMW1yAJl-K2qSfIlOYbzT0MXBYqU-
2022-11-21 14:18:19.287594+0200 Najd.iOS[17253:180223] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSString' (0x7ff863b6d698) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework]' for key 'NS.keys', even though it was not explicitly included in the client allowed classes set: '{(
"'NSDictionary' (0x7ff863b589e0) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]",
"'NSDate' (0x7ff863b58878) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This w
ill be disallowed in the future.
2022-11-21 14:18:19.336678+0200 Najd.iOS[17253:180330] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x6000031ee540> F8BB1C28-BAE8-11D6-9C31-00039315CD46
2022-11-21 14:18:19.339800+0200 Najd.iOS[17253:179942] 6.22.0 - <AppMeasurement>[I-ACS800023] No pending snapshot to activate. SDK name: app_measurement
Things to look out for
Make sure your APN's Authentication key is set up on your Firebase console
Test on the device. It won't work on the simulator
The bundle Action for the GoogleService-info-plist is set to "BundleResource"
Related
I'm trying to implement One Signal in Nativescript. I use nativescript-onesignal plugin for that. It works on android but doesn't work on iOS. I give these errors in sidekick console:
ERROR: Encountered error during push registration with OneSignal: Error Domain=OneSignal Error Code=403 "(null)" UserInfo={returned=Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}}
ERROR: Encountered error during email registration with OneSignal: (null)
as long as there are these errors, One Signal can't detect my device as a subscriber.
has anybody an idea that how to implement that for iOS?
I don't know how I should solve that. any idea?
This is my main.ts file:
// this import should be first in order to load some required settings (like globals and reflect-metadata)
import { platformNativeScriptDynamic } from "nativescript-angular/platform";
import { AppModule } from "./app/app.module";
import * as application from "tns-core-modules/application";
const TnsOneSignal = require("nativescript-onesignal").TnsOneSignal;
// A traditional NativeScript application starts by initializing global objects, setting up global CSS rules, creating, and navigating to the main page.
// Angular applications need to take care of their own initialization: modules, components, directives, routes, DI providers.
// A NativeScript Angular app needs to make both paradigms work together, so we provide a wrapper platform object, platformNativeScriptDynamic,
// that sets up a NativeScript application and can bootstrap the Angular framework.
console.log("main starts");
if (application.ios) {
class MyDelegate extends UIResponder implements UIApplicationDelegate {
public static ObjCProtocols = [UIApplicationDelegate];
public applicationDidFinishLaunchingWithOptions(app: UIApplication, launchOptions: NSDictionary<any, any>): boolean {
try {
console.log("TnsOneSignal", TnsOneSignal);
// init to recieve push notification
TnsOneSignal.initWithLaunchOptionsAppId(launchOptions, "b2fdda95*********");
// I have not yet implemented the part of receiving notifications in ios, when I have it I will publish it
} catch (error) {
console.log("TnsOneSignal error", error);
}
return true;
}
}
application.ios.delegate = MyDelegate;
}
if (application.android) {
application.on(application.launchEvent, function(args: application.ApplicationEventData) {
try {
console.log("TnsOneSignal", TnsOneSignal);
TnsOneSignal.ini(application.android.context).init()
} catch (error) {
console.error("error", error)
}
});
}
platformNativeScriptDynamic().bootstrapModule(AppModule);
After some days, Finally, I found what the problem was! it was fixed by using a VPN.
On iOS, I only can check state of Bluetooth. I'm find the solutions on network and use it.
public class CallBluetoothIphoneService : ICallBlueTooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager();
if (bluetoothManager.State == CBCentralManagerState.PoweredOff|| bluetoothManager.State == CBCentralManagerState.Unknown)
// Does not go directly to bluetooth on every OS version though, but opens the Settings on most
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
But when I try turn off Bluetooth and test code, state of bluetooth is "Unknown".
Then I run code, device open settings, toggle button has color green (turn on bluetooth), but when I check state of Bluetooth in code, State of Bluetooth is "Unknown", is not "Power on".
I'm using Xamarin 3.3 and test on device iOS version 12.0.
I am not sure exactly what you want to do, but if your intent is to open the Bluetooth settings page, this:
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
won't work. Apple has at some points allowed this (iOS 8 IIRC) and at other points it has disallowed this (most versions of iOS). See this long SO thread about this issue: How to open Settings programmatically like in Facebook app?
Regardless, there is no need. When iOS detects that your app has created a CBCentralManager type with delegate, iOS will display an alert to the user that allows them to go to the bluetooth settings to enable bluetooth by tapping the "Settings" button in the alert.
As far as always getting state as "Unknown", you need to check the state in the delegate for the CBCentralManager. You cannot use the parameterless CBCentralManager constructor new CBCentralManager();. Check the apple docs: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager?language=objc and note that there are only two listed init methods, one that takes delegate and queue parameters, and one that takes delegate, queue, and options parameters, although no one complains if you use the parameterless constructor... but you will never get the correct state if you use it. See: https://stackoverflow.com/a/36824770/2913599
So try this:
public class CallBluetoothIphoneService : ICallBluetooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager(new MySimpleCBCentralManagerDelegate(), DispatchQueue.CurrentQueue);
// This will always show state "Unknown". You need to check it in the delegate's UpdatedState method
Console.WriteLine($"State: {bluetoothManager.State.ToString()}");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public class MySimpleCBCentralManagerDelegate : CBCentralManagerDelegate
{
override public void UpdatedState(CBCentralManager mgr)
{
// You can check the state in this delegate method
Console.WriteLine($"UpdatedState: {mgr.State.ToString()}");
if (mgr.State == CBCentralManagerState.PoweredOn)
{
//Passing in null scans for all peripherals. Peripherals can be targeted by using CBUIIDs
CBUUID[] cbuuids = null;
mgr.ScanForPeripherals(cbuuids); //Initiates async calls of DiscoveredPeripheral
//Timeout after 30 seconds
var timer = new Timer(30 * 1000);
timer.Elapsed += (sender, e) => mgr.StopScan();
}
else
{
//Invalid state -- Bluetooth powered down, unavailable, etc.
System.Console.WriteLine("Bluetooth is not available");
}
}
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
Console.WriteLine("Discovered {0}, data {1}, RSSI {2}", peripheral.Name, advertisementData, RSSI);
}
}
Bottom line: always create a CBCentralManager object with one of the following constructors:
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue)
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue, CBCentralInitOptions)
I'm trying to implement google sign in using this component for xamarin.ios: Google Sign-in for iOS
It works great on emulator but when it comes to actual device it's crashing once i tap signin button. (iOS 10.2 - emulator is also using same OS)
I have a custom button which calls SignInUser method on SignIn.SharedInstance
It's crashing with below error (only when the app is deployed on device)
Objective-C exception thrown. Name: NSInvalidArgumentException Reason: uiDelegate must either be a |UIViewController| or implement the |signIn:presentViewController:| and |signIn:dismissViewController:| methods from |GIDSignInUIDelegate|.
I'm calling function below to initialize GoogleSignIn on FinishedLaunching method of AppDelegate.cs
public void Configure()
{
NSError configureError;
Context.SharedInstance.Configure(out configureError);
if (configureError != null)
{
// If something went wrong, assign the clientID manually
Console.WriteLine("Error configuring the Google context: {0}", configureError);
SignIn.SharedInstance.ClientID = googleClientId;
}
SignIn.SharedInstance.Delegate = this;
SignIn.SharedInstance.UIDelegate = new GoogleSignInUIDelegate();
}
Here's my implementation of ISignInUIDelegate():
class GoogleSignInUIDelegate : SignInUIDelegate
{
public override void WillDispatch(SignIn signIn, NSError error)
{
}
public override void PresentViewController(SignIn signIn, UIViewController viewController)
{
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(viewController, true, null);
}
public override void DismissViewController(SignIn signIn, UIViewController viewController)
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
}
}
So the emulator seems to know the methods are implemented, but not the device. Any idea what i am doing wrong here?
After some debugging i found where the actual issue was.
Somehow, the UIDelegate i assigned during initialization was lost when i was calling my login method. So i moved the line below from my initialization step to login
SignIn.SharedInstance.UIDelegate = new GoogleSignInUIDelegate();
Here's how my login method looks like now:
public void Login()
{
SignIn.SharedInstance.UIDelegate = new GoogleSignInUIDelegate(); //moved this here from Configure
SignIn.SharedInstance.SignInUser();
}
This took care of the issue for me but i am still not sure why this is only an issue on the device and not the emulator. Any Ideas?
Add a PreserveAttribute to your GoogleSignInUIDelegate class to prevent the Linker from removing the methods that can not be determined via static analysis.
Add the following class to your project:
public sealed class PreserveAttribute : System.Attribute {
public bool AllMembers;
public bool Conditional;
}
Apply the class attribute:
[Preserve (AllMembers = true)]
class GoogleSignInUIDelegate : SignInUIDelegate
{
~~~~
}
Re: https://developer.xamarin.com/guides/ios/advanced_topics/linker/
Setting PresentingViewController helped me to resolve the issue.
SignIn.SharedInstance.PresentingViewController = this;
Have found such fix here:
https://github.com/googlesamples/google-signin-unity/issues/169#issuecomment-791305225
I need to use the iOS 10 features in UNUserNotificationCenterDelegate. How can I implement this delegate in c# / Xamarin?
When using the an UNUserNotificationCenterDelegate, make sure that you assign it in the WillFinishLaunching or the FinishedLaunching methods in your app's UIApplicationDelegate.
You must assign your delegate object to the UNUserNotificationCenter object no later before your app finishes launching.
Ref: UNUserNotificationCenterDelegate
AppDelegate.cs Example
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>
{
// Handle the user approval or refusal of your notifications...
});
UNUserNotificationCenter.Current.Delegate = new MyUNUserNotificationCenterDelegate();
return true;
}
In that example, I am creating/assigning a delegate class named MyUNUserNotificationCenterDelegate, so you need to implement that class.
MyUNUserNotificationCenterDelegate class example:
This UNUserNotificationCenterDelegate example will capture each local notification sent and toggle between showing it on the lock screen or outputting the details to the syslog.
public class MyUNUserNotificationCenterDelegate : UNUserNotificationCenterDelegate
{
bool toggle;
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
if (toggle)
completionHandler(UNNotificationPresentationOptions.Alert);
else
{
Console.WriteLine(notification);
completionHandler(UNNotificationPresentationOptions.None);
}
toggle = !toggle;
}
}
Now you will actually need to send some notifications, this sets up a simple repeating notification:
Create/Schedule Local Notification:
// Schedule a repeating Notification...
var content = new UNMutableNotificationContent();
content.Title = new NSString("From SushiHangover");
content.Body = new NSString("StackOverflow rocks");
content.Sound = UNNotificationSound.Default;
var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(timeInterval: 60, repeats: true);
var request = UNNotificationRequest.FromIdentifier(identifier: "FiveSecond", content: content, trigger: trigger);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (NSError error) =>
{
if (error != null) Console.WriteLine(error);
});
Every 60 seconds a notification is dispatched and if you are on the lock screen you will receive an alert every 120 seconds...
Recommend reading to understand how you Xamarin.iOS/C# to interact with delegates, protocols, and events:
iOS uses Objective-C delegates to implement the delegation pattern, in which one object passes work off to another. The object doing the work is the delegate of the first object. An object tells its delegate to do work by sending it messages after certain things happen. Sending a message like this in Objective-C is functionally equivalent to calling a method in C#. A delegate implements methods in response to these calls, and so provides functionality to the application.
Ref: Xamarin.iOS and Delegates
I'm making a cross-platform app in Xamarin and currently I'm stuck in trying to get a simple BLE scan up and running. The app crashes ugly, and I've symbolized and hunted the issue down to the file "mini-exceptions.c", line 2360.
Basically, it says;
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;
So, in short; I'm missing the "MonoJitInfo", returning false which in turn throws an exception and I'm done.
But -- I don't get it. Why this "mono"-stuff? I'm developing for the new Xamarin Unified, and AFAIK there's not a single reference in the project to any classic MonoTouch-stuff?
I'm a Xamarin newbie so I'm trying me best to put the puzzle together here...
As for my application, and crash occurs when I create my CBCentralManager to use the "DefaultGlobalQueue", but I'm not getting any crash when I use the MainQueue as DispatchQueue -- but I'm not getting any discovered peripherals either so I'm guessing that it's something related to my DispatchQueue...?
I'm lost, I guess... Any hints are highly valued. Does CoreBluetooth in Xamarin.iOS require Mono?
EDIT;
I'm actually getting a critical error before my native crash, and I see some strange mono-touch references in there too...;
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>
Edit -- with code snippets
My BLE implementation is the iOS-native class implementing an interface in a shared-project setup where all the business-logic is managed.
I've tried both a lambda-variant;
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;
}
... and the other "extend CBCentralManagerDelegate class"-approach;
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
}
Problem summary
The idea is essentially that when a transport is setup (SetupTransport), the BLE interface should kick-in and discover/connect to a peripheral by blocking the invoking thread until it's done and ready for action.
But -- my app crashes when it discovers a peripheral on the iOS-native side. Not in my code -- I never see my debug-messages on the Console, but I've found it when symbolizing the native crash logs...
So, essentially; I'm not doing anything strange, it very straight-forward I'd say, BUT it is a shared-project setup and it's my first Xamarin-project, which makes me less comfortable with the terminology.. I'm using the Unity API. I'm currently suspecting that this is actually a project-setup/constraint/reference-thing and I'm therefore rebuilding a new test-project which is NOT a shared project but a native iOS-thing just to see that I can make a simple BLE discovery without crashing and then I'll take it from there I guess.
Any insights and suggestions are appreciated!
/Markus
Results
I did a test-solution in Xamarin, with only one project; a single-page iOS-template thing and just added my class in the "DidAppear" method in the View-controller, and everything works...
Hence, this is NOT a code/syntax-issue (unless there are rules that I'm not aware of for shared-project setups?), but a shared-project issue/Xamarin-setup issue. Any recommendations out there on how to setup a shared-project. Any missing references that an experienced pair of eyes can find by looking at the crash-traces?
Problem solved. Yes, it was related to shared-project setup and more specifically where my BLE native transport class was created.
Turns out, the CBCentralManager must be created by the main-thread, and I created an instance from a function with async attribute.
So by simply putting my NativeBleCentralTransport instance as a private variable created when the app boot-up, and use that object reference in my async function, everything works (which is also why everything worked nicely when I created a native iOS-project since I just brute-force played with an instance of NativeBleCentralTransport directly from the ViewDidAppear function.