iOS -- is there any method call automatically(Inside UIViewController) in same screen - ios

Is there any method to call a web service automatically?
Currently i am developing an app like Taxi related app by using Google Maps SDK.
I had 2 applications like DRIVER & RIDER. If Driver login in to the application. When ever In User application user should press the request ride then only i want to display Count down timer in Driver app by using web services
The main thing is --> In DRIVER application there was an screen like "Main Screen"(following image). There is no refresh button. How can i get User request in Same screen automatically refresh the UIViewController screen when ever driver get request from server end.
I know some default methods like: ViewDidLoad, ViewWillAppear, ViewWillDisAppear and etc.., --> these all methods call while specific time only like coming from one screen to another (or) while dismiss
In my case how can i rectify this issue
Already i used code like:
NSTimer* myTimer = [NSTimer scheduledTimerWithTimeInterval: 60.0 target: self
selector: #selector(callAfterSixtySecond:) userInfo: nil repeats: YES];
After each 60.0 second , iOS will call the below function
-(void) callAfterSixtySecond:(NSTimer*) t
{
//Here i call my server API
}
But this is not the feasable solution

You can send Push notification to from your server, this will could be use to trigger events in your application. You can do it without notification.
Check this for example:
http://hayageek.com/ios-silent-push-notifications/'
That's would be an easy way, now if you want to get complex read up on the Inter-process communication

Related

WebRTC running from WKWebView AVAudioSession development roadblock

Over the past few years I have steadily developed a complete WebRTC based browser Phone using the SIP protocol. The main SIP toolbox is SIPJS (https://sipjs.com/), and it provides all the tools one needs to make and receive calls to a SIP based PBX of your own.
The Browser Phone project: https://github.com/InnovateAsterisk/Browser-Phone/ gives SIPJS it's full functionality and UI. You can simply navigate to the phone in a browser and start using it. Everything will works perfectly.
On Mobile
Apple finally allow WebRTC (getUserMedia()) on WKWebView, so it wasn't long before people started to ask how it would work on mobile. And while the UI is well suited for cellphones and tablets, just the UI isn't enough now days to be a full solution.
The main consideration is that a mobile app is typically one that has a short lifespan, in that you can't or don't leave it running in the background like you can or would with the Browser on a PC. This presents a few challenges to truly making the Browser Phone mobile friendly. iOS is going to want to shutdown the app as soon as its not the front most app - and rightly so. So there are tools for handling that, like Callkit & Push Notifications. This allows the app to be woken up, so that it can accept the call, and notify the user.
Just remember, this app is created by opening a UIViewController, adding a WKWebView, and navigating to the phone page. There is full communication between the app and the html & Javascript, so events can be passed back and forth.
WKWebView & AVAudioSession Issue:
After a LOT of reading unsolved forum posts, it's clear that AVAudioSession.sharedInstance() is simply not connected to the WKWebView, or there is some undocumented connection.
The result is that if the call starts from the app, and is sent to the background, the microphone is disabled. Clearly this isn't an option if you are on a call. Now, I can manage this limitation a little, by putting the call on hold when the app is sent to the background - although this would be confusing to the user and a poor user experience.
However, the real issue is that if the app was woken from Callkit, because the app never goes to the foreground (because Callkit is), the microphone isn't activated in the first place, and even if you do witch to the app, it doesn't activate even after that. This is simply an unacceptable user experience.
What I found interesting is that if you simply open up Safari Browser on iOS (15.x), and navigate to the phone page: https://www.innovateasterisk.com/phone/ (without making an app in xCode and loading it into a WKWebView), the microphone continues to work when the app is sent to the background. So how do Safari manage to do this? Of course this doesn't and can't salve the CallKit issue, but still interesting to see that Safari can make use of the microphone in the background, since Safari is built off WKWebView.
(I was reading about entitlements, and that this may have to be specially granted... im not sure how this works?)
The next problem with AVAudioSession is that since you cannot access the session for WkWebView, you cannot change the output of the <audio> element, so you cannot change it from say speaker to earpiece, or make it use a bluetooth device.
It simply wouldn't be feasible to redevelop the entire application using an outdated WebRTC SDK (Google no long maintain the WebRTC iOS SDK), and then build my own Swift SIP stack like SIPJS and land up with two sets of code to maintain... so my main questions are:
How can I access the AVAudioSession of WKWebView so that I can set the output path/device?
How can I have the microphone stay active when the app is sent to the background?
How can I activate the microphone when Callkit activates the application (while the application is in the background)?
for 1) Maybe someone also is following this approach and can add some insight/correct wrong assumptions: The audio in a WebRTC site is represented as a Mediastream. Maybe it is possible to get that stream from without the WKWebView and play it back within the app somehow ? This code should pass on some Buffers, but they are empty when they arrive over in swift:
//javascript
...
someRecorder = new MediaRecorder(audioStream);
someRecorder.ondataavailable = async (e) =>
{
window.webkit.messageHandlers.callBackMethod.postMessage(await e.data.arrayBuffer());
}
mediaRecorder.start(1000);
and then in swift receive it like
//swift
import UIKit
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
...
let config = WKWebViewConfiguration()
config.userContentController = WKUserContentController()
config.userContentController.add(self, name: "callBackMethod")
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 10, height: 10), configuration: config)
...
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
addToPlayingAudioBuffer(message.body)
//print(message.body) gives the output "{}" every 1000ms.
}

How to detect if user navigates away from my app in iOS?

I am trying to develop an app which helps people focus. Essentially, users start a session in which they would like to focus. This session lasts as long as the user does not open another app (for example, the user cannot open Facebook). If the user does so, the session is marked as a failure. Users try to last as long as possible.
The issue I see is that iOS does not allow apps to run for more than 3 minutes once the screen turns off. That means that a user can start a session, then put the phone down for 3 or more minutes, and when they unlock the phone, they are presented with their home screen. The app has been killed. A user is then free to roam around and look at any other app, defeating the purpose of my app.
I could use a timer running on a server to maintain overall session duration, and resume the session once the user reopens the app, but this does not solve the issue of users being able to roam before reopening the app.
Are there any ways to get around iOS killing my app? The behavior I want is:
1) User starts session.
2) Session timer begins.
3) If user navigates away from app, session terminates after 30 second warning.
4) If user locks phone, app still runs.
5) When user unlocks phone, app is displayed (not homescreen). Thus, the termination logic is the same.
Thanks!
You can use an observer (add it to your ViewController's viewDidLoad):
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillResignActive(notification:)), name: UIApplication.willResignActiveNotification, object: nil)
And the function will look like this:
#objc func applicationWillResignActive(notification: NSNotification) {
// do something
}

Swift: Run a specific code when app is killed?

I have a framework that returns a ViewController to my app upon request.
This view controller contains a QR code that is subjected to change after a certain period of time - say 3 days.
I would like to call a method contained inside the framework after 3 days so that the changed/updated QR is readily available even if the user is not using the app actively. When user opens the app - the updated QR is there!
For that, I have used below in my ViewController inside the framework - (from tutorial link)
//MARK:- Add Timer to run QR Logic after 5 seconds
let date = Date().addingTimeInterval(5)
let timer = Timer(fireAt: date, interval: 0, target: self, selector: #selector(QrUIViewController.performQrFetchLogic), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
This piece of code works perfectly when app is active/background. Is it possible, and how to achieve this even if the app is killed?
PS: I read Jobscheduler and AlarmManager will work for Android - is there something similar to these in iOS?
The best way to achieve this is probably using a scheduled Local Notification.
You schedule local notification for some time in the future and then afterwards react to it. This is the case both for when the app is active, in background or inactive.
Remember that notifications do not fire if the user kills your app.

NSUserDefaultsDidChangeNotification and Today Extensions

I am developing an iPhone app with a Today Extension. The app has a Model module that loads from/saves toNSUserDefaults. Since I want this information to be available to both the main app and the extension, I use an app group:
let storage = NSUserDefaults(suiteName: "group.etc.etc.etc...")
Both the app and the extension can access the information without any problem.
The main app occasionally might create a local notification to present to the user. That notification has two actions associated with it (UIUserNotificationAction). One of those actions triggers some code run on the background on the main app. That code changes the NSUserDefaults information and triggers a synchronization. My code is something like this:
func application(application: UIApplication, handleActionWithIdentifier id: String?, forLocalNotification not: UILocalNotification, completionHandler: () -> ()) {
// Interact with model here
// New information gets saved to NSUserDefaults
userDefaultsStorage.synchronize()
completionHandler()
}
Now, on the Today Ext. I naturally observe any changes made to the information on NSUserDefaults so that I can reload the interface on the widget:
override func viewDidLoad() {
super.viewDidLoad()
// ...
NSNotificationCenter.defaultCenter().addObserverForName(NSUserDefaultsDidChangeNotification, object: nil, queue: NSOperationQueue.mainQueue()) { _ in
self.reload()
}
}
Now, here's my issue:
The main app schedules a UILocalNotification. I open the today view and look at my today widget.
When the notification fires, a banner appears on the top of the screen.
I slide down on that banner to reveal the two actions and I select the one that I mentioned earlier (the today widget is still live and on screen).
I know for a fact that the action runs correctly in the background, and that the changes are being made to the information on NSUserDefaults.
However, even though the today widget has been active and on screen all this time, no reload action is triggered. After further investigation, I can confirm that the NSUserDefaultsDidChangeNotification is not being fired (I placed a breakpoint and it did not trigger, and did some other checks as well).
I know the changes are being made by the notification action because if I force a reload of the widget (by closing and opening the today view) the widget updates correctly.
I have seen various tutorials online where the first thing they say is to listen to this notification and update the widget so that "the widget is in sync with NSUserDefaults". But the thing is that AFAICT this notification is absolutely useless! How come??
Note 1: When I change the information on NSUserDefaults from within the today widget the notification fires correctly.
Note 2: Debugging a today widget is absolutely horrible, btw. It is always necessary to tell Xcode to "Attach to process by name..." before it can react to breakpoints and crashes. And iOS is constantly creating a new process for the widget so I have to constantly tell Xcode to attach again.
From doc here:
Cocoa includes two types of notification centers:
The NSNotificationCenter class manages notifications within a single
process. The NSDistributedNotificationCenter class manages
notifications across multiple processes on a single computer.
Apparently the containing app and today extension are different processes, since when you debug today extension you want to attach containing app process, but NSNotificationCenter only work within a single process.
In order to communicate between containing app and extensions, you can use
Darwin Notify Center CFNotificationCenterthat works like NSDistributedNotificationCenter, which is only available for osx.
The idea is use a file inside the group folder that they share. in containing app, you write the data you want to send into the file, then post a CFNotification, which will be received by today extension.
In today extension, use CFNotificationCenterAddObserver to observer the CFNotification, upon receiving it, callback will be called, in which a NSNotification has to be posted due to callback is a C style function and "userInfo" cannot be passed in the CFNotification, after receiving this NSNotification object, it starts to read data from the file, which is used to update the today extension view in Notification center.
You can use this github code to implement force loading the today extension view. It works for me.
Here is a great post on this. http://www.atomicbird.com/blog/sharing-with-app-extensions
Another option is to use setHasContent function. When you schedule a local identifier, set has content to false to hide the view, in handleActionWithIdentifier set it to true to show the view. This way, when you stay in notification center, you will not see the view for a moment, but when you see it, it will be the updated data.
let widgetController = NCWidgetController.widgetController()
widgetController.setHasContent(false, forWidgetWithBundleIdentifier: "YourTodayWidgetBundleIdentifier")
But I think the whole problem is a rare case, which doesn't need to be fixed since you can get the updated data reloading the notification center or switch to notification tab and switch back to today tab.

Is it possible to open running background app on in Objective c

open my app from background running on a specific timing..
want to do somthing like this
- (void)applicationDidEnterBackground:(UIApplication *)application
{
timer = [NSTimer scheduledTimerWithTimeInterval:10
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:NO];
}
- (void)timerFired:(NSTimer*)timer
{
NSLog( #"yes it is running...");
PickUpCallViewController *call=[[PickUpCallViewController alloc]initWithNibName:#"PickUpCallViewController" bundle:nil];
navi=[[UINavigationController alloc]initWithRootViewController:call];
[[navi navigationController] setNavigationBarHidden:YES animated:YES];
window.rootViewController = navi;
[window makeKeyAndVisible];
}
It is not possible to open programmatically app when you application in to background Mode. But using URL-scheme you can open App from browser.
You just need to set URL scheme as following screenshot:-
First you need to open project-->Target-->info
After this click on info you found at Bottom like this screenshot:
Click on URL Type you got result like following screenshot:
click on (+) and setting URL-Schemes as following:
Save and minimized your application by tapping Home button and open your safari browser. and just type mytestApp:// that you are setting before save as following screenshot:-
That all process working fine like:-
i think its possible by using Remote notification(ios7 new background method) without showing uialertview interface.....
As per iOS limitation we can't able to open any app without user interaction. If you need to open any app then you either force the user to do buy sending push notification where user could able to see your notification and can click to view the app.
Also for opening the app from another app or from a link then you can follow the URL schema method like Nitin Gohel explained above.
If you need to fetch a certain data without user interaction then you can use silent push notification which is commonly called as background fetch. You need to enable the push notification in the background mode and use application:didReceiveRemoteNotification:fetchCompletionHandler: method to handle inside the app. Also we need to make few tweaks in the server side while sending the push notification
aps { content-available: 1 alert: {...} }
There is lot more stuff available in net regarding background fetch and you can able to understand how it is working in the this link.

Resources