Check Bluetooth status in Xamarin Forms on iOS - ios

I have created a xamarin forms application. I want to check if the status of the bluetooth in iOS. I have used the below code, but the if (state == CBCentralManagerState.PoweredOn) is returning me Unknown. It is not providing the actual status of bluetooth state. Could somebody please help me to figure out what is wrong ? Thanks.
The reference of this method is here : https://developer.xamarin.com/api/type/MonoMac.CoreBluetooth.CBCentralManagerState/
private CBCentralManagerState state;
public bool CheckBluetoothStatus()
{
bool status;
if (state == CBCentralManagerState.PoweredOn)
{
status= true;
}
else
{
status = false;
}
return status;
}

As described here in apple documentation, you need to initialise CBCentralManager before you can actually use it.
If you look at Xamarin Documentation for CBCentralManager, they provide you a list of all constructors it takes. Implement the 2nd one from the bottom
CBCentralManager(CBCentralManagerDelegate, DispatchQueue, CBCentralInitOptions)
But before you implement this, you need to implement the CBCentralManagerDelegate. It could be as simple as this
public class CbCentralDelegate : CBCentralManagerDelegate
{
public override void UpdatedState(CBCentralManager central)
{
if(central.State == CBCentralManagerState.PoweredOn)
{
System.Console.WriteLine("Powered On");
}
}
}
Now that you have implemented the delegate, you should be able to fetch the state of the bluetooth from the CBCentralManager like this
var bluetoothManager = new CBCentralManager(new CbCentralDelegate(),DispatchQueue.DefaultGlobalQueue,
new CBCentralInitOptions{ShowPowerAlert = true});
return bluetoothManager.State == CBCentralManagerState.PoweredOn;
I know its been a while since this was asked, but hopefully this will help you.(Or anyone else)

You should subscript the UpdatedState event in CBCentralManager
_mgr = new CBCentralManager();
_mgr.UpdatedState += CBCentralManager_UpdatedState;
void CBCentralManager_UpdatedState(object sender, EventArgs e){
switch (_mgr.State)
}

Related

Update jetpcak composable when a static class member changes

I have a Paho MQTT connection, with a callback updating a object and i need to update a coposable..
I can see the in Logcat that i receive information, but the composable is not updated.
I am suspecting that the issue is that i am using a static object and it is not mutable. What is the practice on this scenario? I did not implement a ViewModel. It could be done with a timer, but i think it is not an elegant solution.
snippet:
object MyCallBack : MqttCallback {
public var message = ""
override fun messageArrived(topic: String?, message: MqttMessage?) {
this.message = message.toString()
Log.e(ContentValues.TAG,"mqtt Arrived: $message")
}
......
}
and a composable function used to display the information:
#Composable
fun ShowMessage() {
var myCallBack = MyCallBack //here i can access the updated information
var message by remember {
mutableStateOf(myCallBack.message)
Text("Changed ${myCallBack.message}", color = Color.White)
}
}
Thank you!
i have tried to use mutableStateOf() but it did not called for composition, i think it is not observable.

.NET MAUI Accessing Apple Healthkit

I would like to access iOS Healthkit, eventually Android too but cannot find out a successful way to do it. Online I've seen advice pointing to https://learn.microsoft.com/en-us/xamarin/ios/platform/healthkit which is for xamarin and not MAUI, but the methods in the example are not found. This is the code:
private HKHealthStore healthKitStore = new HKHealthStore ();
public override void OnActivated (UIApplication application)
{
ValidateAuthorization ();
}
private void ValidateAuthorization ()
{
var heartRateId = HKQuantityTypeIdentifierKey.HeartRate;
var heartRateType = HKObjectType.GetQuantityType (heartRateId);
var typesToWrite = new NSSet (new [] { heartRateType });
var typesToRead = new NSSet ();
healthKitStore.RequestAuthorizationToShare (
typesToWrite,
typesToRead,
ReactToHealthCarePermissions);
}
void ReactToHealthCarePermissions (bool success, NSError error)
{
var access = healthKitStore.GetAuthorizationStatus (HKObjectType.GetQuantityType (HKQuantityTypeIdentifierKey.HeartRate));
if (access.HasFlag (HKAuthorizationStatus.SharingAuthorized)) {
HeartRateModel.Instance.Enabled = true;
} else {
HeartRateModel.Instance.Enabled = false;
}
}
Unfortunately,
HKQuantityTypeIdentifierKey.HeartRate;
HKObjectType.GetQuantityType (heartRateId);
Seem to be missing. Has anyone got a working example for MAUI?
These two methods in the documentation you refer to are outdated, you can modify your method as follows:
HKQuantityTypeIdentifierKey.HeartRate; ---> HKQuantityTypeIdentifier.HeartRate;
HKObjectType.GetQuantityType (heartRateId); ---> HKQuantityType.Create(heartRateId);
For more details, you can refer to:
HealthKit Namespace | Microsoft
HKQuantityTypeIdentifierKey Class | Microsoft
HKObjectType.GetQuantityType(NSString) Method | Microsoft
I used this code in my .Net Maui app since you asked for both iOS and Android. You can see an auth request for heart rate, but the code doesn't actually query for or observe heart data. Anyway, this code is a great guide to start with. The code also implements completion handlers across iOS and Android.
https://github.com/jlmatus/Xamarin-Forms-HealthKit-steps/blob/master/StepsCounter-Test-Project/iOS/HealthData.cs
Hope this helps!

How to implement listener pattern in swift

I am new in swift moved from java. And some implementaion of dessign patterns confuse me.
For example I have presudo pattern observer (callback) in java code (there is example below). Namely UI passed own listener to Manager class and listen callbacks isConnected and isDisconnected. If a callback is executed UI class shows certain message "isConnected" or "isDisconnected"
public class UI{
private Manager mManager;
void createManager(){
mManager = new Manager(mManagerLister);
}
public void showMessage(String aMsg){
print(aMsg)
}
private final IManagerListener mManagerLister = new IManagerListener{
void isConnected(){
this.showMessage("isConnected")
}
void isDisconnected(){
this.showMessage("isConnected")
}
}
}
public class Manager{
interface IManagerListener{
void isConnected();
void isDisconnected();
}
private final mListener;
public Manager(IManagerListener aListener){
mListener = aListener;
}
}
How to correctly port this java code to swift code? I tries to port but error message Value of type 'UI' has no member 'showMessage' is shown
public class UI{
var manager: Manager?
var managerListener: IManagerListener?
func createManager(){
managerListener = ManagerListenerImp(self)
manager = Manager(managerListener)
}
public func showMessage(msg: String){
print(msg)
}
class ManagerListenerImp: IManagerListener{
weak var parent: UI
init(parent : UI ){
self.parent = parent
}
func isConnected(){
parent.showMessage("isConnected")
// Value of type 'UI' has no member 'showMessage'
}
..........
}
}
Perhaps exists more gracefully a way to use callbacks and my way is not correctly?
There are multiple ways to achieve it.
Delegate Pattern (Using Protocols which are nothing but interfaces
in Java)
Using Blocks/Closures
Using KVO
Because you have used interfaces am elaborating on Delegate pattern below.
Modify your code as below
Declare a protocol
#objc protocol ManagerListenerImp {
func isConnected()
}
Declare a variable in Manager class
class Manager {
weak var delegate : ManagerListenerImp? = nil
}
Confirm to ManagerListenerImp in your UI class
extension UI : ManagerListenerImp {
func isConnected () {
//your isConnected implementation here
}
}
Pass UI instance (self in swift and this in JAVA to manager class)
func createManager(){
manager = Manager()
manager?.delegate = self
}
Finally, whenever you wanna trigger isConnected from Manager class simply say
self.delegate?.isConnected()
in your Manager class
Hope it helps
I'm a bit confused by which class has a reference to which, but that shouldn't be too hard to change in the following example.
You might be looking for an Observer Pattern. This can have multiple objects listening to the same changes:
1. ManagerStateListener Protocol
Protocol to be implemented by any class that should react to changes to the state of the Manager
protocol ManagerStateListener: AnyObject {
func stateChanged(to state: Manager.State)
}
2. Manager Class
The Manager class contains:
Its state
A list with listeners
Methods for adding, removing and invoking the listeners
An example class that implements the ManagerStateListener protocol
class Manager {
/// The possible states of the Manager
enum State {
case one
case two
case three
}
/// The variable that stores the current state of the manager
private var _currentState: State = .one
var currentState: State {
get {
return _currentState
}
set {
_currentState = newValue
/// Calls the function that will alert all listeners
/// that the state has changed
invoke()
}
}
/// The list with all listeners
var listeners: [ManagerStateListener] = []
/// A specific listener that gets initialised here
let someListener = SomeListener()
init() {
addListener(someListener) /// Add the listener to the list
}
/// Method that invokes the stateChanged method on all listeners
func invoke() {
for listener in listeners {
listener.stateChanged(to: currentState)
}
}
/// Method for adding a listener to the list of listeners
func addListener(_ listener: ManagerStateListener) {
listeners.append(listener)
}
/// Method for removing a specific listener from the list of listeners
func removeListener(_ listener: ManagerStateListener) {
if let index = listeners.firstIndex(where: { $0 === listener }) {
listeners.remove(at: index)
}
}
}
3. SomeListener Class
An example listener that implements the ManagerStateListener protocol, held by the Manager class
class SomeListener : ManagerStateListener {
func stateChanged(to state: Manager.State) {
/// Do something based on the newly received state
switch state {
case .one:
print("State changed to one")
case .two:
print("State changed to two")
case .three:
print("State changed to three")
}
}
}
I hope this is of any help.

MvvmCross: Binding a BaseView Property to a BaseViewModel Property

What I am trying to achieve here is a global loading indicator with MvvmCross.
From what I gathered so far it appears that I can implement this by using a BaseView and BaseViewModel. The BaseViewModel should contain an IsLoading property that the BaseView can Bind to. Therefore, I can set IsLoading to true in any of my ViewModels to cause the indicator to be displayed.
The BaseViewModel looks like this:
public abstract class BaseViewModel : MvxViewModel
{
private bool _isLoading = false;
public bool IsLoading
{
get { return _isLoading; }
set { _isLoading = value; RaisePropertyChanged(() => IsLoading); }
}
private string _loadingMessage = "Loading...";
public string LoadingMessage
{
get { return _loadingMessage; }
set { _loadingMessage = value; RaisePropertyChanged(() => LoadingMessage); }
}
}
As for binding to the ViewModel, this issue was addressed here: https://stackoverflow.com/a/10930788
I was successfully able to listen to IsLoading by attaching to the PropertyChanged event, however, since this is not a "real" binding it will not fire if IsLoading is set to true before you attach to the event (Such as before the view is loaded).
Next I attempted to call AddBindings to attach to my BaseViewModel in order to create a real binding between the two properties, although this does not appear to work (no errors).
Here is what my BaseView currently looks like for iOS:
public abstract class BaseView<TViewModel> : MvxViewController where TViewModel : BaseViewModel
{
public TViewModel ViewModel
{
get { return (TViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
protected BaseView(string nib, NSBundle bundle) : base(nib, bundle)
{
}
private LoadingOverlay _loadingOverlay;
public override void ViewDidLoad()
{
base.ViewDidLoad();
_loadingOverlay = new LoadingOverlay(View.Frame);
this.AddBindings(new Dictionary<object, string>()
{
{this, "{'IsLoading':{'Path':'IsLoading'}}"},
{_loadingOverlay, "{'LoadingMessage':{'Path':'LoadingMessage'}}"}
});
}
public bool IsLoading
{
set
{
if (value)
View.Add(_loadingOverlay);
else
_loadingOverlay.Hide();
}
}
}
Are there any pitfalls to AddBindings that I may be unaware of? or is there a newer method altogether that I should be using?
I Appreciate the help, Thanks.
If you are using v3, then by default you must change over to the new 'Swiss' style bindings.
These change Json text like:
"{'LoadingMessage':{'Path':'LoadingMessage'}}"
Into simpler text like:
"LoadingMessage LoadingMessage"
For more on this, see http://blog.ostebaronen.dk/2013/01/awesome-mvvmcross-swiss-bindings-for.html
One further option you can use in v3 is 'fluent bindings'. To see these in action, see all the iOS samples in the N+1 series - http://mvvmcross.wordpress.com/, or questions like Fluent Bindings and UIButton titles
Eg something like:
this.CreateBinding().For("LoadingMessage").To("LoadingMessage").Apply();
It may also help for debugging if you enable additional trace - see MvvmCross Mvx.Trace usage

Whats the best way to completely disable every play at runtime?

I want to disable everyplay, built in unity, when running iphone4/3G/3GS
but I'm not sure of the easiest place to just globally disable it. Any suggestions?
if (iPhone.generation == iPhoneGeneration.iPhone4 || iPhone.generation == iPhoneGeneration.iPhone3G || iPhone.generation == iPhoneGeneration.iPhone3GS )
You can easily disable single core devices (3GS/4/iPad1) by calling Everyplay.SharedInstance.SetDisableSingleCoreDevices(true) in the first scene of your game. After that you don't have to worry if you are calling StartRecording on a single core device since the calls are ignored by Everyplay. 3G (and Unity editor) does not support the recording in the first place.
In case you need to support recording on iPad 1 one approach is to create an Everyplay singleton wrapper which simply does not call recording functions on devices which you have have defined to be not supported.
Simple wrapper example (untested but gives you the idea):
using UnityEngine;
public static class MyEveryplayWrapper {
private static iPhoneGeneration[] unsupportedDevices = {
iPhoneGeneration.iPad1Gen,
iPhoneGeneration.iPhone,
iPhoneGeneration.iPhone3G,
iPhoneGeneration.iPhone3GS,
iPhoneGeneration.iPodTouch1Gen,
iPhoneGeneration.iPodTouch2Gen,
iPhoneGeneration.iPodTouch3Gen
};
private static bool CheckIfRecordingSupported() {
bool recordingSupported = !Application.isEditor;
foreach(iPhoneGeneration device in unsupportedDevices) {
if(device == iPhone.generation) {
recordingSupported = false;
break;
}
}
Debug.Log ("Everyplay recording support: " + recordingSupported);
return recordingSupported;
}
public static bool IsRecordingSupported = CheckIfRecordingSupported();
public static void StartRecording() {
if(IsRecordingSupported) {
Everyplay.SharedInstance.StartRecording();
}
}
public static void StopRecording() {
if(IsRecordingSupported) {
Everyplay.SharedInstance.StopRecording();
}
}
}
To use it you just call MyEveryplayWrapper.MethodName instead of Everyplay.SharedInstance.MethodName. When rendering your UI you can take the IsRecordingSupported into account to show/hide Everplay related buttons etc.

Resources