How to add snooze effect once a notification is delivered in ios 10 - objective-c

I am implementing UserNotification in my app. When the notification gets fired it shows two action, in one i want to add snooze effect, it must snooze after 5 mins again. How to handle it ? thanks for all ! help if any one do have idea

Well to snooze notification you can create another notification with same details of current notification and increase the fire date by 5 mins.
Here is the code I used :
func snoozeScheduledNotification(notification:UILocalNotification) -> Void {
// Snooze for 10 mins
let localNotification = UILocalNotification()
localNotification.fireDate = notification.fireDate?.addingTimeInterval(60*10)
localNotification.repeatInterval = NSCalendar.Unit(rawValue: 0) // 0 = No Repeat
localNotification.alertBody = notification.alertBody
localNotification.soundName = notification.soundName
localNotification.userInfo = notification.userInfo
localNotification.category = notification.category
UIApplication.shared.scheduleLocalNotification(localNotification)
}
Hope it helps you.

The shortest and simplest code I found about it
For Swift 3/4
extension UNNotification {
func snoozeNotification(for hours: Int, minutes: Int, seconds: Int) {
let content = UNMutableNotificationContent()
content.title = "Another Alert"
content.body = "Your message"
content.sound = .default()
let identifier = self.request.identifier
guard let oldTrigger = self.request.trigger as? UNCalendarNotificationTrigger else {
debugPrint("Cannot reschedule notification without calendar trigger.")
return
}
var components = oldTrigger.dateComponents
components.hour = (components.hour ?? 0) + hours
components.minute = (components.minute ?? 0) + minutes
components.second = (components.second ?? 0) + seconds
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: false)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
debugPrint("Rescheduling failed", error.localizedDescription)
} else {
debugPrint("rescheduled success")
}
}
}
}
You just need to call it this way :
response.notification.snoozeNotification(for: 0, minutes: 0, seconds: 30)
Credit goes to Simon Ljungberg : https://gist.github.com/simme/96264d5ceee394083d18e2c64f42a3a9

For iOS10, use this code.
Use this code in AppDelegate.swift file.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
let center = UNUserNotificationCenter.current()
let category = UNNotificationCategory(identifier: "identifier", actions: [], intentIdentifiers: [])
center.setNotificationCategories([category])
center.requestAuthorization(options: [.badge, .alert , .sound]) { (greanted, error) in
print(error)
}
return true
}
You can put this code in any view controller.
let content = UNMutableNotificationContent.init()
content.title = "Notification Title"
content.subtitle = "Notification Sub-Title"
content.body = "Notification Body"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "identifier", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
UNUserNotificationCenter.current().delegate = self
if (error != nil){
//handle here
}
}
You can handle notification using following method:
extension UIViewController: UNUserNotificationCenterDelegate {
public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Swift.Void) {
completionHandler( [.alert, .badge, .sound])
}
public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Swift.Void) {
print("Tapped in notification")
}
}
You can use this Blog as reference and Example.

Related

Client Certificate Selection at run time and use as a URL Credentials using WKWebView is not working. (NSURLAuthenticationMethodClientCertificate)

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
switch challenge.protectionSpace.authenticationMethod {
case NSURLAuthenticationMethodClientCertificate:
let query: [String:Any] = [kSecAttrAccessGroup as String: kSecAttrAccessGroupToken,
kSecAttrKeyClass as String : kSecAttrKeyClassPrivate,
kSecClass as String : kSecClassIdentity,
kSecReturnAttributes as String : kCFBooleanTrue as Any,
kSecReturnRef as String: kCFBooleanTrue as Any,
kSecMatchLimit as String: kSecMatchLimitAll,
kSecReturnPersistentRef as String: kCFBooleanTrue as Any
]
var result : AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
guard status == errSecSuccess, let allItems = result as? [[String: Any]] else {
let errorDescription = SecCopyErrorMessageString(status, nil)
print(errorDescription as Any)
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let items = allItems.filter { item in
return (item["tkid"] as? String)?.starts(with: "Bundle ID") ?? false
// return true
}
// **items are the certificates which is already added in device**
// Let user select which cert to use, handle pin entry and call the completion handler.
let alert = UIAlertController.selectCertAndPinEntryAlert(certs: items, completionHandler: completionHandler)
alert.show()
case NSURLAuthenticationMethodServerTrust:
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, credential);
case NSURLAuthenticationMethodHTTPBasic:
print("Basic auth")
default:
completionHandler(.useCredential, nil)
}
}
selectCertAndPinEntryAlert : this method allows user to choose the certificate which is already added in Keychain.
static func selectCertAndPinEntryAlert(certs: [[String : Any]], completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> UIAlertController {
// Select cert UIAlertController.
let alert = UIAlertController(title: "Select certificate", message: nil, preferredStyle: .actionSheet)
certs.forEach { item in
guard let certData = item["certdata"] as? Data else { return }
guard let certificate = SecCertificateCreateWithData(nil, certData as CFData) else { return }
alert.addAction(UIAlertAction(title: certificate.commonName,
style: .default,
handler: { action in
// Pin entry UIAlertController created after the user selected one of the certs.
let passwordAlert = UIAlertController(title: "Enter pin", message: nil, preferredStyle: .alert)
passwordAlert.addTextField { textField in
textField.isSecureTextEntry = true
}
passwordAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
completionHandler(.cancelAuthenticationChallenge, nil)
})
passwordAlert.addAction(UIAlertAction(title: "Ok",
style: .default,
handler: { action in
guard let pin = passwordAlert.textFields?.first?.text else { completionHandler(.cancelAuthenticationChallenge, nil); return }
** let secIdentity = item["v_Ref"] as! SecIdentity
let urlCredential = URLCredential(identity: secIdentity, certificates: nil, persistence: .forSession)**
// If this doesn't return a UserDefaults something is broken in the project and we might as well crash.
UserDefaults(suiteName: "App Group which used by app")!.writePin(pin)
**completionHandler(.useCredential, urlCredential)**
}))
passwordAlert.show()
}))
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
completionHandler(.cancelAuthenticationChallenge, nil)
})
return alert
}
Please provide the suggestion what i am doing wrong. What code i need to change?
Note : I am using Yubikey for fetching certificates and storing it into the keychain. Later All the added certificate popup i ll get to choose one.
I have tried this code but when i am entring the key to access the certificate, WKWebView is not taking this certificate as further process and i am getting URL Credentials as null in response.

How to make HTTP post request with specific body? And how to access token from the server to allow me to login?

I'm having a scenario like :
1) I want to create Http POST request and for this I'm having the data, please see this image:
2) As you can see in the above image, I have to create post a request with the mentioned body and also I'm getting response named: token. How to create post request and fetch this token response?.
3) That token response will allow me to login into myapp.
I'm newbie to this scenario. I have tried some code by my own but still getting confuse in how to combine my app delegate code with this POST Request Code.
Code
#IBAction func signinaction(_ sender: Any) {
self.username.resignFirstResponder()
self.password.resignFirstResponder()
if (self.username.text == "" || self.password.text == "") {
let alertView = UIAlertController(title: "Login failed",
message: "Wrong username or password." as String, preferredStyle:.alert)
let okAction = UIAlertAction(title: "Try Again!", style: .default, handler: nil)
alertView.addAction(okAction)
self.present(alertView, animated: true, completion: nil)
return
}
// Check if the user entered an email
if let actualUsername = self.username.text {
// Check if the user entered a password
if let actualPassword = self.password.text {
// Build the body message to request the token to the web app
self.bodyStr = "username=8870417698&password=1234&grant_type=password" + actualUsername + "&password=" + actualPassword
// Setup the request
let myURL = NSURL(string: "http://ezschoolportalapi.azurewebsites.net/token")!
let request = NSMutableURLRequest(url: myURL as URL)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = bodyStr.data(using: String.Encoding.utf8)!
let task = URLSession.shared.dataTask(with: request as URLRequest) {
(data, response, error) -> Void in
if data?.count != 0
{
do {
let tokenDictionary:NSDictionary = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! NSDictionary
print(tokenDictionary)
// Get the token
let token:String = tokenDictionary["access_token"] as! String
// Keep record of the token
let userdefaults = UserDefaults()
let saveToken = userdefaults.set(token, forKey: "access_token")
userdefaults.synchronize()
// Dismiss login view and go to the home view controller
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
catch {
// Wrong credentials
// Reset the text fields
self.username.text = ""
self.password.text = ""
// Setup the alert
let alertView = UIAlertController(title: "Login failed",
message: "Wrong username or password." as String, preferredStyle:.alert)
let okAction = UIAlertAction(title: "Try Again!", style:.default, handler: nil)
alertView.addAction(okAction)
self.present(alertView, animated: true, completion: nil)
return
}
}
}
task.resume()
}
}
}
Question is how to combine this code with my above code :
let appDelegate = UIApplication.shared.delegate as! AppDelegate appDelegate.gotoMainvc()
if I use directly this code then in any of the case I'm able to switch over to my home screen it doesn't matter whether m using this POST Request code or not. Please Help.
You are hard coding the username and password in bodyStr update it to
self.bodyStr = "username=" + actualUsername + "&password=" + actualPassword + "&grant_type=password"
Update the statements inside do with
do {
let tokenDictionary:NSDictionary = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! NSDictionary
print(tokenDictionary)
// Get the token
if let authToken = tokenDictionary["access_token"] as? String{
self.token = authToken
UserDefaults.standard.set(accessToken, forKey: "access_token")
UserDefaults.standard.synchronize()
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
}
You can implement a function like isUserLoggedIn which will return true if token is saved in userDefaults. You need to check whether the user has logged in in the appDelegate's applicationdidFinishLaunchingWithOptions.Like
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if isUserLoggedIn(){
//showHomeViewController
} else{
//showLoginViewController
}
return true
}
func isUserLoggedIn() -> Bool{
if let accessToken = UserDefaults.standard.object(forKey: "access_token") as? String {
if (accessToken.characters.count)! > 0{
return true
} else {
return false
}
}
else {
return false
}
}

No sound from remote notification

Could some one help me to understand why i'm not receiving sound from remote notifications in IOS 10 Swift 3.
Here is my code:
AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]?) -> Bool {
let settings = UNUserNotificationCenter.current()
settings.requestAuthorization(options: [.badge, .alert, .sound]) {(granted, error) in
}
return true
}
// Override point for customization after application launch.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
let viewController = self.window?.rootViewController as! LoadingCloudDataViewController
let notification: CKNotification = CKNotification(fromRemoteNotificationDictionary: userInfo as! [String: NSObject])
if(notification.notificationType == CKNotificationType.query) {
let queryNotification = notification as! CKQueryNotification
let recordID = queryNotification.recordID
viewController.fetchRecord(recordID: recordID!)
}
}
And here is the notification subscription code:
func subscriptionNotificationsKcal() {
publicDatabase = container.publicCloudDatabase
let predicate = NSPredicate(format: "TRUEPREDICATE")
let subscription = CKQuerySubscription(recordType: "Kcal", predicate: predicate, options: .firesOnRecordCreation)
let notificationInfo = CKNotificationInfo()
notificationInfo.alertBody = "New Calories Item was Added"
notificationInfo.shouldBadge = true
subscription.notificationInfo = notificationInfo
publicDatabase?.save(subscription, completionHandler: ({returnRecord, error in
if let err = error {
print("subscription failed %#", err.localizedDescription)
}else{
print("sub success")
}
}))
}
By default the sound is muted. To activate it, in the case of this example, use the following code:
notificattionInfo.soundName = "default"

Swift / How to parse json from java spring code

I want to parse json from java spring code (Xcode 7.3 / Swift). I tried almost every solution from all sites.
When I register it gives the following error message at the console:
Response = Optional(<NSHTTPURLResponse: 0x7a7607e0> { URL: http://www.____.com/saveRegistrationJson.htm } { status code: 405, headers {
Allow = GET;
Connection = "Keep-Alive";
"Content-Length" = 1089;
"Content-Type" = "text/html;charset=utf-8";
Date = "Wed, 04 May 2016 12:21:34 GMT";
"Keep-Alive" = "timeout=15, max=100";
Server = "Apache-Coyote/1.1";
} })
before json
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
This is my Code:
import UIKit
class RegistrationViewController: UIViewController {
#IBOutlet weak var userfnametextfield: UITextField!
#IBOutlet weak var userlnametextfield: UITextField!
#IBOutlet weak var useremailtextfield: UITextField!
#IBOutlet weak var userpwdtextfield: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func RegisterbtnTapped(sender: AnyObject) {
let fname = userfnametextfield.text
let lname = userlnametextfield.text
let Email = useremailtextfield.text
let pwd = userpwdtextfield.text
//check empty fields
if(fname!.isEmpty || lname!.isEmpty || Email!.isEmpty || pwd!.isEmpty )
{
DisplayMyAlertMessage("All Fields are required")
return
}
//store data
NSUserDefaults.standardUserDefaults().setObject(fname, forKey: "fname")
NSUserDefaults.standardUserDefaults().setObject(lname, forKey: "lname")
NSUserDefaults.standardUserDefaults().setObject(Email, forKey: "Email")
NSUserDefaults.standardUserDefaults().setObject(pwd, forKey: "password")
NSUserDefaults.standardUserDefaults().synchronize()
//send user data to server side
let myurl = NSURL(string: "http://www.____.com/saveRegistrationJson.htm")
let request = NSMutableURLRequest(URL: myurl!)
request.HTTPMethod = "POST"
let poststring = "fname\(fname!)&lname\(lname!)&email\(Email!)&password\(pwd!)"
request.HTTPBody = poststring.dataUsingEncoding(NSUTF8StringEncoding)
//request.HTTPBody = postData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){data,response, error in
if error != nil{
print("Error\(error)")
return
}
print("Response = \(response)")
do{
var err : NSError?
print("before json")
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as? NSDictionary
print(json)
print("After json")
//print("demo : \(response?.description)")
guard let parseJSON = json else{
print("parsing json here:")
return
}
// guard let value = NSString(data: data!, encoding: NSUTF8StringEncoding) else{
// print("parsed")
// return
//}
//print("FirstName\(value)")
var requestValue = parseJSON[" "] as? String
print("result:\(requestValue)")
var isUserRegistered:Bool = false
if(requestValue=="Success") { isUserRegistered = true}
var messageToDisplay:String = parseJSON["Success"] as! String
if(!isUserRegistered){
messageToDisplay = parseJSON[" "] as! String
}
dispatch_async(dispatch_get_main_queue(), {
let myAlert = UIAlertController(title: "Alert", message: messageToDisplay, preferredStyle: UIAlertControllerStyle.Alert)
let onAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) { (ACTION) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}
myAlert.addAction(onAction)
self.presentViewController(myAlert, animated: true, completion: nil)
})
}
catch let error as NSError
{
print(error)
}
}
task.resume()
Help is very appreciated.

How to continue Alamofire Download task after suspend it, terminate the app, and reopen the app

I need to write a downloader for my app, and It can pause, continue and cancel the downloads. Also it must support to pause download, kill the app, and reopen the app and continue from where it paused.
How can i keep the downloaded data and how can I continue it?
import UIKit
import Foundation
import Alamofire
class DownloaderViewController: UIViewController {
#IBOutlet weak var label: UILabel!
let progressIndicatorView = UIProgressView()
var request: Alamofire.Request?
override func viewDidLoad() {
super.viewDidLoad()
}
}
#IBAction func cancelBtn(sender: AnyObject) {
self.request?.cancel()
self.label.text = "% 0.0"
}
#IBAction func pauseBtn(sender: AnyObject) {
self.request?.suspend()
}
#IBAction func continueBtn(sender: AnyObject) {
self.request?.resume()
}
#IBAction func startBtn(sender: AnyObject) {
var localPath: NSURL?
self.request = Alamofire.download(.GET, "https://dl.dropboxusercontent.com/u/11563257/3.%20Interactive_iPad_test_for_PDF_EXPERT.pdf", destination: { (temporaryURL, response) in
let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
localPath = directoryURL.URLByAppendingPathComponent(pathComponent!)
return localPath!
}).progress() {
(_, totalBytesRead, totalBytesExpectedToRead) in
dispatch_async(dispatch_get_main_queue()) {
self.progressIndicatorView.setProgress(Float(totalBytesRead) / Float(totalBytesExpectedToRead), animated: true)
self.updateProgress(self.progressIndicatorView)
if totalBytesRead == totalBytesExpectedToRead {
self.progressIndicatorView.removeFromSuperview()
}
}
}
func updateProgress(prg:UIProgressView) {
let stepSize:Float = 0.1
prg.setProgress(prg.progress + stepSize, animated: true)
self.label.text = "% " + String(format: "%.2f", prg.progress*100)
}
}
This works while the app is running. But I need to save the data when the app is terminated and continue it when the app started. I have no i idea how to keep the downloaded data and how to continue it. Any help will be appriciated.
I find this in Alamofire documentation :
Alamofire.download(.GET, "https://httpbin.org/stream/100", destination: destination)
.response { _, _, data, _ in
if let
data = data,
resumeDataString = NSString(data: data, encoding: NSUTF8StringEncoding)
{
print("Resume Data: \(resumeDataString)")
} else {
print("Resume Data was empty")
}
}
But I get "Resume Data was empty" everytime. I give the same destination. But It can't catct the Resume Data. And I couldn't find an example with Alamofire.