I've been working on setting up local notifications for my app in iOS 10, but when testing in the simulator I found that the notifications would be successfully scheduled, but would never actually appear when the time they were scheduled for came. Here's the code I've been using:
let UNcenter = UNUserNotificationCenter.current()
UNcenter.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
// Enable or disable features based on authorization
if granted == true {
self.testNotification()
}
}
Then it runs this code (assume the date/time is in the future):
func testNotification () {
let date = NSDateComponents()
date.hour = 16
date.minute = 06
date.second = 00
date.day = 26
date.month = 1
date.year = 2017
let trigger = UNCalendarNotificationTrigger(dateMatching: date as DateComponents, repeats: false)
let content = UNMutableNotificationContent()
content.title = "TestTitle"
content.body = "TestBody"
content.subtitle = "TestSubtitle"
let request = UNNotificationRequest(identifier: "TestID", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("error: \(error)")
} else {
print("Scheduled Notification")
}
}
}
From this code, it will always print "Scheduled Notification", but when the notification is supposed to be triggered, it never triggers. I've been unable to find any fix for this.
Here are a few steps.
Make sure you have the permission. If not, use UNUserNotificationCenter.current().requestAuthorization to get that. Or follow the answer below if you want to show the request pop up more than once.
If you want to show the notification foreground, having to assign UNUserNotificationCenterDelegate to somewhere.
This answer might help.
Related
I am trying to get Core Motion data from an Apple Watch 3 (WatchOS 5.1) but although the DeviceMotion is available (isDeviceMotionAvailable property is true), the handler is never triggered. I get the following message in the console right after parsing super.willActivate():
[Gyro] Manually set gyro-interrupt-calibration to 800
I am using the following function to get Device Motion updates:
func startQueuedUpdates() {
if motion.isDeviceMotionAvailable {
self.motion.deviceMotionUpdateInterval = 1.0 / 100.0
self.motion.showsDeviceMovementDisplay = true
self.motion.startDeviceMotionUpdates(using: .xMagneticNorthZVertical, to: self.queue, withHandler:{
(data, error) in
// Make sure the data is valid before accessing it.
if let validData = data {
print(String(validData.userAcceleration.x))
}
})
}
}
In the InterfaceController I have declared
let motion = CMMotionManager()
let queue : OperationQueue = OperationQueue.main
Has anyone met this message before and managed to resolve it?
Note: I have checked the isGyroAvailable property and it is false.
The trick here is to match the startDeviceMotionUpdates(using: CMAttitudeReferenceFrame parameter to your device's capabilities. If it has no magnetometer, it cannot relate to magnetic north, and even if it has a magnetometer, it cannot relate to true north unless it knows where you are (i.e. has latitude & longitude). If it hasn't got the capabilities to comply with the parameter you select, the update will be called, but the data will be nil.
If you start it up with the minimum .xArbitraryZVertical you will get updates from the accelerometer, but you won't get a meaningful heading, just a relative one, through the CMDeviceMotion.attitude property ...
if motion.isDeviceMotionAvailable {
print("Motion available")
print(motion.isGyroAvailable ? "Gyro available" : "Gyro NOT available")
print(motion.isAccelerometerAvailable ? "Accel available" : "Accel NOT available")
print(motion.isMagnetometerAvailable ? "Mag available" : "Mag NOT available")
motion.deviceMotionUpdateInterval = 1.0 / 60.0
motion.showsDeviceMovementDisplay = true
motion.startDeviceMotionUpdates(using: .xArbitraryZVertical) // *******
// Configure a timer to fetch the motion data.
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
if let data = self.motion.deviceMotion {
print(data.attitude.yaw)
}
}
}
I have the code to download two files from Server and store It to In local using URLSession (let dataTask = defaultSession.downloadTask(with: url)). Everything Is working fine only the problem is it's downloading first file it's giving me success but the second file is not downloading completely.. So, I hope there is a way to restart download for the second file that gives error ..
I think there is way of doing that and start looking into it and I found this delegate method .. but not much help .. can anyone please help me out how to restart download if it fails .. Do i have to use handleEventsForBackgroundURLSession to clear up previous downloads..?
// bellow download method will triggered when i get filenames I am passing it to this and path is optional here..
func download(path: String?, filenames: [String]) -> Int {
for filename in filenames {
var downloadFrom = "ftp://" + username! + ":"
downloadFrom += password!.addingPercentEncoding(withAllowedCharacters: .urlPasswordAllowed)! + "#" + address!
if let downloadPort = port {
downloadFrom += ":" + String(downloadPort) + "/"
} else {
downloadFrom += "/"
}
if let downloadPath = path {
if !downloadPath.isEmpty {
downloadFrom += downloadPath + "/"
}
}
downloadFrom += filename
if let url = URL(string: downloadFrom) {
let dataTask = defaultSession.downloadTask(with: url)
dataTask.resume()
}
}
return DLResponseCode.success
}
Please find delegate methods bellow ..
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
var responseCode = DLResponseCode.success
// Move the file to a new URL
let fileManager = FileManager.default
let filename = downloadTask.originalRequest?.url?.lastPathComponent
let destUrl = cacheURL.appendingPathComponent(filename!)
do {
let data = try Data(contentsOf: location)
// Delete it if it exists first
if fileManager.fileExists(atPath: destUrl.path) {
do{
try fileManager.removeItem(at: destUrl)
} catch let error {
danLogError("Clearing failed downloadFOTA file failed: \(error)")
responseCode = DLResponseCode.datalogger.failToCreateRequestedProtocolPipe
}
}
try data.write(to: destUrl)
} catch {
danLogError("Issue saving data locally")
responseCode = DLResponseCode.datalogger.noDataConnection
}
// Complete the download message
let message = DLBLEDataloggerChannel.Commands.download(responseCode: responseCode).description
connectionManagerDelegate?.sendMessageToDatalogger(msg: message)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if error == nil {
print("session \(session) download completed")
} else {
print("session \(session) download failed with error \(String(describing: error?.localizedDescription))")
// session.downloadTask(withResumeData: <#T##Data#>)
}
guard error != nil else {
return
}
danLogError("Session \(session) invalid with error \(String(describing: error))\n")
let responseCode = DLResponseCode.datalogger.failToCreateRequestedProtocolPipe
let message = DLBLEDataloggerChannel.Commands.download(responseCode: responseCode).description
connectionManagerDelegate?.sendMessageToDatalogger(msg: message)
}
// When I call didWriteData delegate method it's printing below data seems not dowloaded complete data ..
session <__NSURLSessionLocal: 0x103e37970> download task <__NSCFLocalDownloadTask: 0x108d2ee60>{ taskIdentifier: 2 } { running } wrote an additional 30028 bytes (total 988980 bytes) out of an expected 988980 bytes.
//error that I am getting for second file .. this error is coming some times not always but most of the times..
session <__NSURLSessionLocal: 0x103e37970> download failed with error Optional("cancelled")
Please help me out to figure it out .. If there is any way to handle download again after it fails or why it fails ..
The resume data, if the request is resumable, should be in the NSError object's userInfo dictionary.
Unfortunately, Apple seems to have completely trashed the programming guide for NSURLSession (or at least I can't find it in Google search results), and the replacement content in the reference is missing all of the sections that talk about how to do proper error handling (even the constant that you're looking for is missing), so I'm going to have to describe it all from memory with the help of looking at the headers. Ick.
The key you're looking for is NSURLSessionDownloadTaskResumeData.
If that key is present, its value is a small NSData blob. Store that, then use the Reachability API (with the actual hostname from that request's URL) to decide when to retry the request.
After Reachability tells you that the server is reachable, create a new download task with the resume data and start it.
I have a query regarding how to track milestones(Video) in brightcove player by using html 5.
There is already predefined events available for PLAY, PAUSE, STOP, but for the tracking the milestones i am unable to track it via DTM.
Below mentioned is the code,which i have written for PLAY & PAUSE -
CODE -
videojs('te-brightcove-trigger-video_html5_api').on('play',function(){
var myPlayer = this;
console.log('play');
s.linkTrackVars='events,eVar21,prop21';
s.linkTrackEvents='event22';
s.eVar21 = myPlayer.mediainfo.name;
s.prop21 = myPlayer.mediainfo.name;
s.events = 'event22';
s.tl(this, 'o');
});
videojs('te-brightcove-trigger-video_html5_api').on('pause',function(){
console.log('pause');
var myPlayer = this;
s.linkTrackVars='events,eVar21,prop21';
s.linkTrackEvents='event21=6,event24';
s.eVar21 = myPlayer.mediainfo.name;
s.prop21 = myPlayer.mediainfo.name;
s.events = 'event21=6';
s.events = 'event24';
s.tl(this, 'o');
});
Okay look, I'm not sure what exactly you are having trouble with, but posting new questions asking the same thing isn't going to help you. You keep posting these questions asking for help on milestones, but I have yet to see you pony up any code directly relevant to milestones. If you want actual help with understanding where you went wrong, then post what you have actually tried that is relevant to your question.
In general, here is a working example of what you should be doing.
// keep track of events that are triggered to only trigger them once
videojs('te-brightcove-trigger-video_html5_api')._isEventViewed = {};
videojs('te-brightcove-trigger-video_html5_api').on('play',function(){
if (!this._isEventViewed.play) {
console.log('VIDEO: tracking PLAY event');
/* tracking code here */
this._isEventViewed.play=true;
}
});
videojs('te-brightcove-trigger-video_html5_api').on('pause',function(){
if (!this._isEventViewed.pause) {
console.log('VIDEO: tracking PAUSE event');
/* tracking code here */
this._isEventViewed.pause=true;
}
});
videojs('te-brightcove-trigger-video_html5_api').on('timeupdate',function(){
var currentTime = Number(this.currentTime());
var duration = Number(this.duration());
var percentViewed = Math.floor((currentTime/duration)*100);
var ev = this._isEventViewed;
//console.log(currentTime,' / ', duration, ' - ',percentViewed);
//console.log('_isEventViewed:',ev);
switch(true) {
case (!ev['25'] && percentViewed >= 25) :
console.log('VIDEO: tracking 25% MILESTONE event');
/* tracking code here */
ev['25']=true;
break;
case (!ev['50'] && percentViewed >= 50) :
console.log('VIDEO: tracking 50% MILESTONE event');
/* tracking code here */
ev['50']=true;
break;
case (!ev['75'] && percentViewed >= 75) :
console.log('VIDEO: tracking 75% MILESTONE event');
/* tracking code here */
ev['75']=true;
break;
} // end switch percentViewed
});
videojs('te-brightcove-trigger-video_html5_api').on('ended',function(){
if (!this._isEventViewed.ended) {
console.log('VIDEO: tracking ENDED event');
/* tracking code here */
this._isEventViewed.ended=true;
}
});
I am trying to create 3 notifications with 10 seconds gap. However, It only plays the first sound and it repeats forever with 10 seconds gap. Can you please examine my code and tell me what I am doing wrong?
local futureTime = 10 --10 seconds
local sounds = {"Icebaby.mp3", "Pokemon.mp3", "Yoshi.mp3"}
i=1
local options = {
alert = "Wake up!",
sound = "Icebaby.mp3" ,
custom = { msg = "Alarm" }
}
local notificationID = system.scheduleNotification( futureTime, options )
local function notificationListener( event )
system.cancelNotification(notificationID)
i=i+1
options.sound=sounds[i]
if(i>3) then
Runtime:removeEventListener ( "notification", notificationListener )
else
notificationID = system.scheduleNotification( futureTime, options )
end
end
Runtime:addEventListener( "notification", notificationListener )
1st problem: "It only plays the first sound"
-> Yes, because you don't change the options table. So it's always this options table:
local options = {
alert = "Wake up!",
sound = "Icebaby.mp3" ,
custom = { msg = "Alarm" }
}
Change the options table each time you create the next notification. For example use your "sounds" table!
I am trying to implment the XMPP Client. I am using BOSH Connection manager and can run the Strophe.connect but not Strophe.Attach. I have tried incrementing the RID, but no effect.. Any help please ? There is no error here, but the Strophe.Status.CONNECTED is never reached via the attach method and so I cannot send IQ or Presence.
Here is my code
try
{
var cookieJid = $.cookie("jid");
var cookieSid = $.cookie("sid");
var cookieRid = $.cookie("rid");
var connt = new Strophe.Connection("http://localhost:7070/http-bind/");
connt.attach(cookieJid, cookieSid, cookieRid + 1, function(status)
{
if (status === Strophe.Status.CONNECTED)
{
alert ("hola connected");
$("#userName").append("hola connected : " + connt.jid );
var iq = $iq({type: 'get'}).c('query', {xmlns: 'jabber:iq:roster'});
connt.sendIQ(iq, handleRoster);
connt.send($pres());
}
});
}
catch (e)
{
$("#userName").append("Pinky error is " + e);
}
Edit
Thanks Eric and Charlie.
So I took the latest Strophe.js and now Attached status does work.
But the connection disconnects instantaneously. I am not even able to fetch the Roster.
We can possibly do every thing with Connection.attach() as we would with connection.connect(), right?
Any thoughts?
Change the line:
if (status === Strophe.Status.CONNECTED)
...to...
if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED)
Are you using the latest Strophe library? In the version I'm using, I see that the status can be these values:
Status: {
ERROR: 0,
CONNECTING: 1,
CONNFAIL: 2,
AUTHENTICATING: 3,
AUTHFAIL: 4,
CONNECTED: 5,
DISCONNECTED: 6,
DISCONNECTING: 7,
ATTACHED: 8
}
Make sure you convert your cookieRid to a Number by using new Number(cookieRid). Otherwise, when you do +1 on it, you will get "####1".
You can test this out for yourself in Javascript:
var s = "123";
alert(s+1); // "1231" and not "124"
Also, as Eric answered, there is a status ATTACHED so you need to handle that event.