I want to pass data from my iOS App to my watchOS 3 app using WKWatchConnectivityRefreshBackgroundTask
How do I set up code in my watchOS App to handle the data being transferred?
For example in the past I used this iOS code to send a message from the iOS App and if there was no connection send a context:
func sendTable()
{
let tableInfo: WatchWorkout = PhoneData().buildWatchTableData(Foundation.Date().refDays())
let archivedTable: Data = NSKeyedArchiver.archivedData(withRootObject: tableInfo)
if validSession
{
sendMessage([Keys.UpdateType : PhoneUpdateType.TableInfo.rawValue, Keys.Workout: archivedTable])
}
else
{
do
{
try updateApplicationContext([Keys.UpdateType : PhoneUpdateType.TableInfo.rawValue, Keys.Workout: archivedTable])
}
catch
{
print("Phone Session - error sending info: \(error)")
}
}
}
func sendMessage(_ message: [String : AnyObject], replyHandler: (([String : AnyObject]) -> Void)? = nil, errorHandler: ((NSError) -> Void)? = nil)
{
print("Phone Session - phone sent message")
session!.sendMessage(message,
replyHandler:
nil,
errorHandler:
{
(error) -> Void in
print("Phone Session - Error Message during transfer to Watch: \(error)")
}
)
}
func updateApplicationContext(_ applicationContext: [String : AnyObject]) throws
{
print("Phone Session - phone sent context")
if ((session) != nil)
{
do
{
try session!.updateApplicationContext(applicationContext)
}
catch let error
{
print("Phone Session - OPPS something wrong - context send failed")
throw error
}
}
}
I'm not sure how to code the receipt of this data as a background task on the watch.
Can someone provide some example code or post a link? The only Apple example code is not very helpful:
https://developer.apple.com/library/prerelease/content/samplecode/WatchBackgroundRefresh/Introduction/Intro.html
Thanks
Greg
The Quick Switch sample code was updated together with the release of watchOS 3 to include an example of handling the WatchConnectivity background refresh task.
#ccjensen The Quick Switch sample code doesn't work, is it?
It will crash on my iPhone6 iOS10.0 beta3. I sent feedback already last Friday.
In my Case, calling
updateApplicationContext(_:)
transferUserInfo(_:)
transferCurrentComplicationUserInfo(_:)
transferFile(_:metadata:)
on iPhone side never trigger handle(_:) listener.
Related
First of all, I have never used notifications in an app. I have done tutorials but the whole thing confuses me.
I have created a SwiftUI file called Notify.swift. I want the user to be able to set a time for a notification to alert them to perform a task at a specified time, like in this image:
Where you see the time in the image, I have created a DatePicker to pick a time for the notification:
VStack {
Button(action: {}) {
HStack {
DatePicker(" Select a time ....",
selection: $wakeup, displayedComponents: .hourAndMinute)
.font(.title2)
.accentColor(Color(.white))
}
}.background(Color(.black))
}
.frame(width: .infinity, height: 40, alignment: .center)
.padding()
When the user clicks on the Create Button to set the notification, it should set the notification at that particular time (all the time, unless changed). This is what I need to happen but don't know how to do it:
If the notification time is set for 8:30am, like in the image, and the user selects CREATE, a notification is set and should be sent to the user to perform whatever task with maybe a sound and a message at that specified time.
I understand that there are different types of notification: local, user, Apple push, etc, but I don't know which type this falls in or how to do it.
Would this be a notification or an alarm?
You can use local notifications for that. Here I made a function for you to trigger the notification. First off all, check if that time is prior the current time. Then the notification will be tomorrow and we add one day to our Date. You can change title, body as you wish.
Make sure to wrap your DatePicker outside the button, otherwise it will always trigger a notification when you click the DatePicker.
func scheduleNotification() -> Void {
let content = UNMutableNotificationContent()
content.title = "Your title"
content.body = "Your body"
var reminderDate = wakeup
if reminderDate < Date() {
if let addedValue = Calendar.current.date(byAdding: .day, value: 1, to: reminderDate) {
reminderDate = addedValue
}
}
let comps = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: reminderDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: comps, repeats: false)
let request = UNNotificationRequest(identifier: "alertNotificationUnique", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("Uh oh! We had an error: \(error)")
}
}
}
Also you need to request permission for Notifications like this:
func requestPush() -> Void {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
print("All set!")
} else if let error = error {
print(error.localizedDescription)
}
}
}
Here your button:
VStack {
Button(action: {
scheduleNotification()
}) {
Text("Save notification")
}
DatePicker("Select a time ....",
selection: $wakeup, displayedComponents: .hourAndMinute)
.font(.title2)
.accentColor(Color(.white))
}
When wrong user login ios app is crashing and no log displayed. But in Android is working with out crash. Why?
Thread 26: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/user/FlutterHome/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_aws_amplify_cognito-1.0.0+7/ios/Classes/SwiftFlutterAwsAmplifyCognito.swift, line 275
Future<dynamic> login(
{String username,
String password,
GlobalKey<ScaffoldState> globalKey}) async {
return FlutterAwsAmplifyCognito.signIn(username, password)
.then((SignInResult result) {
debugPrint('------------------------${result}');
switch (result.signInState) {
case SignInState.SMS_MFA:
// TODO: Handle this case.
break;
case SignInState.PASSWORD_VERIFIER:
// TODO: Handle this case.
break;
case SignInState.CUSTOM_CHALLENGE:
// TODO: Handle this case.
break;
case SignInState.DEVICE_SRP_AUTH:
// TODO: Handle this case.
break;
case SignInState.DEVICE_PASSWORD_VERIFIER:
// TODO: Handle this case.
break;
case SignInState.ADMIN_NO_SRP_AUTH:
// TODO: Handle this case.
break;
case SignInState.NEW_PASSWORD_REQUIRED:
// TODO: Handle this case.
break;
case SignInState.DONE:
break;
case SignInState.UNKNOWN:
// TODO: Handle this case.
break;
case SignInState.ERROR:
// TODO: Handle this case.
break;
}
return result.codeDetails;
}).catchError((error) {
if (error.code == 'Error') {
globalKey.currentState.showSnackBar(SnackBar(
backgroundColor: Colors.red,
content: Text(LocalizationsUtils(
Locale.fromSubtags(languageCode: AppPreferences().language))
.errorIncorrectEmailPassword),
));
}
});
}
github link
https://github.com/jonsaw/amazon-cognito-identity-dart
Had the same problem. There is just a missing return in code.
static func signIn(result: #escaping FlutterResult, username: String, password: String) {
AWSMobileClient.default().signIn(username: username, password: password){(signinResult, error) in
if (error != nil) {
DispatchQueue.main.async {
result(FlutterError(code: "Error", message: "Error signing in", details: error?.localizedDescription))
}
return // this return was missing!!!
}
FYI: If you run the Application with Xcode, the debugger will point you to the bug.
PS: the return is missing in every error, so the app might crash on other functionCalls too, for example if you try to get Tokens without being loggedIn.
In my InterfaceController I have the following code:
#IBAction func buttonClicked() {
if (WCSession.default.isReachable) {
let message = ["Message": "Hello"]
WCSession.default.sendMessage(message, replyHandler: nil)
print ("message sent")
}
}
In ViewController I have the following code:
override func viewDidLoad() {
super.viewDidLoad()
if (WCSession.isSupported()) {
let session = WCSession.default
session.delegate = self
session.activate()
}
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: #escaping ([String : Any]) -> Void) {
print ("message received")
print (message)
}
When I send a message from the Watch App, I get the following error
message sent
2017-12-03 19:33:03.903709+0530 Watch Extension[1761:74704] [WC] -[WCSession _onqueue_notifyOfMessageError:messageID:withErrorHandler:] 5BBE38F1-13C7-46E3-8E99-A874B43C6516 errorHandler: NO with WCErrorCodeDeliveryFailed
Debug window of iOS App gives me following info:
2017-12-03 19:35:28.706212+0530 WatchTest[1770:76097] [WC] -[WCSession onqueue_handleDictionaryMessageRequest:withPairingID:]_block_invoke delegate WatchTest.ViewController does not implement delegate method
2017-12-03 19:35:28.707992+0530 WatchTest[1770:76097] [WC] -[WCSession _onqueue_sendResponseError:identifier:dictionaryMessage:] identifier: 96B10064-F17B-4D4B-8F5C-1154984D5163 with WCErrorCodeDeliveryFailed
Am I missing any implementation in ViewController class? I am using Xcode 9.0
I changed the buttonClicked action method to following:
#IBAction func buttonClicked() {
if (WCSession.default.isReachable) {
let message = ["Message": "Hello"]
print ("message sent")
WCSession.default.sendMessage(message, replyHandler: { reply in
self.statusLabel.setText(reply["status"] as? String)
}, errorHandler: { error in
print("error: \(error)")
})
}
}
The sendMessage probably requires the reply and error handlers to be defined.
In obj-c I can get the temprature from a beacon with this block :
- (void)readTemperatureWithCompletion:(ESTNumberCompletionBlock)completion
How can I do this with SWIFT with a closure. I have been studying closures but still not sure how to run this block in SWIFT.
Can anyone advise ?
Thanks
This worked for me:
func beaconConnectionDidSucceeded(beacon: ESTBeacon) {
NSLog("beaconConnectionDidSucceeded")
beacon.readTemperatureWithCompletion() { value, error in
NSLog("readTemperatureWithCompletion, value = \(value), error = \(error)")
}
}
I believe this is more correct
beacon.readTemperatureWithCompletion({(temp:NSNumber!, error:NSError?) -> () in
if error? == nil{
println("\(temp)")
}else
{
println("Error \(error!.description)")
}
})
I am using the new iOS7 developer SDK and now the app request from the user his permission to record from mic when the App try to record in the first time.
My App will record after a countdown,so the user can't see this request.
I use this code to check the requestRecordPermission:
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
if (granted) {
// Microphone enabled code
}
else {
// Microphone disabled code
}
}];
But how can i trigger the request by myself before i start to record ?
In the new iOS7 it's very simple try this:
if([[AVAudioSession sharedInstance] respondsToSelector:#selector(requestRecordPermission)])
{
[[AVAudioSession sharedInstance] requestRecordPermission];
}
Here is final code snippet that does work for me. It support both Xcode 4 and 5, and works for iOS5+.
#ifndef __IPHONE_7_0
typedef void (^PermissionBlock)(BOOL granted);
#endif
PermissionBlock permissionBlock = ^(BOOL granted) {
if (granted)
{
[self doActualRecording];
}
else
{
// Warn no access to microphone
}
};
// iOS7+
if([[AVAudioSession sharedInstance] respondsToSelector:#selector(requestRecordPermission:)])
{
[[AVAudioSession sharedInstance] performSelector:#selector(requestRecordPermission:)
withObject:permissionBlock];
}
else
{
[self doActualRecording];
}
As "One Man Crew" claimed you can use requestRecordPermission.
Important thing to be aware of is that you must check that requestRecordPermission is implemented. The reason is that if your app would run on older iOS version (iOS 6.x for example) it would crash after this call.
To prevent that you must check that this selector is implemented (this is a good practice anyway).
Code should be something like this:
if([[AVAudioSession sharedInstance] respondsToSelector:#selector(requestRecordPermission:)]){
[[AVAudioSession sharedInstance] requestRecordPermission];
}
Using this method your app would support the new OS and also previous versions of the OS.
I'm using this method every time Apple add more functionality to new OS (that way I can support older versions pretty easy).
AVAudioSession.sharedInstance().requestRecordPermission({ (granted) -> Void in
if !granted
{
let microphoneAccessAlert = UIAlertController(title: NSLocalizedString("recording_mic_access",comment:""), message: NSLocalizedString("recording_mic_access_message",comment:""), preferredStyle: UIAlertControllerStyle.Alert)
var okAction = UIAlertAction(title: NSLocalizedString("OK",comment:""), style: UIAlertActionStyle.Default, handler: { (alert: UIAlertAction!) -> Void in
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
})
var cancelAction = UIAlertAction(title: NSLocalizedString("Cancel",comment:""), style: UIAlertActionStyle.Cancel, handler: { (alert: UIAlertAction!) -> Void in
})
microphoneAccessAlert.addAction(okAction)
microphoneAccessAlert.addAction(cancelAction)
self.presentViewController(microphoneAccessAlert, animated: true, completion: nil)
return
}
self.performSegueWithIdentifier("segueNewRecording", sender: nil)
});
Based on https://stackoverflow.com/users/1071887/idan's response.
AVAudioSession *session = [AVAudioSession sharedInstance];
// AZ DEBUG ## iOS 7+
AVAudioSessionRecordPermission sessionRecordPermission = [session recordPermission];
switch (sessionRecordPermission) {
case AVAudioSessionRecordPermissionUndetermined:
NSLog(#"Mic permission indeterminate. Call method for indeterminate stuff.");
break;
case AVAudioSessionRecordPermissionDenied:
NSLog(#"Mic permission denied. Call method for denied stuff.");
break;
case AVAudioSessionRecordPermissionGranted:
NSLog(#"Mic permission granted. Call method for granted stuff.");
break;
default:
break;
}
Swift 4:
let session = AVAudioSession.sharedInstance()
if (session.responds(to: #selector(AVAudioSession.requestRecordPermission(_:)))) {
AVAudioSession.sharedInstance().requestRecordPermission({(granted: Bool)-> Void in
if granted {
print("granted")
} else {
print("not granted")
}
})
}