I am trying to present a local notification on an Apple Watch simulator with a button. This is the code:
#IBAction func buttonOne() {
print("button one pressed")
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: "Notified!", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "This is a notification appearing!", arguments: nil)
// Deliver the notification in five seconds.
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5,
repeats: false)
// Schedule the notification.
let request = UNNotificationRequest(identifier: "Notify", content: content, trigger: trigger)
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
} else {
print("successful notification")
}
}
}
The console is successfully printing "successful notification," but the notification never appears on the watch simulator. I have no idea why this is
1) Before scheduling a notification, request permissions. Use requestAuthorization method, for example:
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization
}
2) Notifications will not appear on watch face if the application is running in foreground. Considering this you may use cmd + H to hide the app.
Related
I have created a piece of code to send a local notification at 3 pm and the user can toggle it with a toggle switch. I used an AppStorage wrapper to remember the state it was in. The code works until I toggle the switch on and off (simulating whether the user switches it multiple times) and the number of times I switched the toggle, that same number comes as a notification (i.e. I toggle 5 times, I get 5 notifications all at once). this is the code
struct trial: View {
#AppStorage("3") var three = false
func firstNotify() {
let content = UNMutableNotificationContent()
content.title = "It is 3pm"
content.subtitle = "Read the Prime Hour"
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "notifysound.wav"))
// content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "notifysound"))
var dateComponents = DateComponents()
dateComponents.hour = 15
dateComponents.minute = 00
dateComponents.second = 00
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
// choose a random identifier
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
// add our notification request
UNUserNotificationCenter.current().add(request)
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
print("All set!")
} else if let error = error {
print(error.localizedDescription)
}
}
}
#State private var name: String = "Tim"
var body: some View {
VStack {
Toggle(isOn: $three) {
Text("3 pm")
}
.padding(.horizontal)
.onChange(of: three) { newValue in
if newValue {
firstNotify()
}
}
}
}
}
struct trial_Previews: PreviewProvider {
static var previews: some View {
trial()
}
}
I think what's happening is that the func is not reading whether the toggle is on or off but just adds a notification each time the switch gets turned on. Would anyone know the solution to this???
The toggle is really only scheduling a new notification on every change of the value to true.
This piece of code means that a new notification will be scheduled each time this method is called.
// choose a random identifier
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
// add our notification request
UNUserNotificationCenter.current().add(request)
Not entirely sure what the desired logic is, but you could solve this by either updating the existing notification or clearing out the old one and adding a new one. Rather than creating a new UUID for each notification, it may be best to have an ID convention or otherwise store it so it can be accessed or removed.
You could store the rather than the toggle value:
#AppStorage("notification_id") var notificationID = nil // I don't know if this can be a string or nil, but hopefully it leads you in the right direction.
// Then when creating the request.
let id = notificationID ?? UUID().uuidString
let request = UNNotificationRequest(identifier: id, content: content, trigger: trigger)
notificationID = id
And there needs to be another method when to unschedule when they toggle the other direction. You could simply check to see if the id exists.
if let id = notificationID {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers identifiers: [id])
// OR
UNUserNotificationCenter.current()removeAllPendingNotificationRequests()
}
How do I know that my device is blocked from receiving VoIP notifications?
The application stops receiving VoIP notifications after receiving for 3-4 times. I understand that from iOS 13 VoIP notifications should be reported to CallKit. Even after reporting to CallKit, I'm going through this issue of not receiving VoIP notifications.
We have set apns-expiration to 0 and the priority to immediately(10).
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: #escaping () -> Void) {
dictPayload = payload.dictionaryPayload[K.KEY.APS] as? [String : Any]
if dictPayload![K.KEY.ALERTTYPE] as? String == K.KEY.VOIPCALL {
self.displayIncomingCall(uuid: appDelegate.uudiForCall, handle: (self.dictPayload!["handle"] as? String)!) { (error) in
}
CallProviderDelegate.sharedInstance.callDidReceiveIncomingCallfromKill(callInfo: self.dictPayload!)
} else if dictPayload![K.KEY.ALERTTYPE] as? String == K.KEY.PUSHTOTALK {
isPTTON = true
pjsua_set_no_snd_dev()
CallHandler.sharedCallManager()?.muteCall(true)
CallHandler.sharedCallManager()?.setAudioSessionSpeaker()
CallProviderDelegate.sharedInstance.callDidReceivePTTFromKIll(callFromName: dictPayload!["title"] as? String, callfromExt: dictPayload![K.KEY.BODY] as? String)
} else if dictPayload![K.KEY.ALERTTYPE] as? String == K.KEY.HANGUP {
isPTTON = false
CallProviderDelegate.sharedInstance.endCallFromPTT(endCallUDID: appDelegate.uudiForCall)
}
}
func displayIncomingCall(
uuid: UUID,
handle: String,
hasVideo: Bool = false,
completion: ((Error?) -> Void)?
) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .phoneNumber, value:(handle))
CallProviderDelegate.sharedInstance.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in })
}
XCODE: 11.3.1,
SWIFT: 4.2 &
iOS: 13.0 +
I am trying to figure out this issue since the last 2 months but not able to resolve it. Please help me
Thanks In Advance.
Actually, it seems that you aren't reporting a new incoming call for every VoIP push notification. It's true that when there is an active CallKit call, you can receive VoIP pushes without reporting a new incoming call, but it's not as simple as it might seem. Since CallKit and PushKit are asynchronous, you are not guaranteed that when you receive a push of type K.KEY.PUSHTOTALK or K.KEY.HANGUP the call has already started. Moreover, if dictPayload is nil, you fail to report a new incoming call.
Anyway, I think that the biggest problem in your code is that you're not calling the completion handler of the pushRegistry(:didReceiveIncomingPushWith...) method. You should do the following:
self.displayIncomingCall(uuid: appDelegate.uudiForCall, handle: (self.dictPayload!["handle"] as? String)!) { (error) in
completion() // <---
}
and
CallProviderDelegate.sharedInstance.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in
completion()
})
// or
CallProviderDelegate.sharedInstance.provider.reportNewIncomingCall(with: uuid, update: update, completion: completion)
I am attempting to implement Square Connect iOS SDK, and after implementing and clicking the pay button it opens up the Square Payment app and redirects to a blank page .. have you guys had the same issues ?
My App delegate has the proper section:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
guard let sourceApplication = options[.sourceApplication] as? String,
sourceApplication.hasPrefix("com.squareup.square") else {
return false
}
do {
let response = try SCCAPIResponse(responseURL: url)
if let error = response.error {
// Handle a failed request.
print(error.localizedDescription)
} else {
// Handle a successful request.
}
} catch let error as NSError {
// Handle unexpected errors.
print(error.localizedDescription)
}
return true
}
I have created a proper URL scheme inside the Square portal. Also my view controller has the correct code:
func charge()
{
// connect v1
if let callbackURL = URL(string: "myscheme://")
{
do
{
SCCAPIRequest.setClientID("xxxxxxxxxxx")
let amount = try SCCMoney(amountCents: 100, currencyCode: "USD")
let request = try SCCAPIRequest(
callbackURL: callbackURL,
amount: amount,
userInfoString: nil,
locationID: nil,
notes: "Purchase for cleaning",
customerID: nil, supportedTenderTypes: .all,
clearsDefaultFees: true,
returnAutomaticallyAfterPayment: true)
try SCCAPIConnection.perform(request)
}
catch let error as NSError {
print(error.localizedDescription)
}
}
}
https://snag.gy/R4A30L.jpg
Andrei
You need to make sure you delete all apps from the phone with having duplicate bundle ids. This way you will make sure you go back to the original app which triggered the payment.
I am making an iPad game in sprite kit using swift in xcode 7beta3 and I want the results of the game to be send to the users email after the game is completed. The user should press a button called send and redirect to where they can type in their email-address and send the message. But I have no idea how to make and send an email.
I have been searching all around the internet for an answer to this question, but all are older version answers. I hope you can help.
Thanks in advance
EDIT:
I have been searching some more and i found a solution (here: http://kellyegan.net/sending-files-using-swift/), but I still have a problem. In my GameViewController i have added:
override func viewDidLoad() {
super.viewDidLoad()
let scene = StartGameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .ResizeFill
skView.presentScene(scene)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
internal func sendEmail() {
//Check to see the device can send email.
if( MFMailComposeViewController.canSendMail() ) {
print("Can send email.")
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
//Set the subject and message of the email
mailComposer.setSubject("Have you heard a swift?")
mailComposer.setMessageBody("This is what they sound like.", isHTML: false)
if let filePath = NSBundle.mainBundle().pathForResource("Math", ofType: "txt") {
print("File path loaded.")
if let fileData = NSData(contentsOfFile: filePath) {
print("File data loaded.")
mailComposer.addAttachmentData(fileData, mimeType: "text/plain", fileName: "Math")
}
}
self.presentViewController(mailComposer, animated: true, completion: nil)
}
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
self.dismissViewControllerAnimated(true, completion: nil)
}
The sendMail() is called in one of my gameScenes when you press a button.
The problem is that I get an error when I press that button. It prints out
Can send email.
File path loaded.
File data loaded.
as it should, but then it gives an error:
Could not cast value of type 'UIView' (0x1964ea508) to 'SKView' (0x19624f560).
I think the problem is the self.presentViewController(), but I have no idea how to fix it.
i'm developing a mac app that requires email access
here's the code i've tried on ios
-(IBAction)Contact us:(id)sender {
//Email Subject
NSString *emailTitle = #"";
//Email Content
NSString *messageBody = #"";
//Email Address
NSArray *toRecipients =[NSArray arrayWithObject:#"info#mandarin-espeak.com"];
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:emailTitle];
[mc setMessageBody:messageBody isHTML:YES];
[mc setToRecipients:toRecipients];
}
how can i do it on a mac app to open default email client
In MacOS you can easily send e-mails like this:
class SendEmail: NSObject {
static func send() {
let service = NSSharingService(named: NSSharingServiceNameComposeEmail)!
service.recipients = ["abc#dom.com"]
service.subject = "Vea software"
service.performWithItems(["This is an email for auto testing through code."])
}
}
Usage:
SendEmail.send()
I ended up going with an AppleScript solution. This is a one off app, not for the store, so I turned sandboxing off. I also added Privacy - AppleEvents Sending Usage Description to the info.plist and in the Hardened Runtime under Signing and Capabilities checked Apple Events
My email code, shouldn't be too hard to pan out my unique stuff:
func emailUser(_ thisUser:NSManagedObject) {
let dictSIPResponse = checkSIPforAppIdentifier("com.microsoft.Outlook")
if let bIsSIPEnabled = dictSIPResponse["isSIPEnabled"] as? Bool, let strSIPMessage = dictSIPResponse["sipMessage"] as? String{
if bIsSIPEnabled {
if let thisWriter = thisUser as? Writer, let strEmailAddress = thisWriter.email {
let outlookScript = """
if application "Outlook" is running then
tell application "Outlook"
set newMessage to make new outgoing message with properties {subject:"Hooray for automation"}
make new recipient at newMessage with properties {email address:{name:"Steve Suranie", address:"steven.suranie#xandr.com"}}
send newMessage
end tell
end if
"""
var out: NSAppleEventDescriptor?
if let scriptObject = NSAppleScript(source: outlookScript) {
var errorDict: NSDictionary? = nil
out = scriptObject.executeAndReturnError(&errorDict)
if let error = errorDict {
print(error)
}
}
}
} else {
print(strSIPMessage)
}
}
}
Before trying to email with the AppleScript I check to ensure the permissions have been set:
func checkSIPforAppIdentifier(_ sipIdentifier:String) -> Dictionary<String, Any> {
var dictSIPResponse = [String:Any]()
var targetAppEventDescriptor = NSAppleEventDescriptor(bundleIdentifier: sipIdentifier)
var status = AEDeterminePermissionToAutomateTarget(targetAppEventDescriptor.aeDesc, typeWildCard, typeWildCard, true);
switch (status) {
case -600: //procNotFound
dictSIPResponse["isSIPEnabled"] = false
dictSIPResponse["sipMessage"] = "Not running app with id \(sipIdentifier)"
break;
case 0: // noErr
dictSIPResponse["isSIPEnabled"] = true
dictSIPResponse["sipMessage"] = "SIP check successfull for app with id \(sipIdentifier)"
break;
case -1744: // errAEEventWouldRequireUserConsent
// This only appears if you send false for askUserIfNeeded
dictSIPResponse["isSIPEnabled"] = false
dictSIPResponse["sipMessage"] = "User consent required for app with id \(sipIdentifier)"
break;
case -1743: //errAEEventNotPermitted
dictSIPResponse["isSIPEnabled"] = false
dictSIPResponse["sipMessage"] = "User didn't allow usage for app with id \(sipIdentifier)"
// Here you should present a dialog with a tutorial on how to activate it manually
// This can be something like
// Go to system preferences > security > privacy
// Choose automation and active [APPNAME] for [APPNAME]
default:
break;
}
return dictSIPResponse
}