How to check which one button click? [duplicate] - ios

I want to do an action after the user tapped on the call button and made a call then returned to the app.
This is my function for making a phone call :
let phoneURL = URL(string: String(format: "tel://%#", phoneNumber.englishNumbers))
UIApplication.shared.open(phoneURL!)
and I have set an observer on CallView in viewDidLoad() like this:
NotificationCenter.default.addObserver(self, selector: #selector (showFeedBack), name: UIApplication.didEnterBackgroundNotification, object: nil)
After I made the call and pressed on the End button (the red button which ends the call). the CallView would appear but the notification won't get called.
Am I using the right notification? or is this the correct approach for detecting when a user made a phone call through your app and came back?
P.S. I have used willResignActiveNotification notification. but it send the notification before even making the call (when the alert is appeared and the user has not select anything yet)

You can use CXCallObserver to listen the call events as below,
import CallKit
class ViewController: UIViewController, CXCallObserverDelegate {
let co = CXCallObserver()
override func viewDidLoad() {
super.viewDidLoad()
co.setDelegate(self, queue: DispatchQueue.main)
}
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
if call.hasEnded {
print("Call is ended")
}
if call.hasEnded == false && call.hasConnected {
print("Call is connected")
}
if call.isOutgoing {
print("This is an outgoing call")
} else if call.hasEnded == false && call.hasConnected == false {
print("This is an incoming call")
}
}
}

Related

swift notification messages manually for app

How to notify the message when manually changes from device notifications from setting
. notifications changes, what method will be invoke inside app, to know that notification was changes
override func awakeFromNib() {
super.awakeFromNib()
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { (settings) in
if(settings.authorizationStatus == .authorized)
{
print(" authorized")
DispatchQueue.main.async {
self.onOffSwitch.isOn = true
}
}
else
{
print(" not authorized")
DispatchQueue.main.async {
self.onOffSwitch.isOn = false
}
}
}
I got tableview inside SettingViewcontroller customize my cell where added the swift onOffSwift.
Based on the setting manually user changes the notifications from setting I wants my app sync accordingly.
SettingViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tbl_SettingView.reloadData()
}
I expected this will work for me? but not
How to handle when user changes there notifications from setting screen should reflect on mobile app screen.
Your app doesn't get an automatic notification when the settings are changed. But the user can make this change only in the Settings app, so you can check the settings when your app comes back to the foreground.
The reason your
override func viewWillAppear(_ animated: Bool) {
doesn't help is that viewWillAppear is not called when the app comes back to the foreground.
There might be better ways but the one I know is this:
Store Settings.authorizationStatus as value in a singleton class or as an entry in UserDefaults
Whenever the app becomes active compare the new value to the stored value. If the they are not the same than you know the settings were changed
I believe you want to get your updated settings when your app enters foreground and not when viewWillAppear called. Just add the observer to your viewDidLoad() (and don't forget to remove it once you're done with the controller):
NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in
UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { settings in
DispatchQueue.main.async {
// update your view with current settings.authorizationStatus
}
})
}

Can Callkit be used with non-voip call to get the call states in ios?

I have read the question about making a-non-voip-call and it seems, that the open url is the only way to do it. Since CoreTelephony is deprecated, is it possible to use Callkit to get the call states when making a call with open url? If not is there any way to get the call states programmatically? I am developing an in-house-app.
How can CallKit be used to make a non-voip call?
Thanks in advance!!
To get call states in CallKit, you can use CXCallObserver in your app.
import CallKit
final class ProviderDelegate: NSObject, CXCallObserverDelegate {
var callObserver: CXCallObserver!
func setupCallObserver(){
callObserver = CXCallObserver()
callObserver.setDelegate(self, queue: nil)
}
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
if call.hasEnded == true {
print("CXCallState :Disconnected")
}
if call.isOutgoing == true && call.hasConnected == false {
print("CXCallState :Dialing")
}
if call.isOutgoing == false && call.hasConnected == false && call.hasEnded == false {
print("CXCallState :Incoming")
}
if call.hasConnected == true && call.hasEnded == false {
print("CXCallState : Connected")
}
}
}

iOS How to detect call state in background?

I'm trying to change button state depending on call state.
I used code from here to detect call state: How to get a call event using CTCallCenter:setCallEventHandler: that occurred while the app was suspended?
And it works fine when app is in foreground. But it doesn't work in background at all. In documentation for CTCallCenter.callEventHandler:
When your application resumes the active state, it receives a single
call event for each call that changed state—no matter how many state
changes the call experienced while your application was suspended. The
single call event sent to your handler, upon your application
returning to the active state, describes the call’s state at that
time.
But I don't get any call events when app resumes active. All I get is last saved call state when app was in foreground. How can I detect call state in background?
Here is my code:
AppDelegate.swift
let callСenter = CTCallCenter()
func block (call:CTCall!)
{
callState = String(call.callState)
print(call.callState)
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
//check for call state
callСenter.callEventHandler = block
...
return true
}
ViewController.swift
override func viewDidLoad()
{
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(cameBackFromSleep),
name: NSNotification.Name.UIApplicationDidBecomeActive,
object: nil
)
...
}
func cameBackFromSleep()
{
self.viewWillAppear(true)
}
override func viewWillAppear(_ animated: Bool)
{
switch callState
{
case "CTCallStateConnected":
print("callState: ", callState)
self.textLabel.isHidden = true
startBtnAnimation()
case "CTCallStateDisconnected":
print("callState: ", callState)
self.textLabel.center.y += self.view.bounds.height
self.textLabel.isHidden = false
stopBtnAnimation()
default: break
}
}
Finally, I solved it! I used code from this answer: Find if user is in a call or not?
I removed everything from AppDelegate, all job is done in ViewController:
override func viewDidLoad()
{
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(cameBackFromSleep),
name: NSNotification.Name.UIApplicationDidBecomeActive,
object: nil
)
...
}
private func isOnPhoneCall() -> Bool
{
let callCntr = CTCallCenter()
if let calls = callCntr.currentCalls
{
for call in calls
{
if call.callState == CTCallStateConnected || call.callState == CTCallStateDialing || call.callState == CTCallStateIncoming
{
print("In call")
return true
}
}
}
print("No calls")
return false
}
func cameBackFromSleep()
{
self.viewWillAppear(true)
}
override func viewWillAppear(_ animated: Bool)
{
print("is on call", isOnPhoneCall())
switch isOnPhoneCall()
{
case true:
print("startBtnAnimation")
startBtnAnimation()
recordBtnIsPressed = true
case false:
print("stopBtnAnimation")
stopBtnAnimation()
recordBtnIsPressed = false
default: break
}
}
Now it works fine. Not sure why CTCallCenter works so weird in AppDelegate.

access reachability with enough time to return true state

i have a reachability class which is checked from within my VC code as below:
func setupReachability (hostName:String?, useClosures: Bool) {
let reachability = hostName == nil ? Reachability() : Reachability(hostname: hostName!)
self.reachability = reachability
try! self.reachability?.startNotifier()
if useClosures {
reachability?.whenReachable = { reachability in
DispatchQueue.main.async {
self.connected = true
print("Reachable....")
}
}
reachability?.whenUnreachable = { reachability in
DispatchQueue.main.async {
self.connected = false
print("Not Connected....")
}
}
} else {
NotificationCenter.default.addObserver(self, selector: Selector(("reachabilityChanged:")), name: ReachabilityChangedNotification, object: reachability)
}
}
this is initialised from within viewDidLoad:
setupReachability(hostName: nil, useClosures: true)
print(self.connected)
the problem i am having is that it always returns false and i need this to load with enough time that it returns true (if it is really connected) at this point. I'm struggling to figure out where to place my setupReachability function and initialise it so that it can be accessed from anywhere in the app and return its connected state. Ive tried placing this in a separate class but can't seem to get it working or access the connected state. Any tips on how to achieve this?

How to call an NSTimer until selector is successful [duplicate]

This question already has answers here:
Stop NSTimer and dismiss view controller (swift)
(5 answers)
Closed 6 years ago.
I have a function called "Check" that checks if an object has been updated, if that's the case, the user is sent to another view controller. However, the NSTimer keeps repeating itself, I want it to stop after the user is sent to the other view controller.
func check(){
let current = PFUser.currentUser()?.objectForKey("username")
let check = PFQuery(className: "Requests")
check.whereKey("username", equalTo: current!)
check.whereKey("requestResponded", equalTo: "True")
check.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error != nil || objects == nil{
print("Request rejected.")
} else {
for object in objects!{
let service = object["service"] as! NSValue
print(service)
if service == 1{
self.performSegueWithIdentifier("detailedRequest", sender: self)
print("detailedRequest")
} else {
self.performSegueWithIdentifier("normalRequest", sender: self)
print("normal")
}
}
print("Successfully retrieved that object.")
}
})
}
self.timer = NSTimer.scheduledTimerWithTimeInterval(10.0, target: self, selector: #selector(self.check), userInfo: nil, repeats: true)
Declare a viewDidDisappear function and inside it invalidate your timer. This function automatically be called each time your viewController has disappeared.
Something like this:
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(true)
self.timer.invalidate()
}

Resources