.NET MAUI Accessing Apple Healthkit - ios

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!

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.

Initialize method not getting called on GoBackAsync, Xamarin forms

The question can be really basic since I have little to no knowledge about Xamarin Forms.
I have recently started working on an old Xamarin Forms project where I had to upgrade "Prism.Plugin.Popups" plugin to Version="7.2.0.1046"
and “Prism.Unity.Forms" to Version="7.2.0.1422"
I had to Implement IInitialize Interface since INavigatingAware is deprecated in latest Prism framework as mentioned in https://github.com/PrismLibrary/Prism/issues/1858
Issue:
I want app to navigate back from XPopupPage to AViewModel with the code _navigationService.GoBackAsync(navParams); which is working but Initialize function of AViewModel isn’t getting called once it comes back from XPopupPage.
Here’s the code:
AViewModel:
public class AViewModel : BindableBase, INavigationAware, IInitialize {
....
// Code to navigate to XPopupPageViewModel private void ShowPopup(object obj)
{
_navigation.NavigateAsync($”{.....}”);
}
//NOT GETTING CALLED once it come back from XPopupPageViewModel
public void Initialize(INavigationParameters parameters) {
.....
} }
XPopupPageViewModel:
public class XPopupPageViewModel : BindableBase, INavigationAware, IInitialize
{
//Code to navigate back to AViewModel private void Update(object obj)
{
....
var navParams = new NavigationParameters(.....); _navigationService.GoBackAsync(navParams);
} }
From the github issue you posted:
Use OnNavigatedTo when calling GoBack

Swift Combine properties inheritance throws 'Fatal error: Call of deleted method' on Xcode 11.4 beta 2 / iOS 13.4

I'm trying to using Swift Combine to get the changed event of a property.
I have this class that publish the isLogged property
class CurrentUser: Account {
static let me = CurrentUser() //Singleton
#Published var isLogged: Bool = false
}
that inherit from this other class that publish the profileImageVersion property
class Account {
#Published var profileImageVersion: String?
init(){
self.profileImageVersion = ""
}
}
I'm trying to subscribe to the published inherit profileImageVersion property like this without success!
// Subscribe to account image changes
userImageChangedSubscriber = CurrentUser.me.$profileImageVersion.receive(on: DispatchQueue.main).sink(receiveValue: { (imageVersion) in
...
}
})
The error is Fatal error: Call of deleted method
if, on the other hand, I subscribe to the isLogged property, all Is working fine...
// Subscribe to logged changes
userLoggedSubscriber = CurrentUser.me.$isLogged.receive(on: DispatchQueue.main).sink(receiveValue: { (logged) in
...
})
This error is thrown only on Xcode 11.4 beta 2 / iOS 13.4.
Using Xcode 11.3.1 / 13.3 all is working fine!
I have this same crash, and as a temporary workaround I found that moving all your published properties to the concrete class you are using will fix the issue. I had a setup like this:
class EpisodesViewModel {
#Published var episodes: [Episode]
init(fetchRequest: NSFetchRequest<Episode>, context: NSManagedObjectContext? = nil) throws {
...
}
...
}
With a subclass of this model that simply gave a fetch request:
final class LatestEpisodesViewModel: EpisodesViewModel {
init() throws {
try super.init(fetchRequest: Episode.latestFetchRequest())
}
}
By changing my setup to this I was able to fix the crash:
class EpisodesViewModel {
var fetchedEpisodes: [Episode]
init(fetchRequest: NSFetchRequest<Episode>, context: NSManagedObjectContext? = nil) throws {
...
}
...
}
final class LatestEpisodesViewModel: EpisodesViewModel {
#Published var episodes: [Episode] = []
override var fetchedEpisodes: [Episode] {
didSet {
episodes = fetchedEpisodes
}
}
init() throws {
try super.init(fetchRequest: Episode.latestFetchRequest())
}
}
This certainly seems like an Apple bug to me, but this got me around the issue in the meantime.
I have this same crash on Xcode 11.4.1.
I use "Clean Build Folder", build my project again and all works now fine !

Flutter - how do I send/receive data between different class?

I want to get a current user location to update nearby stores based on latitude/longitude inside the url.
but I can't figure out how to interact data between two different class.
I want to make it work something like 'AppConfig.latitude = _position.latitude;'. I tried with several methods including inherited widget that I found on stackoverflow and youtube, but still don't work. It's definitely that I'm missing something.
when I use a bloc, I have no clue how to update data inside 'class AppConfig' with bloc. Can it be done simply using SetState? I spent the whole day yesterday Googling for this problem. please guide me to right approach
class _CurrentLocationState extends State<CurrentLocation> {
Position _position;
Future<void> _initPlatformState() async {
Position position;
try {
final Geolocator geolocator = Geolocator()
...
setState(() {
_position = position;
// print(${_position.latitude})
// 35.9341...
// print(${_position.longitude})
// -117.0912...
<*I want to make it work something like this*>
AppConfig.latitude = _position.latitude;
AppConfig.longitude = _position.longitude;
<*this is how I tried with bloc*>
latLongBloc.getUserLocation(LatLng(position.latitude, position.longitude));
});
<* latitude/longitude need to be updated with a current user location *>
abstract class AppConfig {
static const double latitude = 0;
static const double longitude = 0;
static const List<String> storeName = ['starbucks'];
}
<* I need to use AppConfig.latitude for url in Repository class*>
class Repository {
...
Future<List<Business>> getBusinesses() async {
String webAddress =
"https://api.yelp.com/v3/businesses/search?latitude=${AppConfig.latitude}&longitude=${AppConfig.longitude}&term=${AppConfig.storeName}";
...
}
this is my bloc.dart file
class LatLongBloc {
StreamController _getUserLocationStreamController = StreamController<LatLng>();
Stream get getUserLocationStream => _getUserLocationStreamController.stream;
dispose(){
_getUserLocationStreamController.close();
}
getUserLocation(LatLng userLatLong) {
_getUserLocationStreamController.sink.add(userLatLong);
}
}
final latLongBloc = LatLongBloc();
You want to share state between classes/widgets, right? There are also other state management patterns like ScopedModel or Redux. Each pattern has its pros and cons, but you don't have to use BLoC if you don't understand it.
I would recommend to use ScopedModel because it's quite easy to understand in my opinion. Your data/state is in a central place and can be accessed by using ScopedModel. If you don't like to use this approach then try Redux or other patterns :)
Hope it helped you :D
Yours Glup3

AutoFac Register confusion

Hi I am just been looking at AutoFac and following their getting-started tutorial
http://autofac.readthedocs.org/en/latest/getting-started/index.html
having followed it and understanding how their services work I wanted to try to create a new implementation on the same interface type
builder.RegisterType<TodayWriter>().As<IDateWriter>();
builder.RegisterType<TomorrowWriter>().As<IDateWriter>();
Both implentations contain the same code
public class TomorrowWriter : IDateWriter
{
private IOutput _output;
public TomorrowWriter(IOutput output)
{
this._output = output;
}
public void WriteDate()
{
this._output.Write(DateTime.Today.AddDays(1).ToShortDateString());
}
}
So TodaysWriter is the same apart from the WriteDate method displaying
this._output.Write(DateTime.Today.ToShortDateString());
instead.
So now using the application, how do I determine what implementation to use as both methods are called WriteDate()
using(var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve<IDateWriter>();
// Is this using todaysWriter or TomorrowWriter?
writer.WriteDate();
}
Am I using this wrong?
Thanks
To differentiate between different implementations of the same interface look at named and keyed services in the docs.
Alternatively you can roll your own by registering a DateWriterFactory and having a method on that to get a specific IDateWriter implementation. something like:
public class DateWriterFactory
{
IDateWriter GetWriter(string writerName)
{
if (writername=="TodayWriter")
return new TodayWriter();
if (writername=="TomorrowWriter")
return new TomorrowWriter();
}
}
obviously the implementation of the factory could be as complex or as simple as you need. Or you could just have methods to get the fixed writers rather than pass in a string.

Resources