Setup custom Haptic with latest Swift for iPhone7 and up - swift

After reading about it, I have some mess in my head.
This function is being called while user swipe his finger on some UI element :
func wasDragged() { signal here }
I would like to make small Haptic signals every time it's being called ( like a dates picker wheel )
How would I setup first time and make the signals of the Haptic Engine on call ?
Do I have to check for device kind ? I want it only on iPhone 7 and up.
Using latest Swift.

The documentation oh Haptic feedback is really descriptive.
But if you want some quick solution here it is.
var hapticGenerator: UISelectionFeedbackGenerator?
func wasDragged() {
hapticGenerator = UISelectionFeedbackGenerator()
haptiGenerator.selectionChanged()
hapticGeneraor = nil
}
Alternatively depending on the logic of the screen, you can initialize generator outside of wasDragged function and inside of it just call hapticGenerator.prepare() and selectionChanged(). In that case you should not assign nil to it after the dragging is complete because it won't get triggered again. As per documentation you have to release generator when no longer needed as Taptic Engine will wait and therefore consume system resources for another call.
Note that calling these methods does not play haptics directly.
Instead, it informs the system of the event. The system then
determines whether to play the haptics based on the device, the
application’s state, the amount of battery power remaining, and other
factors.
For example, haptic feedback is currently played only:
On a device with a supported Taptic Engine
When the app is running in the foreground
When the System Haptics setting is enabled
Documentation:
https://developer.apple.com/documentation/uikit/uifeedbackgenerator

Related

Cancel a smart alarm without any haptic feedback

I have create a smart alarm which relies on WKExtendedRuntimeSession.
There should be a possibility to manually stop the background session by, for example navigating back in the view hierarchy.
class BackgroundSessionController {
private var session: WKExtendedRuntimeSession?
func start() {
guard session?.state != .running else { return }
if nil == session || session?.state == .invalid {
session = WKExtendedRuntimeSession()
}
print("session started")
session?.start(at: Date())
}
func stopManual() {
session?.invalidate()
}
func stopByAlarm() {
session?.notifyUser(hapticType: .stop)
session?.invalidate()
}
}
When firing the function stopManual, and so invalidating the session I receive the message:
App has been running in the background but failed to play a scheduled
alarm. Would you like to disable the app's ability to run background
tasks ...
Seems that manually invalidating a session requires a haptic notification as well ?
How can I invalidate the session without the haptic feedback ?
added example:
let's say i'm a terrorist and i'm making a secret bomb which fires when movement stops. So you need to keep moving or else a timer starts counting down.
I Activate the app, I need to enable background modes, else the sensors stop working when the app goes into the background.
When movement stops, a smart alarm timer will fire .start(at:) which
counts down from 10 minutes.
I'm using smart alarm as functionality, which allows me to use 30 minutes of background modes. When these 30 minutes are finished and the person is still moving, i want to invalidate and then restart the session without sending any haptic feedback (the person will notice something isn'tright and deactivates the bomb)
What to use in this case then? This example is a bit weird but almost the same functionality I want.
The documentation of WKExtendedRuntimeSession clearly states this behaviour:
For sessions started with start(at:), you can only call invalidate() when the app is active. For all other sessions, you can call invalidate() to end a session at any time.
Since you are passing the current date for start(at:), why don't you just use start() instead and then you can call invalidate() even while your app is inactive. If you actually call start(at:) with a future date, then you don't have any alternatives.
The docs also state that you must play a haptic during your session. So if your session has started, you cannot invalidate it without playing a haptic. If your session hasn't started yet, you can invalidate it.
During the session, your app must trigger the alarm by calling the session’s notifyUser(hapticType:repeatHandler:) method.
If you fail to play a haptic during the session, the system displays a warning and offers to disable future sessions.
Bear in mind, this is probably a designed feature of watchOS. Due to the battery constraints of Apple Watches, watchOS puts an even bigger emphasis on apps being energy efficient, so if your app uses a background mode and the system thinks it might be abusing it (by declaring a smart alarm background mode, but not playing an alarm), it will alert the user.

How to put Apple Watch into waterproof mode?

I've got a swimming workout set up.
let configuration = HKWorkoutConfiguration()
configuration.activityType = .swimming
configuration.locationType = .outdoor
do {
workoutSession = try HKWorkoutSession(configuration: configuration)
workoutSession!.delegate = self
healthStore.start(workoutSession!)
} catch let error as NSError {
// Perform proper error handling here...
fatalError("*** Unable to create the workout session: \(error.localizedDescription) ***")
}
But my client is saying that the watch doesn't go into waterproof mode unless he manually makes it.
For context, "waterproof lock" is a mode that the Watch Series 2 is supposed to enter into when starting a swimming workout. From an Apple Support article:
When you start a swimming workout, your Apple Watch automatically locks the screen with Water Lock to avoid accidental taps. When you're done, turn the Digital Crown to unlock the screen and clear any water from your Apple Watch. You hear sounds and may feel some water on your wrist.
This functionality does not appear to be working with my app.
I only have a Series 0 to test on, so I can't confirm what's happening with my code with regards to the waterproof lock.
Am I missing something to make the workout force the watch into waterproof mode?
Available since watchOS 4:
https://developer.apple.com/documentation/watchkit/wkextension/2868458-enablewaterlock
// Only an application which is in an active workout or location session and is foreground is allowed to enable water lock
#available(watchOS 4.0, *)
open func enableWaterLock()
Call WKExtension.shared().enableWaterLock() when starting your swim / water workout.
There is currently no "waterproof mode". My client was under the impression that there was.
The native Apple Exercise app has a button that locks the watch and ignores interaction until the digital crown is rotated. This is not currently reproducible in third party apps.
The solution I have found is to disable all buttons on the watch app. This way, buttons are not accidentally tapped while in the water. The user has to force touch the watch to re-enable the buttons.

iphone html 5 video - how to start from different time

What is the correct way to begin playback of a video from a specific time?
Currently, the approach we use is to check at an interval whether it's possible to seek via currentTime and then seek. The problem with this is, when the video fullscreen view pops up, it begins playback from the beginning for up to a second before seeking.
I've tried events such as onloadmetadata and canplay, but those seem to happen too early.
Added information:
It seems the very best I can do is to set a timer that tries to set currentTime repeatedly as soon as play() is called, however, this is not immediate enough. The video loads from the beginning, and after about a second, depending on the device, jumps. This is a problem for me as it provides an unsatisfactory experience to the user.
It seems like there can be no solution which does better, but I'm trying to see if there is either:
a) something clever/undocumented which I have missed which allows you to either seek before loading or otherwise indicate that the video needs to start not from 00:00 but from an arbitrary point
b) something clever which allows you to hide the video while it's playing and not display it until it has seeked (So you would see a longer delay on the phone before the fullscreen video window pops up, but it would start immediately where I need it to instead of seeking)
do something like this;
var video = document.getElementsById("video");
video.currentTime = starttimeoffset;
more Information can be found on this page dedicated to video time offset howtos
For desktop browser Chrome/Safari, you can append #t=starttimeoffsetinseconds to your video src url to make it start from certain position.
For iOS device, the best we can do is to listen for the timeupdated event, and do the seek in there. I guess this is the same as your original approach of using a timer.
-R

Responding to events when device has been locked

I'm working on a radio alarm clock, and i have some issues.
I am using local notifications for the alarms, so it has a gentle fallback if the app is not running.
I am well aware of the limitations of the device, and i know what i can and cannot do when the device has gone into background.
But my question is this:
I have seen other apps starting an audio streamer when i've locked the device. How is this possible? May this be inside an execution-timeframe?
How is the best way to implement this? Is it any way i can activate a streaming session when the device is locked?
Edit
To clarify: I know how i make audio play in the background. But the issue is triggering the audio-playback when an local notification or some other event fires.
One app that seems to do this, is Radio Alarm Clock. I haven't tried it for long period of times yet. But it seems to do this. A video demo of the app: http://www.youtube.com/watch?v=KJQiFOcdBWk
Have you already declared your background task?
Support for some types of background execution must be declared in advance by the app that uses them. An app declares support for a service using its Info.plist file. Add the UIBackgroundModes key to your Info.plist file and set its value to an array containing one or more of the following strings:
audio — The app plays audible content to the user while in the background. (This content includes streaming audio or video content using AirPlay.)
iOS App Programming Guide - Implementing Long Running Background Tasks
You can add this by clicking on your main project icon, then under the Info tab you can add "Required Background Modes" to the "Custom iOS Target Properties" section. "App Plays Audio" will be one of the three default values.
Big Edit With New Answer:
If everything else is already in order, you can keep your app running in the background using the UIApplication method
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler
detailed here: UIApplication Class Reference
with an example here: Hour 21: Building Background-Aware Applications
This allows you to run an instance of NSTimer which triggers your music player. The difference between this approach and UILocalNotifications is that this method never lets the app fully enter the background mode, the music player exists the entire time which subverts the need to create it from the background, which looks to be impossible.
There may be limitations to how long of a timer you can set, I haven't tested this past 14 minutes out.

UIAccelerometer is Shaking

I want a functionality in which i want to detect if my device is being shaked.The problem is i can detect the shake with didAccelerate method of UIAcceleratorDelegate , but i dont know how to detect if the device is still shaking. I want to play an audio file when the user shakes the device for first time,i have to check if the user is still shaking the device while playing the 1st audio file,if it is still being shaked, then i have to play another file.
See the sample project GLPaint from Apple which was found by visiting http://developer.apple.com/iphone and entering "shake" in the search box. Developer account not required.
You might consider writing a Method that runs in a separate thread that polls wether your device is being shaken every now and then and fire events that you handle somewhere else in your code (or instead of that, handle whatever you want to handle within the threads context itself, even tough i would not recommend doing that).
You just have to make sure, that your "shake-detektor"-thread exits at some point in time, you probably want to do that when the second audio file stopped playing. So your loop could test on that condition.
Hope I could help a bit.