Does HKObserverQuery can receive notification when the application not running(Killed)? - ios

My requirement is to register for any one of the Health data like steps, weight, heart rate, etc., for background delivery using enableBackgroundDeliveryForType: method. And then create a Observer query for the same Health data to check.
In this scenario, if my application is killed by the user forcely and did changes to Health data using Health app. By this stage is it possible to get the notification to My application?
Is it mandatory to register for any of the background modes, to get notified for health data modifications through HKObserverQuery?
EDIT 1:
- (void)requestAuthorizationToShareTypes:(NSSet *)typesToShare readTypes:(NSSet *)typesToRead completion:(void (^)(BOOL, NSError *))completion
{
if ([HKHealthStore isHealthDataAvailable]) {
[self.healthStore requestAuthorizationToShareTypes:typesToShare readTypes:typesToRead completion:^(BOOL success, NSError *error) {
if(success)
{
self.authorizationSuccess = YES;
completion(YES, nil);
}
else
{
[MyUtilities showAlertWithTitle:#"Authorization fail!" message:#"You didn't allow to access Health data."];
completion(NO, error);
return;
}
}];
}
else
{
[MyUtilities showAlertWithTitle:#"Sorry!" message:#"Your device does not support Health data."];
NSDictionary *errorDictionary = #{ NSLocalizedDescriptionKey : #"Your device doesn't support Health Kit."};
NSError *error = [[NSError alloc] initWithDomain:#"" code:2 userInfo:errorDictionary];
completion(NO, error);
return;
}
}
- (void)authorizeConsumeHealth:(void (^)(BOOL, NSError *))completion
{
NSSet *readObjectTypes = [NSSet setWithObjects:
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryCaffeine],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryCalcium],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryChloride],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryIron],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic], [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount],
nil];
[self requestAuthorizationToShareTypes:nil readTypes:readObjectTypes completion:^(BOOL success, NSError *error) {
if(completion)
{
completion(success, error);
[self observeStepCountChanges];
}
}];
}
- (void)observeStepCountChanges
{
HKSampleType *sampleType = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
[self.healthStore enableBackgroundDeliveryForType:sampleType frequency:HKUpdateFrequencyImmediate withCompletion:^(BOOL success, NSError *error) {}];
HKObserverQuery *query = [[HKObserverQuery alloc] initWithSampleType:sampleType predicate:nil updateHandler:^(HKObserverQuery *query, HKObserverQueryCompletionHandler completionHandler, NSError *error) {
if(error)
{
NSLog(#"Steps count observer completion block. Error: %#", error);
}
else
{
NSLog(#"Steps count observer completion block");
}
}];
[self.healthStore executeQuery:query];
}
Please help me. Thanks.

Related

Quickblox error: You are not connected and not authorized

I know this question has been asked multiple time but none of them solved my problem.
Error Domain=com.quickblox.chat Code=401 "Password not verified"
actually I have tried this:
- (void)viewDidLoad
{
[super viewDidLoad];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"bdsfbd %#",chatuserobj.fullName);
NSLog(#"Chat Id %lu",(unsigned long)chatuserobj.ID);
NSLog(#"Current User %#",[QBSession currentSession].currentUser);
QBUUser *currentUserr = [QBUUser user];
currentUserr.ID = appDelegate.loginUserId;
currentUserr.password = appDelegate.loginUserPassword;
// connect to Chat
[QBRequest logInWithUserLogin:appDelegate.loginUser password:appDelegate.loginUserPassword successBlock:^(QBResponse *response, QBUUser *user)
{
chatDialog = [[QBChatDialog alloc] initWithDialogID:NULL type:QBChatDialogTypePrivate];
chatDialog.occupantIDs = #[#(chatuserobj.ID)];
[QBRequest createDialog:chatDialog successBlock:^(QBResponse *response, QBChatDialog *createdDialog)
{
NSLog(#"Created Dialog %#",createdDialog);
} errorBlock:^(QBResponse *response)
{
NSLog(#"Error %#",response);
}];
} errorBlock:^(QBResponse *response) {
}];
[[QBChat instance] connectWithUser:chatuserobj completion:^(NSError * _Nullable error)
{
NSLog(#"USer is Connected %#",error.description);
[self startChat];
}];
[QBSettings setKeepAliveInterval:30];
[QBSettings setAutoReconnectEnabled:YES];
}
and this
-(void)startChat
{
[[QBChat instance] addDelegate:self];
QBChatMessage *message = [QBChatMessage message];
[message setText:#"Hey there"];
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[#"save_to_history"] = #YES;
[message setCustomParameters:params];
[chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error)
{
NSLog(#"Completed: %#",error.description);
}];
}
I don't know where I am wrong. So point out my mistake.
EDIT: again in did load
- (void)viewDidLoad
{
[super viewDidLoad];
// connect to Chat
[[QBChat instance] connectWithUser:currentUserr completion:^(NSError * _Nullable error)
{
NSLog(#"USer is Connected %#",error.description);
}];
dispatch_async(dispatch_get_main_queue(), ^(void)
{
[self chat];
});
dispatch_async(dispatch_get_main_queue(), ^(void)
{
[self startChat];
});
}
chat is method for creating dialog for private group or one to one connection
-(void)chat
{
chatDialog = [[QBChatDialog alloc] initWithDialogID:NULL type:QBChatDialogTypePrivate];
chatDialog.occupantIDs = #[#(chatuserobj.ID)];
[QBRequest createDialog:chatDialog successBlock:^(QBResponse *response, QBChatDialog *createdDialog) {
} errorBlock:^(QBResponse *response) {
}];
}
and start chat actual communication occur
-(void)startChat
{
[[QBChat instance] addDelegate:self];
QBChatMessage *message = [QBChatMessage message];
[message setText:#"Hey there"];
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[#"save_to_history"] = #YES;
[message setCustomParameters:params];
[chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error)
{
NSLog(#"Completed: %#",error.description);
}];
}
now this error occur
UserInfo={NSLocalizedRecoverySuggestion = You are not connected to chat.
- (void)viewDidLoad
{
[super viewDidLoad];
// connect to Chat
[[QBChat instance] connectWithUser:currentUserr completion:^(NSError * _Nullable error)
{
NSLog(#"USer is Connected %#",error.description);
dispatch_async(dispatch_get_main_queue(), ^(void)
{
[self chat];
});
dispatch_async(dispatch_get_main_queue(), ^(void)
{
[self startChat];
});
}];
}
and same method of start chat and chat. it works well
[[QBChat instance] connectWithUser:chatuserobj completion:^(NSError * _Nullable error)
{
NSLog(#"USer is Connected %#",error.description);
}];
This method is used to connect yourself to the chat and not your opponents. Furthermore, in order to connect with this method your QBUUser instance must have valid password set as password property.
Basically you need to connect yourself to the chat and then just start creating dialogs and sending messages.

HKAnchoredQuery update handler not working properly

I wrote a code to get heart rate values from Health kit. The code is working fine but when the new heart values are updated in Health kit. I have to come to main screen and then multitask my app to get the updated results. What my aim is to get the updated result on my app without reopening or multitasking it, please help as I am new to iOS development.
My code:-
-(void)get_heartRates
{
//code to get the updated heart beats
HKSampleType *sampleType =
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
HKObserverQuery *query =
[[HKObserverQuery alloc]
initWithSampleType:sampleType
predicate:nil
updateHandler:^(HKObserverQuery *query,
HKObserverQueryCompletionHandler completionHandler,
NSError *error) {
if (error) {
NSLog(#"error occured while setting observer. %# ",
error.localizedDescription);
abort();
}
// Take whatever steps are necessary to update your app's data and UI
// This may involve executing other queries
[self executeAnchoredQuery];
// If you have subscribed for background updates you must call the completion handler here.
// completionHandler();
}];
[self.healthStore executeQuery:query];
}
-(void)executeAnchoredQuery
{
NSDate *startDate1 = [NSDate distantPast];
NSPredicate *Predicate = [HKQuery predicateForSamplesWithStartDate:startDate1 endDate:[NSDate date] options:HKQueryOptionStrictEndDate];
HKSampleType *object = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
sum_Of_HeartRates=0.0;
HKAnchoredObjectQuery *heartQuery = [[HKAnchoredObjectQuery alloc] initWithType:object predicate:Predicate anchor:self.lastAnchor limit:0 resultsHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *sampleObjects, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) {
NSLog(#"Sample counts:%ld",sampleObjects.count);
for(int i=0;i<(int)sampleObjects.count;i++)
{
HKQuantitySample *sample = (HKQuantitySample *)[sampleObjects objectAtIndex:i];
HKQuantity *quantity = sample.quantity;
double bpm_Values= [quantity doubleValueForUnit:[HKUnit unitFromString:#"count/min"]];
sum_Of_HeartRates=sum_Of_HeartRates+bpm_Values;
}
avg_heartBeats=sum_Of_HeartRates/(int)sampleObjects.count;
}];
[heartQuery setUpdateHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *SampleArray, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *Anchor, NSError *error) {
HKQuantitySample *sample = (HKQuantitySample *)[SampleArray objectAtIndex:0];
HKQuantity *quantity = sample.quantity;
new_Updated_Data =[quantity doubleValueForUnit:[HKUnit unitFromString:#"count/min"]];
NSLog(#"new quantity:%f",new_Updated_Data);
}];
[self.healthStore executeQuery:heartQuery];
NSLog(#"updated data %f",new_Updated_Data);
NSLog(#"%f", avg_heartBeats);
}
See if the following code could help you...
HKSampleType *sampleType =
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
HKObserverQuery *query =
[[HKObserverQuery alloc]
initWithSampleType:sampleType
predicate:nil
updateHandler:^(HKObserverQuery *query,
HKObserverQueryCompletionHandler completionHandler,
NSError *error) {
if (error) {
NSLog(#"error occured while setting observer. %# ",
error.localizedDescription);
abort();
}
// Take whatever steps are necessary to update your app's data and UI
// This may involve executing other queries
[self executeAnchoredQuery];
// If you have subscribed for background updates you must call the completion handler here.
// completionHandler();
}];
[self.healthStore executeQuery:query];
and then the function where you write you anchoredQuery code, this may give you an idea of the code flow :
-(void)executeAnchoredQuery
{
HKSampleType *sampleType =
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
HKAnchoredObjectQuery *query =
[[HKAnchoredObjectQuery alloc]
initWithType:sampleType
predicate:nil
anchor:self.anchor
limit:HKObjectQueryNoLimit
resultsHandler:^(HKAnchoredObjectQuery * _Nonnull query,
NSArray<__kindof HKSample *> * _Nullable sampleObjects,
NSArray<HKDeletedObject *> * _Nullable deletedObjects,
HKQueryAnchor * _Nullable newAnchor,
NSError * _Nullable error) {
if (error != nil) {
// Add proper error handling here...
NSLog(#"*** Unable to query for step counts: %# ***",
error.localizedDescription);
abort();
}
// Process the results...
self.anchor = newAnchor;
for (HKQuantitySample *sample in sampleObjects) {
[self addStepCountSample:sample];
}
for (HKDeletedObject *sample in deletedObjects) {
[self removeStepCountSample:sample];
}
NSLog(#"Done!");
}];
[self.healthStore executeQuery:query];
}
Please go through apple developer docs for further details.

Getting Private User Record in CloudKit

I am attempting to get a Users' saved data in CloudKit. I can see the record in the CloudKit Dashboard, but am unable to get to it via code in app.
-(void)getUserRecordID {
CKContainer *defaultContainer =[CKContainer defaultContainer];
[defaultContainer fetchUserRecordIDWithCompletionHandler:^(CKRecordID *recordID, NSError *error) {
if (!error) {
[defaultContainer fetchUserRecordIDWithCompletionHandler:^(CKRecordID *recordID, NSError *error) {
self.userRecordID = recordID;
NSLog(#"user record id: %#",recordID);
[self getUserRecord];
}];
}
else {
NSLog(#"error: %#",error.localizedDescription);
}
}];
}
-(void)getUserRecord {
CKContainer *defaultContainer =[CKContainer defaultContainer];
CKDatabase *publicDatabase = defaultContainer.publicCloudDatabase;
[publicDatabase fetchRecordWithID:self.userRecordID completionHandler:^(CKRecord *userRecord, NSError *error) {
if (!error) {
NSLog(#"current coins: %#",userRecord);
}
else {
NSLog(#"error: %#",error.localizedDescription);
}
}];
}
This gets me the User record information, but not the ID's of the saved private records. How can I get them?
Figured out the solution. You have to query for private records using CKQuery and NSPredicate.
-(void)getUserRecordID {
CKContainer *defaultContainer =[CKContainer defaultContainer];
[defaultContainer fetchUserRecordIDWithCompletionHandler:^(CKRecordID *recordID, NSError *error) {
if (!error) {
self.userRecordID = recordID;
NSLog(#"user record id: %#",recordID.recordName);
[self getStatsRecord];
}
else {
NSLog(#"error: %#",error.localizedDescription);
}
}];
}
-(void)getStatsRecord {
CKDatabase *privateDatabase = [[CKContainer defaultContainer] privateCloudDatabase];
CKReference *reference = [[CKReference alloc] initWithRecordID:self.userRecordID action:CKReferenceActionNone];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"creatorUserRecordID = %#", reference];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"Stats" predicate:predicate];
[privateDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
if (error) {
NSLog(#"error: %#",error.localizedDescription);
}
else {
if (![results firstObject]) {
[self createBlankRecord];
}
else {
CKRecord *record = [results firstObject];
NSLog(#"%#",record);
}
}
}];
}

How not to ask for publish permission everytime?

I did this in facebook
[self vSuspendAndHaltThisThreadTillUnsuspendedWhileDoing:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.ACAstore requestAccessToAccountsWithType:self.ACAccounts options:[self dicPostOptions] completion:^(BOOL granted, NSError *error) {
self.bPermissionToAccessStoreGranted=granted;
[self vContinue];
}];
}];
}];
Basically I am asking for publish permission. What I want to do is to check whether such publish permission has been granted or not before asking again.
How to do so?
To check permissions available:
if(![postRequest.session.permissions containsObject:#"publish_actions"])
You can make an FBRequest with the open graph API with me/permissions. It will return you a response with a dictionary where the key are the permissions.
FBRequest *req = [FBRequest requestWithGraphPath:#"me/permissions" parameters:Nil HTTPMethod:#"GET"];
[req startWithCompletionHandler: ^(FBRequestConnection *connection,
NSDictionary* result,
NSError *error) {
BOOL canPublish = FALSE;
if (!error)
{
FBGraphObject *data = [result objectForKey:#"data"];
for(NSDictionary<FBGraphObject> *aKey in data)
{
canPublish = [[aKey objectForKey:#"publish_stream"] boolValue];
}
}
else
{
NSLog(#"%#", error);
}
NSLog(#"%#", canPublish ? #"I have publish perms" : #"I don't have publish perms");
}];
Try this -
First of all implement all the facebook sdk delegate methods in your app delegate.
- (IBAction)loginWithFacebookButtonTapped:(id)sender
{
IntubeAppDelegate *delegat = (IntubeAppDelegate*)[[UIApplication sharedApplication] delegate];
[delegat doLoginAndSwitch];
}
Now, in your appDelegate -
-(void) doLoginAndSwitch
{
[self openSessionWithAllowLoginUI:YES];
}
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI
{
NSArray *permissions = [NSArray arrayWithObjects:#"email", nil];
return [FBSession openActiveSessionWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
-(BOOL)openSessionWithAllowPublishStreamPermission:(BOOL)allowLoginUI
{
NSArray *permissions = [NSArray arrayWithObjects:#"publish_actions",#"publish_stream", nil];
[[FBSession activeSession] requestNewPublishPermissions:permissions defaultAudience:FBSessionDefaultAudienceEveryone completionHandler:^(FBSession *session, NSError *error){
}];
return YES;
}
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState)state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if(!error)
{
// NSLog(#"FBSessionStateOpen :- logged in");
[self openSessionWithAllowPublishStreamPermission:YES];
// Your code
}
}
}
I hope you would get what you desire now. :)

Publish picture with caption on application album whether it exists or not using Facebook SDK 3.1 for iOS

Using toblerpwn answer i manage to publish a picture to the application album as i wanted to.
But this works only when the application album has already been created (because i need to specify the album id).
In the other hand the requestForUploadPhoto convenience method creates the application album if it doesn't exists and publishes the picture.
So could someone help me figure out how to merge this two beheviours?
Thanks to #deepak-lakshmanan i manage to solve my problem.
The idea is to publish to the application album using /USER_ID/photos insted of /ALBUM_ID/photos; this way the album is automatically created if it doesn't exist.
So the steps to follow are:
get the publish permission
then retrieve the user id using /me
finally publish the picture to the application album with /USER_ID/photos
Here is my code in case someone struggles with this, am using Facebook SDK 3.1 for iOS:
- (void)sendRequestFacebookPublishPermission {
NSArray *permissions = [[NSArray alloc] initWithObjects:#"publish_stream", nil];
if(!FBSession.activeSession.isOpen ) {
[FBSession openActiveSessionWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self requestFacebookPublishPermissionCompleted:session status:status error:error];
}];
} else if ([FBSession.activeSession.permissions indexOfObject:#"publish_actions"] == NSNotFound) {
[FBSession.activeSession reauthorizeWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
[self requestFacebookPublishPermissionCompleted:session status:FBSessionStateOpen error:error];
}];
} else {
[self sendRequesFacebooktUserInfo];
}
}
- (void)requestFacebookPublishPermissionCompleted:(FBSession *)session
status:(FBSessionState)status
error:(NSError *)error {
if (error) {
DLog(#"%#", error.localizedDescription);
} else {
[self sendRequesFacebooktUserInfo];
}
}
-(void)sendRequesFacebooktUserInfo {
FBRequestConnection *newConnection = [[FBRequestConnection alloc] init];
// output the results of the request
FBRequestHandler handler = ^(FBRequestConnection *connection, id result, NSError *error) {
[self requestFacebookUserInfoCompleted:connection result:result error:error];
};
// create the request object, using the fbid as the graph path
FBRequest *request = [[FBRequest alloc] initWithSession:FBSession.activeSession graphPath:#"me"];
// add the request to the connection object
[newConnection addRequest:request completionHandler:handler];
// if there's an outstanding connection, just cancel
[self.requestConnection cancel];
// keep track of our connection, and start it
self.requestConnection = newConnection;
[newConnection start];
}
- (void)requestFacebookUserInfoCompleted:(FBRequestConnection *)connection
result:(id)result
error:(NSError *)error {
// not the completion we were looking for...
if (self.requestConnection && connection != self.requestConnection) {
return;
}
// clean this up, for posterity
self.requestConnection = nil;
if (error) {
DLog(#"%#", error.localizedDescription);
} else {
FBGraphObject *dictionary = (FBGraphObject *)result;
NSString* userId = (NSString *)[dictionary objectForKey:#"id"];
[self sendRequestFacebookPublishOnAlbum:userId];
}
}
- (void)sendRequestFacebookPublishOnAlbum:(NSString*)fbId {
UIImage *imageToPost = /* get the image you need*/ ;
/*
//--- Facebook SDK convenience method : requestForUploadPhoto won't let me post image description ---//
FBRequestConnection *newConnection = [FBRequestConnection startForUploadPhoto:screenshot completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
[self requestPostCardOnFacebookCompleted:connection result:result error:error];
}];
// if there's an outstanding connection, just cancel
[self.requestConnection cancel];
// keep track of our connection, and start it
self.requestConnection = newConnection;
//-----------------------------------------------------------------------------------------------------//
*/
//--- http://stackoverflow.com/questions/12486852/facebook-ios-sdk-cannot-specify-an-album-using-fbrequests-requestforuploadphot ---//
NSString *messagePublie = laCarte.message;
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:
screenshot, #"picture",
messagePublie , #"name",
nil] ;
FBRequestConnection *newConnection = [[FBRequestConnection alloc] init];
FBRequestHandler handler = ^(FBRequestConnection *connection, id result, NSError *error) {
[self requestFacebookPublishOnAlbumCompleted:connection result:result error:error];
};
NSString *graphPath = [NSString stringWithFormat:#"%#/photos",fbId];
FBRequest *request = [[FBRequest alloc] initWithSession:FBSession.activeSession graphPath:graphPath parameters:parameters HTTPMethod:#"POST"];
[newConnection addRequest:request completionHandler:handler];
// if there's an outstanding connection, just cancel
[self.requestConnection cancel];
// keep track of our connection, and start it
self.requestConnection = newConnection;
[newConnection start];
}
- (void)requestFacebookPublishOnAlbumCompleted:(FBRequestConnection *)connection result:(id)result error:(NSError *)error {
if (self.requestConnection && connection != self.requestConnection) {
return;
}
// clean this up, for posterity
self.requestConnection = nil;
if (error) {
DLog(#"%#", error.localizedDescription);
} else {
DLog(#"%#", "Done");
}
}

Resources