Cannot convert value of type 'NSData' to expected argument type 'String' - xcode

I'm writing codes on swift in XCode. This is the code:
import UIKit
import Foundation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let notificationTypes : UIUserNotificationType = [.Alert, .Badge, .Sound]
let notificationSettings : UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
return true
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings)
{
UIApplication.sharedApplication().registerForRemoteNotifications()
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
print("TOKEN:", deviceToken);
let token = String(data: deviceToken, encoding: NSUTF8StringEncoding);
let myUrl = NSURL(fileURLWithPath: "http://......php?id=" + token);
print("URL:",fileURLWithPath: "http://......php?id=" + token);
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print(error.localizedDescription)
}
/* func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
}*/
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
Compiler gives me an error on the func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {" and it says me "Cannot convert value of type 'NSData' to expected argument type 'String'"... but I can't understand the way to solve the problem. So, can somebody help me to correct the error?

var charSet: NSCharacterSet = NSCharacterSet(charactersInString: "<>")
var tokenStr: String = (deviceToken.description as NSString)
.stringByTrimmingCharactersInSet(characterSet)
.stringByReplacingOccurrencesOfString( " ", withString: "") as String
print(deviceTokenString)
Try that

USe this, for sending token to the server. Worked well for me
var token: String = "\(deviceToken)"
let rawtoken = token.stringByReplacingOccurrencesOfString(">", withString: "")
let cleantoken = rawtoken.stringByReplacingOccurrencesOfString("<", withString: "")
var finaltoken = cleantoken.stringByReplacingOccurrencesOfString(" ", withString: "")
Final token is the one that you are supposed to use.
Source was Udemy online courses.

Note that the token is BINARY, so you cannot easily convert it to a string (no UTF8!).
It is a good practice to convert it to hex:
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for var i = 0; i < deviceToken.length; i++ {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
print("Push token: \(tokenString)")

Related

iOS Swift app calls the SquarePOS app on iPad -Square app's screen displays briefly then reverts to my screen's calling view controller-did nothing

This app is intentionally tiny - the UI is just a button to initiate the api call. The appDelegate simply shows a console log proving the callback was executed. I did this because I can not get the Square payment system to work even thought the code and url setup etc looks right to me. I am wondering if I misunderstand something in the documentation.
My app ID is: sq0idp-TbgQGqSrC84qkfcXSTntNg
bundleID is: com.craig.POSSDKTest2
My info.plist setup is a screenshot:info.plist and URLScheme setup
My code in the api calling VC:
// ViewController.swift
// POSSDKTest2
//
// Created by Dr Craig E Curphey on 2022-06-14.
//
import UIKit
import SquarePointOfSaleSDK
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}//------------------------------------
#IBAction func doPaymentTapped(_ sender: Any) {
//------ API to Square right here ******-----------------
let callbackURL = URL(string: "POSSDKTest2Scheme://")!
SCCAPIRequest.setApplicationID("sq0idp-TbgQGqSrC84qkfcXSTntNg")
var money: SCCMoney?
do {
// Specify the amount of money to charge - $1.00
let todaysFeePennies = 100
money = try SCCMoney(amountCents: todaysFeePennies, currencyCode: "CAD")
} catch {
print("money conversion failed.")
}
let LoginID = "TestPatient"
//log values used to console:
print("Initiating payment api request")
print("callback: \(callbackURL)")
print("money: \(money!)")
print("LoginID: TestPatient")
print("Creating payment api request")
do
{
let apiRequest =
try SCCAPIRequest(
callbackURL: callbackURL,
amount: money!,
userInfoString: LoginID,
locationID: "",
notes: "TestingSDK2",
customerID: "tester2",
supportedTenderTypes: .all,
clearsDefaultFees: false,
returnsAutomaticallyAfterPayment: false,
disablesKeyedInCardEntry: false,
skipsReceipt: false
)
print("api initiating!")
try SCCAPIConnection.perform(apiRequest)
} catch let error as NSError {
print("Error detected: \(error.localizedDescription)")
}//end API
print("End of payment api function.")
}//------------------------------------
}
Here is my appDelegate code - I just want to see if I get a callback - I'll add the code to process the response later ...
// AppDelegate.swift
// POSSDKTest2
//
// Created by Dr Craig E Curphey on 2022-06-14.
//
var squareTokenID = "not specified - let it fail - I just want a callback!"
import UIKit
import SquarePointOfSaleSDK
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
//-------------------------------------------
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
print("Callback was executed!")
guard SCCAPIResponse.isSquareResponse(url) else {
print("\(SCCAPIResponse.isSquareResponse(url))")
return true
}
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
}//-------------------------------------------------------
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}//-------------------------------------------------------
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}//--------------------------------------------------------
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}//---------------------------------------------------------
}
Screenshot of console log from trying to do the api:
Console log
The work environment is Xcode 13.3, Swift, macOSMonterey 12.1 beta, iPad 10.2" (I think) mounted in a Square iPad kiosk with attached card reader, running iOS 15.5.
I would be very happy to send the whole project in a zip file to anyone who would be willing to take a look into why it is failing.

XCode 11: Background region monitoring does not work

After hours of reading and re-coding I still can't find a solution.
I want to build a simple app, that tracks my location in the background. On first application load I set up a region around my current location, start monitoring for exactly this region and stopUpdatingLocations. Once the app gets the didExitRegion event, I again get the current location, set up another region (after cleaning all other monitored regions) and it all starts again.
The app has alwaysAuthorization for location, background mode for location updates is set, PList contains LocationAlwaysAndWhenInUseUsageDescription and LocationWhenInUseUsageDescription.
For some time, it works great. But after many hours of not moving, the app gets suspended and does not receive any more location updates, not even the monitor event, which should relaunch the app when I understand this () correctly.
Could anyboy give me a hint?
Thanks.
import UIKit
import CoreLocation
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
let locationManager = CLLocationManager()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let currentNotifications = UNUserNotificationCenter.current()
currentNotifications.getNotificationSettings { (settings) in
if settings.authorizationStatus == .notDetermined {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, error) in }
}
}
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
return true
}
}
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let now = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
for region in locationManager.monitoredRegions {
locationManager.stopMonitoring(for: region)
}
var regionIdentifier = String(format: "%f", location.coordinate.latitude) + ", " + String(format: "%f", location.coordinate.latitude) + "( set on " + formatter.string(from: now) + ")"
var geofenceRegion = CLCircularRegion(center: CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude), radius: 250, identifier: regionIdentifier)
geofenceRegion.notifyOnExit = true
locationManager.startMonitoring(for: geofenceRegion)
locationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
locationManager.stopMonitoring(for: region)
sendNotification(title: "Event triggered", subtitle: "Region exit", body: region.identifier)
locationManager.startUpdatingLocation()
}
}
public func sendNotification(title: String, subtitle: String, body: String) {
let content = UNMutableNotificationContent()
content.title = title
content.subtitle = subtitle
content.body = body
content.sound = .default
let identifier = "geoStalker4_notification_" + String(format: "%f", NSDate().timeIntervalSince1970)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
Try adding this to your locationManager settings:
locationManager.pausesLocationUpdatesAutomatically = false

Custom Google Sign-In Button in SwiftUI

I'm having trouble using SwiftUI to make a custom Google Sign-in button. It will open a window allowing you that looks like it should allow you to login, but when I try to type anything into the text field, it won't type. Has anyone come across this? This is my app delegate (some of the print statements are just there rn for my reference):
// AppDelegate.swift
// WasteLESS
//
// Created by Maya Reese on 5/26/20.
// Copyright © 2020 Maya Reese. All rights reserved.
//
import UIKit
import Firebase
import FBSDKCoreKit
import GoogleSignIn
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
var user = UserData()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
ApplicationDelegate.shared.application(
application,
didFinishLaunchingWithOptions: launchOptions
)
return true
}
func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
ApplicationDelegate.shared.application(
application,
open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation]
)
return GIDSignIn.sharedInstance().handle(url)
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
if let error = error {
print(error.localizedDescription)
return
}
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken)
Auth.auth().signIn(with: credential) { (res, err) in
if err != nil {
print((err?.localizedDescription)!)
return
}
self.user.authorized = true
}
}
}
and this is the function that hitting my "continue with google" button calls:
func GoogleButtonTapped(){
GIDSignIn.sharedInstance().presentingViewController = UIApplication.shared.windows.last?.rootViewController
GIDSignIn.sharedInstance().signIn()
}
I'm a total beginner, so there might be stupid mistakes in there.

Remote Push notifications actions

I created a code that receive remote push norification, this code is worked ok. Now I need to add two "buttons" that swip left and do a action. I know that this below code is used to indetify the action
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
if identifier == "optin1" {
//do something
}
else identifier == "option2" {
//do something
}
completionHandler()
}
But I dont knew how to create the buttons to swip left. How can I do it
This is my AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
// Override point for customization after application launch.
let types:UIUserNotificationType = [.Alert, .Sound, .Badge]
application.registerForRemoteNotifications()
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: types, categories: nil))
initLocationManager()
return true
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
//print(error)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
print(deviceToken)
}
func application(application: UIApplication, didReceiveRemoteNotificationuserInfo userInfo: [NSObject : AnyObject]) {
print(userInfo)
}
Update: new version Swift 4 compatible. This example was adapted from this amazing tutorial https://cocoacasts.com/actionable-notifications-with-the-user-notifications-framework
Configure User Notification Center
import UserNotifications
...
UNUserNotificationCenter.current().delegate = self
Define Actions
let actionReadLater = UNNotificationAction(identifier: Constants.Action.readLater,
title: "Read Later",
options: [])
Define Category
let tutorialCategory = UNNotificationCategory(identifier: Constants.Category.tutorial,
actions: [actionReadLater],
intentIdentifiers: [],
options: [])
Register Category
UNUserNotificationCenter.current().setNotificationCategories([tutorialCategory])
Schedule local notifications by instance from an IBAction
// Request Notification Settings
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
self.requestAuthorization(completionHandler: { (success) in
guard success else { return }
// Schedule Local Notification
self.scheduleLocalNotification()
})
case .authorized:
// Schedule Local Notification
self.scheduleLocalNotification()
case .denied:
print("Application Not Allowed to Display Notifications")
case .provisional:
print("provisional")
}
}
previous version
You can copy&paste this code in didFinishLaunchingWithOptions method:
Create the action
// NOTFICATION
let incrementAction = UIMutableUserNotificationAction()
incrementAction.identifier = "HI_ACTION"
incrementAction.title = "Hi!"
incrementAction.activationMode = UIUserNotificationActivationMode.Background
incrementAction.authenticationRequired = false
incrementAction.destructive = false
Create the category
let counterCategory = UIMutableUserNotificationCategory()
counterCategory.identifier = "HELLO_CATEGORY"
Associate action and category
counterCategory.setActions([incrementAction],
forContext: UIUserNotificationActionContext.Default)
counterCategory.setActions([incrementAction],
forContext: UIUserNotificationActionContext.Minimal)
Registration
let categories = NSSet(object: counterCategory) as! Set<UIUserNotificationCategory>
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Sound], categories: categories)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
The last step is only for demostration
let notification = UILocalNotification()
notification.alertBody = "Hey!"
notification.soundName = UILocalNotificationDefaultSoundName
notification.fireDate = NSDate(timeIntervalSinceNow: 5)
notification.category = "HELLO_CATEGORY"
UIApplication.sharedApplication().scheduleLocalNotification(notification)
When the app is launched you have to push CMD+L
Here's a link to an example

FBSDKAccessToken.currentAccessToken always nil

I have a terms and conditions view controller that is the entry point to my app. It checks:
if( FBSDKAccessToken.currentAccessToken() != nil){
print("here")
dispatch_async(dispatch_get_main_queue()){
[unowned self] in
self.performSegueWithIdentifier("jump", sender: self)
}
}
else{
print("user not logged in")
}
}
Here is my AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
Parse.initializeWithConfiguration(parseConfiguration)
PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)
if( FBSDKAccessToken.currentAccessToken() == nil){
print("fuck")
}
return true
}
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(
application,
openURL: url,
sourceApplication: sourceApplication,
annotation: annotation)
}
func applicationWillResignActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
let loginManager: FBSDKLoginManager = FBSDKLoginManager()
loginManager.logOut()
}
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "mm.MunchMatch" in the application's documents Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1]
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = NSBundle.mainBundle().URLForResource("MunchMatch", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}
}
Does anyone have any idea why my current access token is evaluating to nil even though the user has already logged in?
Why are you loging out the user in applicationWillTerminate ?
calling loginManager.logOut() will set the currentAccesToken to nil.

Resources