Posts

Post not yet marked as solved
7 Replies
250 Views
I have an app which uses Cocoa Pods to use MQTTClient in connecting to io.adafruit. I use the app to get the various data point stored at io.adafruit and to even send data to adafruit to control a connected unit. I am using .xcworkspace to upload the app on my phone and everything works fine. I am hoping to wake my app every so ofter to get some data points from io.adafruit and if certain conditions exist, I want to send a notification to the user. I have added Background Modes to my app's Signing & Capabilities (Background fetch) and in my INFO I have Permitted background task scheduler identifiers with the String identifier LEVELIT.Refresh. The following is my code I am using in my AppDelegate.h #import <UIKit/UIKit.h> #import <CoreData/CoreData.h> #import <MQTTClient/MQTTClient.h> #import <UserNotifications/UserNotifications.h> @interface AppDelegate: UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate,UIAlertViewDelegate,MQTTSessionDelegate>{ MQTTSession *session3; } @property (nonatomic, retain) MQTTSession *session3; @property (nonatomic, strong) NSPersistentContainer *persistentContainer; @end And this is the code I use in my AppDelegate.m #import "AppDelegate.h" #import <BackgroundTasks/BackgroundTasks.h> #import <CloudKit/CloudKit.h> #import <UserNotifications/UserNotifications.h> static NSString* TaskID = @"LEVELIT.refresh"; @interface AppDelegate() @property (nonatomic, retain) NSString *myUserName; @property (nonatomic, retain) NSString *myUserKey; @property (nonatomic, retain) NSString *myTrips; @property (nonatomic, retain) NSString *atrip; @property (nonatomic, retain) NSString *trip; @property (nonatomic, retain) NSString *gettrip; @property(strong) void (^expirationHandler)(void); @end @implementation AppDelegate @synthesize session3,window; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if (@available(iOS 13.0, *)) { [[BGTaskScheduler sharedScheduler] registerForTaskWithIdentifier:TaskID usingQueue:nil launchHandler:^(BGAppRefreshTask *task) { [self handleAppRefreshTask:task]; }]; } else { // Fallback on earlier versions } UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) { }]; UNNotificationCategory* generalCategory = [UNNotificationCategory categoryWithIdentifier:@"GENERAL" actions:@[] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction]; NSUserDefaults *defaults2 = [NSUserDefaults standardUserDefaults]; if([[[defaults2 dictionaryRepresentation] allKeys] containsObject:@"myUserNameFile"]){ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; self.myUserName = [defaults objectForKey:@"myUserNameFile"]; NSLog(@"myUserName1:%@",self.myUserName); self.myUserKey = [defaults objectForKey:@"myUserKeyFile"]; NSLog(@"myUserKey1:%@",self.myUserKey); } return YES; } } -(void)schedualLocalNotifications{ } - (void)setTaskCompletedWithSuccess:(BOOL)success;{ NSLog(@"Completed"); } - (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"Entering background"); if (@available(iOS 13.0, *)) { BGAppRefreshTaskRequest *request = [[BGAppRefreshTaskRequest alloc] initWithIdentifier:TaskID]; request.earliestBeginDate = [NSDate dateWithTimeIntervalSinceNow:15*60]; NSError *error; BOOL success = [[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error]; if (success == TRUE) { } } //BREAKPOINT } -(void)handleAppRefreshTask:(BGAppRefreshTask *)task API_AVAILABLE(ios(13.0)){ //do things with task NSLog(@"Process started!"); task.expirationHandler = ^{ NSLog(@"WARNING: expired before finish was executed."); }; MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init]; transport.host = @"io.adafruit.com"; transport.port = 1883; self.session3 = [[MQTTSession alloc] init]; self.session3.userName = self.myUserName; self.session3.password = self.myUserKey; self.session3.transport = transport; self.session3.delegate = self; self.session3.keepAliveInterval = 30; // new stuff NSString *feeds = [self.myUserName stringByAppendingString:@"/feeds/"]; self.atrip = [feeds stringByAppendingString:@"trip"]; self.gettrip = [self.atrip stringByAppendingString:@"/get"]; [session3 connectWithConnectHandler:^(NSError *error) { if(!error){ [self.session3 subscribeToTopic:self.atrip atLevel:1 subscribeHandler:^(NSError *error, NSArray *gQoss){ if (error) { NSLog(@"Subscription failed %@", error.localizedDescription); } else { NSLog(@"Subscription sucessfull! Granted Qos: %@", gQoss); NSData* data = [@"0" dataUsingEncoding:NSUTF8StringEncoding]; [self.session3 publishData:data onTopic:self.gettrip retain:NO qos:0 publishHandler:nil]; } }]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(45* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [task setTaskCompletedWithSuccess:YES]; }); self.session3.keepAliveInterval =30; } else {NSLog(@"[connectWithConnectHandler]Error Connect %@", error.localizedDescription);} }]; task.expirationHandler = ^{ NSLog(@"WARNING: expired before finish was executed."); }; } } } //More code here but too much. @end I am not sure about the local notification because the BGAppRefreshTask is not working. I have placed a breakpoint just after the app enters background and the TASK is submitted. Then I type in e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"LEVELIT.refresh"] The app launches in the background but I get an error error: Header search couldn't locate module MQTTClient error: couldn't install checkers, unknown error Message from debugger: Terminated due to signal 9 When I tried running the app without .xcworkspace the project said it couldn't find MQTTClient. But with the workspace everything works fine. Why would launching the app in the background cause the app not to locate the MQTTClient libraries? And how do I work around this problem? Any and all help would be appreciated.
Posted
by gbenna.
Last updated
.
Post not yet marked as solved
3 Replies
444 Views
I have an app that tracks some sensors. I am using MQTT and Adafruit to send the sensor information between sensor stations and Adafruit and my app. I have everything working great but have a small problem. I would like to be able to check my sensor reading on my app every 10 - 15 minutes when the app is in the background. I have the background function working and have scheduled it for every 15 minutes. When the app wakes in the background it checks the reading from Adafruit and sends those reading to a cloud account using CloudKit. This is used to update the AppleWatch extension of the App. I would also like to send notifications if certain sensor conditions are met. Like when water is detected and how much water is there. I know that in order to moderate the impact of the background functionality of an app on processing and battery power Apple basically can delay the background function up to two days. This poses a problem since the purpose of the app is to detect how much water is present. Say a leak developed and it is sensed but the owner isn't notified of the leak for two days. The app isn't much good since in two day a lot of damage can be caused which if notified within 10-15 minutes could have been avoided. When my app wakes in background it runs for about 5 seconds. So over the course of one day that would be about 12 minutes. Is there any way to petition Apple to let an app runs as needed in the background to promote the true function of the App?
Posted
by gbenna.
Last updated
.
Post not yet marked as solved
0 Replies
386 Views
I am trying to fetch my CloudKit record and then update it with new data. I have imported CloudKit framework I have added CloudKit and key/values to my capabilities. I have put them into my entitlements. I have use Schemas to create new custom type private records and added 5 fields. I would like to know how to update these field strings in my iphone app and then get that information on my watch app and put the data in text labels. I have tried various things but nothing seems to be working. I am working in objc. Could someone help me. Here is some code I am trying to get to work but with little success. As a 68 yr old retired art teacher teaching myself this I am not a trained coder and need all the help I can get. I just tried this and it runs through, but I can't see where I put in the values for the keys I have put in. Where do I put those values to modify. NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init]; &#9;&#9;&#9;&#9;[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; &#9;&#9;&#9;&#9;// or @"yyyy-MM-dd hh:mm:ss a" if you prefer the time with AM/PM &#9;&#9;&#9;&#9;NSLog(@"%@",[dateFormatter stringFromDate:[NSDate date]]); &#9;&#9;&#9;&#9;NSString *date =[dateFormatter stringFromDate:[NSDate date]]; &#9;&#9;&#9;&#9;NSString *myPoolString = @"MyPoolInfo"; &#9;&#9;&#9;&#9;NSString *MyPoolInfoString = [myPoolString stringByAppendingString:date]; &#9;&#9;&#9;&#9;NSLog(@"MyPoolInfoString:::%@",MyPoolInfoString); &#9;&#9;&#9;&#9;CKRecordID *recordID = [[CKRecordID alloc]initWithRecordName:myPoolString]; &#9;&#9;&#9;&#9;NSLog(@"recordID:::%@", recordID); &#9;&#9;&#9;&#9;CKRecord *record = [[CKRecord alloc] initWithRecordType: @"Pool" recordID: recordID]; &#9;[[CKContainer defaultContainer].privateCloudDatabase fetchRecordWithID:recordID &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; completionHandler:^(CKRecord *record, NSError *error) { &#9;&#9;&#9;&#9;&#9;&#9;NSArray *myFields = [NSArray arrayWithObjects:@"temperature",@"date",@"level",@"trip",@"battery",nil]; &#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;CKModifyRecordsOperation *modifyRecords= [[CKModifyRecordsOperation alloc] &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; initWithRecordsToSave:myFields recordIDsToDelete:nil]; &#9;&#9;&#9;&#9;&#9;&#9;//[modifyRecords setValue:self.myTrip forKey:@"temperature"]; &#9;&#9;&#9;&#9;&#9;&#9;//[modifyRecords setValue:self.myDate forKey:@"date"]; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;modifyRecords.savePolicy=CKRecordSaveAllKeys; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;modifyRecords.qualityOfService=NSQualityOfServiceUserInitiated; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;modifyRecords.modifyRecordsCompletionBlock= &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; ^(NSArray * savedRecords, NSArray * deletedRecordIDs, NSError * operationError){ &#9;&#9;&#9;&#9;&#9;&#9;//&#9; the completion block code here &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; [record setObject: self.myTemp forKey: @"temperature"]; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; NSLog(@"savedRecords:%@",savedRecords); &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;}; &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;[[CKContainer defaultContainer].privateCloudDatabase addOperation:modifyRecords]; &#9;&#9;&#9;&#9; }]; Like I said I have set up a private database Pool and a CKRecordID MyPoolInfo and fields but I am totally lost. There is very little out there for people working in objective-c. HELP
Posted
by gbenna.
Last updated
.
Post not yet marked as solved
7 Replies
2.3k Views
I have an app that I am updating since Apple made having a launch screen storyboard a must. I have created the launchscreen storyboard and included all the launch images in my images.xcassets folder.The problem is that when the simulator loads the app in iPhone 8, 8+, iPad (7gen),iPad Air, iPad 9.7 the launch image is blank. The included images do not load. In the simulators for the iPhone 11, 11Pro, 11ProMax, iPad11, and iPad12.9 the launch images show up fine.I know the correct phone is being loaded because I have put: if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){ NSLog(@"THIS IS DEVICE STRING "); if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 480.0){ // 4 320x480 x0 y0 deviceString2 = @"0"; NSLog(@"THIS IS DEVICE STRING -0"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 568.0){ //5 320x568 x0 y*1.183+62 deviceString2 = @"0"; NSLog(@"THIS IS DEVICE STRING 0"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 667.0){ //678 375x667 x*1.171, y*1.389+25 deviceString2 = @"1"; NSLog(@"THIS IS DEVICE STRING 1"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 736.0){ //678+ 414x736 x*1.29, y*1.53+28 deviceString2 = @"2"; NSLog(@"THIS IS DEVICE STRING 2"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 812.0){ //11pro&amp;max 375x812 x*1.17, y*1.69+97 deviceString2 = @"3"; NSLog(@"THIS IS DEVICE STRING 3"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 896.0){ //11 414x896 x*1.29, y*1.867+107 deviceString2 = @"4"; NSLog(@"THIS IS DEVICE STRING 4"); }} else if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad){ [advertise setTitle:NSLocalizedString(@"CHESSOBJ1",nil) forState:UIControlStateNormal]; if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 1024.0){ //9.7 768x1024 x*2.4 y*2.13-122 deviceString2 = @"5"; NSLog(@"THIS IS DEVICE STRING 5"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 1080.0){ //7gen 810x1080 x*2.53 y*2.256-128 deviceString2 = @"6"; NSLog(@"THIS IS DEVICE STRING 6"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 1112.0){ //10.5 834x1112 x*2.6 y*2.32-130 deviceString2 = @"7"; NSLog(@"THIS IS DEVICE STRING 7"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 1366.0){ //12.9 1024x1366 x*3.2 y*2.85-162 deviceString2 = @"8"; NSLog(@"THIS IS DEVICE STRING 8"); } else if([UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height == 1194.0){ //11 834x1194 x*2.6 y*2.49-89 deviceString2 = @"9"; NSLog(@"THIS IS DEVICE STRING 9"); } }On the simulators the correct log is written for the device loaded, but still no images show up.On the iPhone six the log says that the iPhone 6 is an iPhone 5 in size. (I'm not sure if the iPhone 7,8,6+,7+,8+ do the same since I am not rich enough to own all devices. I have read about this but I need to have the app recognize each iPhone so I can designate the placement and size of my various objects in the space. I cannot use storyboard auto resize as this doesn't work. The app I have connects two Apple devices together through bluetooth to play games together. When I move a piece on my device it moves on your device. So precise placement on various devices is essential.HOW CAN I GET THE APP TO RECOGNIZE THE VARIOUS DEVICE SIZES THROUGH CODE?I can't believe Apple would take this ability away form a developer.Please Help!
Posted
by gbenna.
Last updated
.