How to prevent iOS app launching whilest defining protocol handling - ios

I have successfully implemented urlHandling of a self-defined protocol.
I need to prevent the app from launching when other apps try to call this url for security issues. The protocol is only needed for a callback from executed JavaScript-code, so only calls within the app are allowed.
To use the response of UIWebView:stringByEvaluatingJavascriptFromString is not an option because the JS code has to work on multiple platforms.
I thought of intercepting the call itself within my app (which would work by using UIWebViewDelegate:shouldStartLoadWithRequest) but I could not figure out if that is possible with WP8. (In Android this would work with WebViewClient:shouldOverideUrlLoading)

How about implementing the UIApplicationDelegate protocol method:
application:openURL:sourceApplication:annotation:
and checking sourceApplication?

As far as I know, there is no standard API on iOS to have something like a "white-list" for which apps are allowed to call your custom URL scheme and open your app this way. When using this URL schemes, you can only have the whole cake, not just a small piece.
Suggestion A:
You could set a boolean variable in your app delegate to store if openURL was initiated from your app or another, in your view controller check if this variable is set to NO and exchange the rootViewController of your apps' window with a blank screen or an info screen telling the user that the app was not opened from a trusted source or whatever.
Suggestion B:
If you really don't want your app to open, you could make it crash in application:openURL:sourceApplication:annotation:.
Just check if the sourceApplication is a trusted source and if not use something like NSAssert(YES == NO, #"Bad bad boy") to make it crash.
B would only be a hack and I would not consider it best practice. Try suggestion A, it is a much more user-friendly way and you should be able to achieve your goal.

finally I've found a solution that works for me. ;) It's a different approach, though.
First: you might want to check out WebViewJavascriptBridge, thats a Bridge for communication in both directions implementing callbacks and everyhting you might need. But that is working with iframes... I wanted to use ajax.
I'm not implementing a protocol that my app is going to listen to. What I do now is implement a NSURLProtocol, which will allways return NO for canInitWithRequest. I am using a unique path (like /!anythingUnique) to identify my JS-Calls. With that set up I can call ajax and do stuff in the Obj-C code.
implement NSURLProtocol.
register NSURLProtocol via [NSURLProtocol registerClass:[SFJURLProtocol class]];.
you will need to set a baseURL... do that by loading any page or or via webView:loadHTMLSString. Do that when you initialize the controller.
fire Requests from JavaScript
catch them in your canInitWithRequestfunction. You might want to do stuff in the Controller for the sake of clean code, so think of a callback mechanism or something. ;)
???
Profit!
I hope this helps.

Related

Can I make a background data fetch in an external library?

I am currently making a SDK that would require fetching data in the background. For an example, let's say that the SDK provides some weather data that needs to be relatively fresh to be useful. At some point, the data is outdated and needs to be refreshed. The problem is, that the app might be often used in places with poor internet connection, or with no internet access at all. This brings me to the idea that maybe I should fetch the data in background, when the internet is accessible.
The SDK is packaged into a XCFramework, and distributed using Swift Package Manager. When I try adding capabilities to my target, Xcodes gives me a screen that states "No matches, Capabilities are not supported for SDK".
Is it even possible to make a background data fetch without the access to app capabilities? Or does this responsibility fall to the client app for my SDK? Sorry if the answer is obvious, I've tried searching online for a direct response to my problem, and wasn't able to find a clear answer.
An SDK/framework can't request such capabilities, but it can contain the code necessary to do all the work. You need to expose a function that the client can call to run this code.
E.g.
Inside your framework
public func setupBackgroundDataFetching() {
// create background task
}
Then inside your README, you need to tell users that they have to enable this capability and call:
let weatherSDK = WeatherSDK()
weatherSDK.setupBackgroundDataFetching()
Inside their AppDelegate. Depending on your use case you may need to have the function take in some parameters, or make a singleton class and have this as a static/class func, etc. But the basic idea is the same, wrap up the code and ask the client to invoke it
Example:
Heres the repo of a crash reporting tool I use: https://github.com/getsentry/sentry-cocoa
You'll notice their README contains installation/usage guide which asks users to run a setup method in their AppDelegate, which takes in a configuration. Based on this configuration, they can setup anything they need once the app starts, such as a background task if needed

ios - swizzling of firebase cloud messing

I am working with an app using Firebase Cloud Messaging for Push Notification. After reading its documentation, I have a little confuse about "Swizzling disabled", I tried to find some tutorials which are talking about it, but unfortunately there is no any tutorials. Could you please help me to describe what exactly "swizzling" mean? and what is case we need to use it?
Thank you so much.
Ryan
Method swizzling means that you change the implementation of a given function at runtime.
It is often used when you don't have access to the code of the function or if you don't want to modify the code of a library and when inheritance doesn't apply.
Basically what Firebase does: you don't have access to the Push Notifications API/functions except for the delegates that Apple exposes. By swizzling such a function, you can add some logic to what it is currently doing. (You can still call the "previous" function like you would do with super or completely replace its original purpose).
This is how Firebase asks you to activate PUSH Notifications. It makes it easier for you to add it in your code and give Firebase a lot of flexibility as with one line in your AppDelegate they can run whatever they want.
NB: A simple example: you don't have access to the print function, you can just use it. Instead of wrapping the print function in a custom function and replacing its usage everywhere; you could swizzle print with one of your custom function to extend or replace its original functionality. As it is applied at runtime, you wouldn't have to change anything in your project and all print calls would be "redirected" to your new custom function.

Keeping a WKWebView and it's UIViewController in the background running and accessible from multiple ViewControllers

Background: In order to make web requests to an API endpoint, I need to scrape a website and retrieve a token every 25-30 seconds. I'm doing this with a WKWebView and injecting some custom JavaScript using WKUserScript to retrieve AJAX response headers containing the token. Please focus on the question specifically and not on this background information - I'm attempting this entirely for my own educational purposes.
Goal
I will have different 'model' classes, or even just other UIViewControllers, that may need to call the shared UIViewController to retrieve this token to make an authenticated request.
Maybe I might abstract this into one "Sdk" class. Regardless, this 'model' SDK class could be instantiated and used by any other ViewController.
More info
I would like to be able to call the UIViewController of the WKWebView and retrieve some data. Unless I re-create it every 25 seconds, I need to run it in the background or share it. I would like to be able to run a UIViewController 'in the background' and receive some information from it once WKWebView has done it's thing.
I know there are multiple ways of communicating with another ViewController including delegation and segueing. However, I'm not sure that these help me keep the view containing the WKWebView existing in the background so I can call it's ViewController and have it re-perform the scrape. Delegation may work for normal code, but what about one that must have the view existing? Would I have to re-create this WKWebView dynamically each time a different model, or view controller, were to try and get this token?
One post suggests utilising ContainerViewControllers. From this, I gather that in the 'master' ViewController (the one containing the other ones), I could place the hidden WKWebView to do it's thing and communicate to the child view controllers that way via delegation.
Another post suggests using AppDelegate and making it a shared service. I'm completely against using a Singleton as it is widely considered an anti-pattern. There must be another way, even if a little more complex, that helps me do what I want without resorting to this 'cheat'.
This post talks about communicating between multiple ViewControllers, but I can't figure out how this would be useful when something needs to stay running and executing things.
How about any other ways to do this? Run something in a background thread with a strong pointer so it doesn't get discarded? I'm using Xcode 9.2, Swift 4, and iOS 11. As I'm very new to iOS programming, any small code examples on this would be appreciated.
Unfortunately, WKWebView must be in the view hierarchy to use it. You must have added it as a sub view of an on-screen view controller.
This was fine for me. I added this off-screen so it was not visible. Hidden attribute might have worked as well. Either way you must call addSubview with it to make it work.
There are some other questions and answers here which verify this.
Here is a way if you don't wish to use a singleton.
1- In the DidFinishlaunchingWithOptions, Make a timer that runs in the background and call a method inside the app delegate Called FetchNewToken.
2- In FetchNewToken, make the call needed and retrieve the new token (you can use alamofire or any 3rd library to make the call easier for you).
Up on successfully retrieving the token, save it in NSUserDefaults under the name upToDateToken
You can access this token anywhere from the application using NSUserDefaults and it will always be up to date.

Swizzling methods : Programmatically dismiss system dialogs like “<App> would like to access your contacts” in iOS

Is there a way to programmatically dismiss dialogs like the ones where the app wants to access contacts?
I think there's a way by swizzling API methods, but I don't really know which. What is the methodology to find out which methods need to be swizzled? If swizzling is not the way then what could be another alternative?
As a note, this is not for a product, is just for testing so swizzling is a good option if it works.Kindly share sample code if any.
No there's no way to do that. The security notices are presented by the system UI Window Server, not the app itself.
This is done for security, so what you're trying to do totally negates the whole point of them popping up in the first place.

Where is the correct place to make HTTP requests in iOS?

I have an app that fetches data from a server using NSURLSessionDataTask. As of right now I am starting my HTTP GET Request in the init method of the UIViewController that displays the data. Is this the best/smartest place to kick off an HTTP request? If not, where should I do it?
I'm asking this question because when I exit my app and it goes into the background (and is not killed) and then re-open my application, the HTTP request is not fired off (because it is in the UIViewControllers init method) and the data being displayed is not up to date with what's on the server. I've tried putting it in viewDidLoad but this method is not called upon entering the foreground, neither is viewWillAppear nor viewDidAppear.
Should I be doing all of my HTTP requests in one of the UIApplications life cycle methods in my appDelegate?
In short, where is the best place to make HTTP requests in iOS?
Thank you, I can post code or explain more if needed.
first off, this is a huge question and probably impossible to answer fully here, but hopefully I can point you in the right direction so you can learn how to fish. :)
To stick to the Model-View-Controller paradigm, you will want to create a separate object for making your HTTP requests. An HTTP request would be considered part of your model. The benefit of this is being able to use your model in other iOS apps you create, for example.
As for where to put all of this stuff and what's the best design.... One thing that strikes me in your question is you want the data being displayed in your app to be up to date with what is on the server. On a high level, a really good way to do this is to use iOS's ability to multitask and perform functions for you when you app is in the background. You would need to register with the OS as an app that performs fetches to a server in the background.
According to Apple's documentation, "In Xcode 5 and later, you declare the background modes your app supports from the Capabilities tab of your project settings. Enabling the Background Modes option adds the UIBackgroundModes key to your app’s Info.plist file." From there you would need to research the UIApplicationDelegate's protocol methods – application:performFetchWithCompletionHandler: and -application:handleEventsForBackgroundURLSession:completionHandler:.
Also, you will need to look into NSURLSession a little more. If you want to use background fetching, NSURLSessionDataTask is not supported. You will need to use NSURLSessionDownloadTask, save the response to a file and process it however you need to. Also, as the app delegate method name above implies, you will need to read the NSURLSessionConfiguration Class Reference, specifically about backgroundSessionConfiguration.
The really cool thing about all of this is, after you have implemented it, your app UI will be up to date for the user – even if your app was killed by the user or by the OS. Pretty nifty.
Good luck and hope this all helps. I hope I didn't miss any other big pieces here.
I think it a personal preference. So I personally do it on the model objects. Lets say I have a Car object and a ShowroomViewController. I always declare a class method to Car object to call service to get all the cars.
#interaface Car
+(void)fetchCarsWithCompletionHandler:(void (^)(NSArray* cars, NSError *error ))handler;
-(void)getDetailsWithCompletionHandler:(void (^)(Car* car, NSError *error ))handler;
#end
Then call the class method on viewWillAppear(If I need to update the cars very often) or viewDidload(If I need to call the service once).
The other trick I mostly do is define a flag in the view controller like
#interface ShowroomViewController
#property(assign)BOOL needsModelUpdate;
#end
and I update the modal conditionally.
#implementation ShowroomViewController
-(void)viewWillAppear:(BOOL)animated{
if(self.needsModelUpdate){
[self fetchModel]
}
}
-(void)fetchModel{
__block __weak ShowroomViewController *weakRef=self;
[Car fetchCarsWithCompletionHandler:^(NSArray *cars, NSError *error) {
[weakRef setCars:cars];
[weakRef.tableView reloadData];
}];
}
#end
The reason I define this flag is I can change it somewhere else lets say applicationDidEnterBackground: method the change the flag. Or you can use KVO but I always find it overkill .
Do it however you want.
Personally, I create a class specifically for all communication with the server. Actually, my App has around 20 classes for different parts of the communication process. But yours is probably less complicated.
Add an instance of the class as an object in an xib file or else create an instance of it inside the app delegate's init method.
Use didEnterForeground to tell the other class that it needs to do it's stuff, but still use the init method to create an instance of the class.

Resources